]> git.sesse.net Git - pistorm/blob - raylib/external/miniaudio.h
60522da51a89f728ea836290ac8a954ace36ed33
[pistorm] / raylib / external / 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.10.33 - 2021-04-04
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 one .c file:
16
17     ```c
18     #define MINIAUDIO_IMPLEMENTATION
19     #include "miniaudio.h"
20     ```
21
22 You can do `#include "miniaudio.h"` in other parts of the program just like any other header.
23
24 miniaudio uses the concept of a "device" as the abstraction for physical devices. The idea is that you choose a physical device to emit or capture audio from,
25 and then move data to/from the device when miniaudio tells you to. Data is delivered to and from devices asynchronously via a callback which you specify when
26 initializing the device.
27
28 When initializing the device you first need to configure it. The device configuration allows you to specify things like the format of the data delivered via
29 the callback, the size of the internal buffer and the ID of the device you want to emit or capture audio from.
30
31 Once you have the device configuration set up you can initialize the device. When initializing a device you need to allocate memory for the device object
32 beforehand. This gives the application complete control over how the memory is allocated. In the example below we initialize a playback device on the stack,
33 but you could allocate it on the heap if that suits your situation better.
34
35     ```c
36     void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
37     {
38         // In playback mode copy data to pOutput. In capture mode read data from pInput. In full-duplex mode, both
39         // pOutput and pInput will be valid and you can move data from pInput into pOutput. Never process more than
40         // frameCount frames.
41     }
42
43     int main()
44     {
45         ma_device_config config = ma_device_config_init(ma_device_type_playback);
46         config.playback.format   = ma_format_f32;   // Set to ma_format_unknown to use the device's native format.
47         config.playback.channels = 2;               // Set to 0 to use the device's native channel count.
48         config.sampleRate        = 48000;           // Set to 0 to use the device's native sample rate.
49         config.dataCallback      = data_callback;   // This function will be called when miniaudio needs more data.
50         config.pUserData         = pMyCustomData;   // Can be accessed from the device object (device.pUserData).
51
52         ma_device device;
53         if (ma_device_init(NULL, &config, &device) != MA_SUCCESS) {
54             return -1;  // Failed to initialize the device.
55         }
56
57         ma_device_start(&device);     // The device is sleeping by default so you'll need to start it manually.
58
59         // Do something here. Probably your program's main loop.
60
61         ma_device_uninit(&device);    // This will stop the device so no need to do that manually.
62         return 0;
63     }
64     ```
65
66 In the example above, `data_callback()` is where audio data is written and read from the device. The idea is in playback mode you cause sound to be emitted
67 from the speakers by writing audio data to the output buffer (`pOutput` in the example). In capture mode you read data from the input buffer (`pInput`) to
68 extract sound captured by the microphone. The `frameCount` parameter tells you how many frames can be written to the output buffer and read from the input
69 buffer. A "frame" is one sample for each channel. For example, in a stereo stream (2 channels), one frame is 2 samples: one for the left, one for the right.
70 The channel count is defined by the device config. The size in bytes of an individual sample is defined by the sample format which is also specified in the
71 device config. Multi-channel audio data is always interleaved, which means the samples for each frame are stored next to each other in memory. For example, in
72 a stereo stream the first pair of samples will be the left and right samples for the first frame, the second pair of samples will be the left and right samples
73 for the second frame, etc.
74
75 The configuration of the device is defined by the `ma_device_config` structure. The config object is always initialized with `ma_device_config_init()`. It's
76 important to always initialize the config with this function as it initializes it with logical defaults and ensures your program doesn't break when new members
77 are added to the `ma_device_config` structure. The example above uses a fairly simple and standard device configuration. The call to `ma_device_config_init()`
78 takes a single parameter, which is whether or not the device is a playback, capture, duplex or loopback device (loopback devices are not supported on all
79 backends). The `config.playback.format` member sets the sample format which can be one of the following (all formats are native-endian):
80
81     +---------------+----------------------------------------+---------------------------+
82     | Symbol        | Description                            | Range                     |
83     +---------------+----------------------------------------+---------------------------+
84     | ma_format_f32 | 32-bit floating point                  | [-1, 1]                   |
85     | ma_format_s16 | 16-bit signed integer                  | [-32768, 32767]           |
86     | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607]       |
87     | ma_format_s32 | 32-bit signed integer                  | [-2147483648, 2147483647] |
88     | ma_format_u8  | 8-bit unsigned integer                 | [0, 255]                  |
89     +---------------+----------------------------------------+---------------------------+
90
91 The `config.playback.channels` member sets the number of channels to use with the device. The channel count cannot exceed MA_MAX_CHANNELS. The
92 `config.sampleRate` member sets the sample rate (which must be the same for both playback and capture in full-duplex configurations). This is usually set to
93 44100 or 48000, but can be set to anything. It's recommended to keep this between 8000 and 384000, however.
94
95 Note that leaving the format, channel count and/or sample rate at their default values will result in the internal device's native configuration being used
96 which is useful if you want to avoid the overhead of miniaudio's automatic data conversion.
97
98 In addition to the sample format, channel count and sample rate, the data callback and user data pointer are also set via the config. The user data pointer is
99 not passed into the callback as a parameter, but is instead set to the `pUserData` member of `ma_device` which you can access directly since all miniaudio
100 structures are transparent.
101
102 Initializing the device is done with `ma_device_init()`. This will return a result code telling you what went wrong, if anything. On success it will return
103 `MA_SUCCESS`. After initialization is complete the device will be in a stopped state. To start it, use `ma_device_start()`. Uninitializing the device will stop
104 it, which is what the example above does, but you can also stop the device with `ma_device_stop()`. To resume the device simply call `ma_device_start()` again.
105 Note that it's important to never stop or start the device from inside the callback. This will result in a deadlock. Instead you set a variable or signal an
106 event indicating that the device needs to stop and handle it in a different thread. The following APIs must never be called inside the callback:
107
108     ```c
109     ma_device_init()
110     ma_device_init_ex()
111     ma_device_uninit()
112     ma_device_start()
113     ma_device_stop()
114     ```
115
116 You must never try uninitializing and reinitializing a device inside the callback. You must also never try to stop and start it from inside the callback. There
117 are a few other things you shouldn't do in the callback depending on your requirements, however this isn't so much a thread-safety thing, but rather a
118 real-time processing thing which is beyond the scope of this introduction.
119
120 The example above demonstrates the initialization of a playback device, but it works exactly the same for capture. All you need to do is change the device type
121 from `ma_device_type_playback` to `ma_device_type_capture` when setting up the config, like so:
122
123     ```c
124     ma_device_config config = ma_device_config_init(ma_device_type_capture);
125     config.capture.format   = MY_FORMAT;
126     config.capture.channels = MY_CHANNEL_COUNT;
127     ```
128
129 In the data callback you just read from the input buffer (`pInput` in the example above) and leave the output buffer alone (it will be set to NULL when the
130 device type is set to `ma_device_type_capture`).
131
132 These are the available device types and how you should handle the buffers in the callback:
133
134     +-------------------------+--------------------------------------------------------+
135     | Device Type             | Callback Behavior                                      |
136     +-------------------------+--------------------------------------------------------+
137     | ma_device_type_playback | Write to output buffer, leave input buffer untouched.  |
138     | ma_device_type_capture  | Read from input buffer, leave output buffer untouched. |
139     | ma_device_type_duplex   | Read from input buffer, write to output buffer.        |
140     | ma_device_type_loopback | Read from input buffer, leave output buffer untouched. |
141     +-------------------------+--------------------------------------------------------+
142
143 You will notice in the example above that the sample format and channel count is specified separately for playback and capture. This is to support different
144 data formats between the playback and capture devices in a full-duplex system. An example may be that you want to capture audio data as a monaural stream (one
145 channel), but output sound to a stereo speaker system. Note that if you use different formats between playback and capture in a full-duplex configuration you
146 will need to convert the data yourself. There are functions available to help you do this which will be explained later.
147
148 The example above did not specify a physical device to connect to which means it will use the operating system's default device. If you have multiple physical
149 devices connected and you want to use a specific one you will need to specify the device ID in the configuration, like so:
150
151     ```c
152     config.playback.pDeviceID = pMyPlaybackDeviceID;    // Only if requesting a playback or duplex device.
153     config.capture.pDeviceID = pMyCaptureDeviceID;      // Only if requesting a capture, duplex or loopback device.
154     ```
155
156 To retrieve the device ID you will need to perform device enumeration, however this requires the use of a new concept called the "context". Conceptually
157 speaking the context sits above the device. There is one context to many devices. The purpose of the context is to represent the backend at a more global level
158 and to perform operations outside the scope of an individual device. Mainly it is used for performing run-time linking against backend libraries, initializing
159 backends and enumerating devices. The example below shows how to enumerate devices.
160
161     ```c
162     ma_context context;
163     if (ma_context_init(NULL, 0, NULL, &context) != MA_SUCCESS) {
164         // Error.
165     }
166
167     ma_device_info* pPlaybackInfos;
168     ma_uint32 playbackCount;
169     ma_device_info* pCaptureInfos;
170     ma_uint32 captureCount;
171     if (ma_context_get_devices(&context, &pPlaybackInfos, &playbackCount, &pCaptureInfos, &captureCount) != MA_SUCCESS) {
172         // Error.
173     }
174
175     // Loop over each device info and do something with it. Here we just print the name with their index. You may want
176     // to give the user the opportunity to choose which device they'd prefer.
177     for (ma_uint32 iDevice = 0; iDevice < playbackCount; iDevice += 1) {
178         printf("%d - %s\n", iDevice, pPlaybackInfos[iDevice].name);
179     }
180
181     ma_device_config config = ma_device_config_init(ma_device_type_playback);
182     config.playback.pDeviceID = &pPlaybackInfos[chosenPlaybackDeviceIndex].id;
183     config.playback.format    = MY_FORMAT;
184     config.playback.channels  = MY_CHANNEL_COUNT;
185     config.sampleRate         = MY_SAMPLE_RATE;
186     config.dataCallback       = data_callback;
187     config.pUserData          = pMyCustomData;
188
189     ma_device device;
190     if (ma_device_init(&context, &config, &device) != MA_SUCCESS) {
191         // Error
192     }
193
194     ...
195
196     ma_device_uninit(&device);
197     ma_context_uninit(&context);
198     ```
199
200 The first thing we do in this example is initialize a `ma_context` object with `ma_context_init()`. The first parameter is a pointer to a list of `ma_backend`
201 values which are used to override the default backend priorities. When this is NULL, as in this example, miniaudio's default priorities are used. The second
202 parameter is the number of backends listed in the array pointed to by the first parameter. The third parameter is a pointer to a `ma_context_config` object
203 which can be NULL, in which case defaults are used. The context configuration is used for setting the logging callback, custom memory allocation callbacks,
204 user-defined data and some backend-specific configurations.
205
206 Once the context has been initialized you can enumerate devices. In the example above we use the simpler `ma_context_get_devices()`, however you can also use a
207 callback for handling devices by using `ma_context_enumerate_devices()`. When using `ma_context_get_devices()` you provide a pointer to a pointer that will,
208 upon output, be set to a pointer to a buffer containing a list of `ma_device_info` structures. You also provide a pointer to an unsigned integer that will
209 receive the number of items in the returned buffer. Do not free the returned buffers as their memory is managed internally by miniaudio.
210
211 The `ma_device_info` structure contains an `id` member which is the ID you pass to the device config. It also contains the name of the device which is useful
212 for presenting a list of devices to the user via the UI.
213
214 When creating your own context you will want to pass it to `ma_device_init()` when initializing the device. Passing in NULL, like we do in the first example,
215 will result in miniaudio creating the context for you, which you don't want to do since you've already created a context. Note that internally the context is
216 only tracked by it's pointer which means you must not change the location of the `ma_context` object. If this is an issue, consider using `malloc()` to
217 allocate memory for the context.
218
219
220
221 2. Building
222 ===========
223 miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details.
224
225
226 2.1. Windows
227 ------------
228 The Windows build should compile cleanly on all popular compilers without the need to configure any include paths nor link to any libraries.
229
230 2.2. macOS and iOS
231 ------------------
232 The macOS build should compile cleanly without the need to download any dependencies nor link to any libraries or frameworks. The iOS build needs to be
233 compiled as Objective-C and will need to link the relevant frameworks but should compile cleanly out of the box with Xcode. Compiling through the command line
234 requires linking to `-lpthread` and `-lm`.
235
236 Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's notarization process. To fix this there are two options. The
237 first is to use the `MA_NO_RUNTIME_LINKING` option, like so:
238
239     ```c
240     #ifdef __APPLE__
241         #define MA_NO_RUNTIME_LINKING
242     #endif
243     #define MINIAUDIO_IMPLEMENTATION
244     #include "miniaudio.h"
245     ```
246
247 This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioUnit`. Alternatively, if you would rather keep using runtime
248 linking you can add the following to your entitlements.xcent file:
249
250     ```
251     <key>com.apple.security.cs.allow-dyld-environment-variables</key>
252     <true/>
253     <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
254     <true/>
255     ```
256
257
258 2.3. Linux
259 ----------
260 The Linux build only requires linking to `-ldl`, `-lpthread` and `-lm`. You do not need any development packages.
261
262 2.4. BSD
263 --------
264 The BSD build only requires linking to `-lpthread` and `-lm`. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS.
265
266 2.5. Android
267 ------------
268 AAudio is the highest priority backend on Android. This should work out of the box without needing any kind of compiler configuration. Support for AAudio
269 starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+.
270
271 There have been reports that the OpenSL|ES backend fails to initialize on some Android based devices due to `dlopen()` failing to open "libOpenSLES.so". If
272 this happens on your platform you'll need to disable run-time linking with `MA_NO_RUNTIME_LINKING` and link with -lOpenSLES.
273
274 2.6. Emscripten
275 ---------------
276 The Emscripten build emits Web Audio JavaScript directly and should compile cleanly out of the box. You cannot use -std=c* compiler flags, nor -ansi.
277
278
279 2.7. Build Options
280 ------------------
281 `#define` these options before including miniaudio.h.
282
283     +----------------------------------+--------------------------------------------------------------------+
284     | Option                           | Description                                                        |
285     +----------------------------------+--------------------------------------------------------------------+
286     | MA_NO_WASAPI                     | Disables the WASAPI backend.                                       |
287     +----------------------------------+--------------------------------------------------------------------+
288     | MA_NO_DSOUND                     | Disables the DirectSound backend.                                  |
289     +----------------------------------+--------------------------------------------------------------------+
290     | MA_NO_WINMM                      | Disables the WinMM backend.                                        |
291     +----------------------------------+--------------------------------------------------------------------+
292     | MA_NO_ALSA                       | Disables the ALSA backend.                                         |
293     +----------------------------------+--------------------------------------------------------------------+
294     | MA_NO_PULSEAUDIO                 | Disables the PulseAudio backend.                                   |
295     +----------------------------------+--------------------------------------------------------------------+
296     | MA_NO_JACK                       | Disables the JACK backend.                                         |
297     +----------------------------------+--------------------------------------------------------------------+
298     | MA_NO_COREAUDIO                  | Disables the Core Audio backend.                                   |
299     +----------------------------------+--------------------------------------------------------------------+
300     | MA_NO_SNDIO                      | Disables the sndio backend.                                        |
301     +----------------------------------+--------------------------------------------------------------------+
302     | MA_NO_AUDIO4                     | Disables the audio(4) backend.                                     |
303     +----------------------------------+--------------------------------------------------------------------+
304     | MA_NO_OSS                        | Disables the OSS backend.                                          |
305     +----------------------------------+--------------------------------------------------------------------+
306     | MA_NO_AAUDIO                     | Disables the AAudio backend.                                       |
307     +----------------------------------+--------------------------------------------------------------------+
308     | MA_NO_OPENSL                     | Disables the OpenSL|ES backend.                                    |
309     +----------------------------------+--------------------------------------------------------------------+
310     | MA_NO_WEBAUDIO                   | Disables the Web Audio backend.                                    |
311     +----------------------------------+--------------------------------------------------------------------+
312     | MA_NO_NULL                       | Disables the null backend.                                         |
313     +----------------------------------+--------------------------------------------------------------------+
314     | MA_ENABLE_ONLY_SPECIFIC_BACKENDS | Disables all backends by default and requires `MA_ENABLE_*` to     |
315     |                                  | enable specific backends.                                          |
316     +----------------------------------+--------------------------------------------------------------------+
317     | MA_ENABLE_WASAPI                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
318     |                                  | enable the WASAPI backend.                                         |
319     +----------------------------------+--------------------------------------------------------------------+
320     | MA_ENABLE_DSOUND                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
321     |                                  | enable the DirectSound backend.                                    |
322     +----------------------------------+--------------------------------------------------------------------+
323     | MA_ENABLE_WINMM                  | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
324     |                                  | enable the WinMM backend.                                          |
325     +----------------------------------+--------------------------------------------------------------------+
326     | MA_ENABLE_ALSA                   | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
327     |                                  | enable the ALSA backend.                                           |
328     +----------------------------------+--------------------------------------------------------------------+
329     | MA_ENABLE_PULSEAUDIO             | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
330     |                                  | enable the PulseAudio backend.                                     |
331     +----------------------------------+--------------------------------------------------------------------+
332     | MA_ENABLE_JACK                   | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
333     |                                  | enable the JACK backend.                                           |
334     +----------------------------------+--------------------------------------------------------------------+
335     | MA_ENABLE_COREAUDIO              | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
336     |                                  | enable the Core Audio backend.                                     |
337     +----------------------------------+--------------------------------------------------------------------+
338     | MA_ENABLE_SNDIO                  | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
339     |                                  | enable the sndio backend.                                          |
340     +----------------------------------+--------------------------------------------------------------------+
341     | MA_ENABLE_AUDIO4                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
342     |                                  | enable the audio(4) backend.                                       |
343     +----------------------------------+--------------------------------------------------------------------+
344     | MA_ENABLE_OSS                    | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
345     |                                  | enable the OSS backend.                                            |
346     +----------------------------------+--------------------------------------------------------------------+
347     | MA_ENABLE_AAUDIO                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
348     |                                  | enable the AAudio backend.                                         |
349     +----------------------------------+--------------------------------------------------------------------+
350     | MA_ENABLE_OPENSL                 | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
351     |                                  | enable the OpenSL|ES backend.                                      |
352     +----------------------------------+--------------------------------------------------------------------+
353     | MA_ENABLE_WEBAUDIO               | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
354     |                                  | enable the Web Audio backend.                                      |
355     +----------------------------------+--------------------------------------------------------------------+
356     | MA_ENABLE_NULL                   | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to       |
357     |                                  | enable the null backend.                                           |
358     +----------------------------------+--------------------------------------------------------------------+
359     | MA_NO_DECODING                   | Disables decoding APIs.                                            |
360     +----------------------------------+--------------------------------------------------------------------+
361     | MA_NO_ENCODING                   | Disables encoding APIs.                                            |
362     +----------------------------------+--------------------------------------------------------------------+
363     | MA_NO_WAV                        | Disables the built-in WAV decoder and encoder.                     |
364     +----------------------------------+--------------------------------------------------------------------+
365     | MA_NO_FLAC                       | Disables the built-in FLAC decoder.                                |
366     +----------------------------------+--------------------------------------------------------------------+
367     | MA_NO_MP3                        | Disables the built-in MP3 decoder.                                 |
368     +----------------------------------+--------------------------------------------------------------------+
369     | MA_NO_DEVICE_IO                  | Disables playback and recording. This will disable ma_context and  |
370     |                                  | ma_device APIs. This is useful if you only want to use miniaudio's |
371     |                                  | data conversion and/or decoding APIs.                              |
372     +----------------------------------+--------------------------------------------------------------------+
373     | MA_NO_THREADING                  | Disables the ma_thread, ma_mutex, ma_semaphore and ma_event APIs.  |
374     |                                  | This option is useful if you only need to use miniaudio for data   |
375     |                                  | conversion, decoding and/or encoding. Some families of APIs        |
376     |                                  | require threading which means the following options must also be   |
377     |                                  | set:                                                               |
378     |                                  |                                                                    |
379     |                                  |     ```                                                            |
380     |                                  |     MA_NO_DEVICE_IO                                                |
381     |                                  |     ```                                                            |
382     +----------------------------------+--------------------------------------------------------------------+
383     | MA_NO_GENERATION                 | Disables generation APIs such a ma_waveform and ma_noise.          |
384     +----------------------------------+--------------------------------------------------------------------+
385     | MA_NO_SSE2                       | Disables SSE2 optimizations.                                       |
386     +----------------------------------+--------------------------------------------------------------------+
387     | MA_NO_AVX2                       | Disables AVX2 optimizations.                                       |
388     +----------------------------------+--------------------------------------------------------------------+
389     | MA_NO_AVX512                     | Disables AVX-512 optimizations.                                    |
390     +----------------------------------+--------------------------------------------------------------------+
391     | MA_NO_NEON                       | Disables NEON optimizations.                                       |
392     +----------------------------------+--------------------------------------------------------------------+
393     | MA_NO_RUNTIME_LINKING            | Disables runtime linking. This is useful for passing Apple's       |
394     |                                  | notarization process. When enabling this, you may need to avoid    |
395     |                                  | using `-std=c89` or `-std=c99` on Linux builds or else you may end |
396     |                                  | up with compilation errors due to conflicts with `timespec` and    |
397     |                                  | `timeval` data types.                                              |
398     |                                  |                                                                    |
399     |                                  | You may need to enable this if your target platform does not allow |
400     |                                  | runtime linking via `dlopen()`.                                    |
401     +----------------------------------+--------------------------------------------------------------------+
402     | MA_LOG_LEVEL [level]             | Sets the logging level. Set `level` to one of the following:       |
403     |                                  |                                                                    |
404     |                                  |     ```                                                            |
405     |                                  |     MA_LOG_LEVEL_VERBOSE                                           |
406     |                                  |     MA_LOG_LEVEL_INFO                                              |
407     |                                  |     MA_LOG_LEVEL_WARNING                                           |
408     |                                  |     MA_LOG_LEVEL_ERROR                                             |
409     |                                  |     ```                                                            |
410     +----------------------------------+--------------------------------------------------------------------+
411     | MA_DEBUG_OUTPUT                  | Enable `printf()` debug output.                                    |
412     +----------------------------------+--------------------------------------------------------------------+
413     | MA_COINIT_VALUE                  | Windows only. The value to pass to internal calls to               |
414     |                                  | `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`.            |
415     +----------------------------------+--------------------------------------------------------------------+
416     | MA_API                           | Controls how public APIs should be decorated. Default is `extern`. |
417     +----------------------------------+--------------------------------------------------------------------+
418     | MA_DLL                           | If set, configures MA_API to either import or export APIs          |
419     |                                  | depending on whether or not the implementation is being defined.   |
420     |                                  | If defining the implementation, MA_API will be configured to       |
421     |                                  | export. Otherwise it will be configured to import. This has no     |
422     |                                  | effect if MA_API is defined externally.                            |
423     +----------------------------------+--------------------------------------------------------------------+
424
425
426 3. Definitions
427 ==============
428 This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this
429 section is intended to clarify how miniaudio uses each term.
430
431 3.1. Sample
432 -----------
433 A sample is a single unit of audio data. If the sample format is f32, then one sample is one 32-bit floating point number.
434
435 3.2. Frame / PCM Frame
436 ----------------------
437 A frame is a group of samples equal to the number of channels. For a stereo stream a frame is 2 samples, a mono frame is 1 sample, a 5.1 surround sound frame
438 is 6 samples, etc. The terms "frame" and "PCM frame" are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio
439 needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it's referring to with something like "FLAC frame".
440
441 3.3. Channel
442 ------------
443 A stream of monaural audio that is emitted from an individual speaker in a speaker system, or received from an individual microphone in a microphone system. A
444 stereo stream has two channels (a left channel, and a right channel), a 5.1 surround sound system has 6 channels, etc. Some audio systems refer to a channel as
445 a complex audio stream that's mixed with other channels to produce the final mix - this is completely different to miniaudio's use of the term "channel" and
446 should not be confused.
447
448 3.4. Sample Rate
449 ----------------
450 The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It's the number of PCM frames that are processed per second.
451
452 3.5. Formats
453 ------------
454 Throughout miniaudio you will see references to different sample formats:
455
456     +---------------+----------------------------------------+---------------------------+
457     | Symbol        | Description                            | Range                     |
458     +---------------+----------------------------------------+---------------------------+
459     | ma_format_f32 | 32-bit floating point                  | [-1, 1]                   |
460     | ma_format_s16 | 16-bit signed integer                  | [-32768, 32767]           |
461     | ma_format_s24 | 24-bit signed integer (tightly packed) | [-8388608, 8388607]       |
462     | ma_format_s32 | 32-bit signed integer                  | [-2147483648, 2147483647] |
463     | ma_format_u8  | 8-bit unsigned integer                 | [0, 255]                  |
464     +---------------+----------------------------------------+---------------------------+
465
466 All formats are native-endian.
467
468
469
470 4. Decoding
471 ===========
472 The `ma_decoder` API is used for reading audio files. Decoders are completely decoupled from devices and can be used independently. The following formats are
473 supported:
474
475     +---------+------------------+----------+
476     | Format  | Decoding Backend | Built-In |
477     +---------+------------------+----------+
478     | WAV     | dr_wav           | Yes      |
479     | MP3     | dr_mp3           | Yes      |
480     | FLAC    | dr_flac          | Yes      |
481     | Vorbis  | stb_vorbis       | No       |
482     +---------+------------------+----------+
483
484 Vorbis is supported via stb_vorbis which can be enabled by including the header section before the implementation of miniaudio, like the following:
485
486     ```c
487     #define STB_VORBIS_HEADER_ONLY
488     #include "extras/stb_vorbis.c"    // Enables Vorbis decoding.
489
490     #define MINIAUDIO_IMPLEMENTATION
491     #include "miniaudio.h"
492
493     // The stb_vorbis implementation must come after the implementation of miniaudio.
494     #undef STB_VORBIS_HEADER_ONLY
495     #include "extras/stb_vorbis.c"
496     ```
497
498 A copy of stb_vorbis is included in the "extras" folder in the miniaudio repository (https://github.com/mackron/miniaudio).
499
500 Built-in decoders are amalgamated into the implementation section of miniaudio. You can disable the built-in decoders by specifying one or more of the
501 following options before the miniaudio implementation:
502
503     ```c
504     #define MA_NO_WAV
505     #define MA_NO_MP3
506     #define MA_NO_FLAC
507     ```
508
509 Disabling built-in decoding libraries is useful if you use these libraries independantly of the `ma_decoder` API.
510
511 A decoder can be initialized from a file with `ma_decoder_init_file()`, a block of memory with `ma_decoder_init_memory()`, or from data delivered via callbacks
512 with `ma_decoder_init()`. Here is an example for loading a decoder from a file:
513
514     ```c
515     ma_decoder decoder;
516     ma_result result = ma_decoder_init_file("MySong.mp3", NULL, &decoder);
517     if (result != MA_SUCCESS) {
518         return false;   // An error occurred.
519     }
520
521     ...
522
523     ma_decoder_uninit(&decoder);
524     ```
525
526 When initializing a decoder, you can optionally pass in a pointer to a `ma_decoder_config` object (the `NULL` argument in the example above) which allows you
527 to configure the output format, channel count, sample rate and channel map:
528
529     ```c
530     ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, 48000);
531     ```
532
533 When passing in `NULL` for decoder config in `ma_decoder_init*()`, the output format will be the same as that defined by the decoding backend.
534
535 Data is read from the decoder as PCM frames. This will return the number of PCM frames actually read. If the return value is less than the requested number of
536 PCM frames it means you've reached the end:
537
538     ```c
539     ma_uint64 framesRead = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead);
540     if (framesRead < framesToRead) {
541         // Reached the end.
542     }
543     ```
544
545 You can also seek to a specific frame like so:
546
547     ```c
548     ma_result result = ma_decoder_seek_to_pcm_frame(pDecoder, targetFrame);
549     if (result != MA_SUCCESS) {
550         return false;   // An error occurred.
551     }
552     ```
553
554 If you want to loop back to the start, you can simply seek back to the first PCM frame:
555
556     ```c
557     ma_decoder_seek_to_pcm_frame(pDecoder, 0);
558     ```
559
560 When loading a decoder, miniaudio uses a trial and error technique to find the appropriate decoding backend. This can be unnecessarily inefficient if the type
561 is already known. In this case you can use the `_wav`, `_mp3`, etc. varients of the aforementioned initialization APIs:
562
563     ```c
564     ma_decoder_init_wav()
565     ma_decoder_init_mp3()
566     ma_decoder_init_memory_wav()
567     ma_decoder_init_memory_mp3()
568     ma_decoder_init_file_wav()
569     ma_decoder_init_file_mp3()
570     etc.
571     ```
572
573 The `ma_decoder_init_file()` API will try using the file extension to determine which decoding backend to prefer.
574
575
576
577 5. Encoding
578 ===========
579 The `ma_encoding` API is used for writing audio files. The only supported output format is WAV which is achieved via dr_wav which is amalgamated into the
580 implementation section of miniaudio. This can be disabled by specifying the following option before the implementation of miniaudio:
581
582     ```c
583     #define MA_NO_WAV
584     ```
585
586 An encoder can be initialized to write to a file with `ma_encoder_init_file()` or from data delivered via callbacks with `ma_encoder_init()`. Below is an
587 example for initializing an encoder to output to a file.
588
589     ```c
590     ma_encoder_config config = ma_encoder_config_init(ma_resource_format_wav, FORMAT, CHANNELS, SAMPLE_RATE);
591     ma_encoder encoder;
592     ma_result result = ma_encoder_init_file("my_file.wav", &config, &encoder);
593     if (result != MA_SUCCESS) {
594         // Error
595     }
596
597     ...
598
599     ma_encoder_uninit(&encoder);
600     ```
601
602 When initializing an encoder you must specify a config which is initialized with `ma_encoder_config_init()`. Here you must specify the file type, the output
603 sample format, output channel count and output sample rate. The following file types are supported:
604
605     +------------------------+-------------+
606     | Enum                   | Description |
607     +------------------------+-------------+
608     | ma_resource_format_wav | WAV         |
609     +------------------------+-------------+
610
611 If the format, channel count or sample rate is not supported by the output file type an error will be returned. The encoder will not perform data conversion so
612 you will need to convert it before outputting any audio data. To output audio data, use `ma_encoder_write_pcm_frames()`, like in the example below:
613
614     ```c
615     framesWritten = ma_encoder_write_pcm_frames(&encoder, pPCMFramesToWrite, framesToWrite);
616     ```
617
618 Encoders must be uninitialized with `ma_encoder_uninit()`.
619
620
621 6. Data Conversion
622 ==================
623 A data conversion API is included with miniaudio which supports the majority of data conversion requirements. This supports conversion between sample formats,
624 channel counts (with channel mapping) and sample rates.
625
626
627 6.1. Sample Format Conversion
628 -----------------------------
629 Conversion between sample formats is achieved with the `ma_pcm_*_to_*()`, `ma_pcm_convert()` and `ma_convert_pcm_frames_format()` APIs. Use `ma_pcm_*_to_*()`
630 to convert between two specific formats. Use `ma_pcm_convert()` to convert based on a `ma_format` variable. Use `ma_convert_pcm_frames_format()` to convert
631 PCM frames where you want to specify the frame count and channel count as a variable instead of the total sample count.
632
633
634 6.1.1. Dithering
635 ----------------
636 Dithering can be set using the ditherMode parameter.
637
638 The different dithering modes include the following, in order of efficiency:
639
640     +-----------+--------------------------+
641     | Type      | Enum Token               |
642     +-----------+--------------------------+
643     | None      | ma_dither_mode_none      |
644     | Rectangle | ma_dither_mode_rectangle |
645     | Triangle  | ma_dither_mode_triangle  |
646     +-----------+--------------------------+
647
648 Note that even if the dither mode is set to something other than `ma_dither_mode_none`, it will be ignored for conversions where dithering is not needed.
649 Dithering is available for the following conversions:
650
651     ```
652     s16 -> u8
653     s24 -> u8
654     s32 -> u8
655     f32 -> u8
656     s24 -> s16
657     s32 -> s16
658     f32 -> s16
659     ```
660
661 Note that it is not an error to pass something other than ma_dither_mode_none for conversions where dither is not used. It will just be ignored.
662
663
664
665 6.2. Channel Conversion
666 -----------------------
667 Channel conversion is used for channel rearrangement and conversion from one channel count to another. The `ma_channel_converter` API is used for channel
668 conversion. Below is an example of initializing a simple channel converter which converts from mono to stereo.
669
670     ```c
671     ma_channel_converter_config config = ma_channel_converter_config_init(
672         ma_format,                      // Sample format
673         1,                              // Input channels
674         NULL,                           // Input channel map
675         2,                              // Output channels
676         NULL,                           // Output channel map
677         ma_channel_mix_mode_default);   // The mixing algorithm to use when combining channels.
678
679     result = ma_channel_converter_init(&config, &converter);
680     if (result != MA_SUCCESS) {
681         // Error.
682     }
683     ```
684
685 To perform the conversion simply call `ma_channel_converter_process_pcm_frames()` like so:
686
687     ```c
688     ma_result result = ma_channel_converter_process_pcm_frames(&converter, pFramesOut, pFramesIn, frameCount);
689     if (result != MA_SUCCESS) {
690         // Error.
691     }
692     ```
693
694 It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM frames.
695
696 Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported.
697
698
699 6.2.1. Channel Mapping
700 ----------------------
701 In addition to converting from one channel count to another, like the example above, the channel converter can also be used to rearrange channels. When
702 initializing the channel converter, you can optionally pass in channel maps for both the input and output frames. If the channel counts are the same, and each
703 channel map contains the same channel positions with the exception that they're in a different order, a simple shuffling of the channels will be performed. If,
704 however, there is not a 1:1 mapping of channel positions, or the channel counts differ, the input channels will be mixed based on a mixing mode which is
705 specified when initializing the `ma_channel_converter_config` object.
706
707 When converting from mono to multi-channel, the mono channel is simply copied to each output channel. When going the other way around, the audio of each output
708 channel is simply averaged and copied to the mono channel.
709
710 In more complicated cases blending is used. The `ma_channel_mix_mode_simple` mode will drop excess channels and silence extra channels. For example, converting
711 from 4 to 2 channels, the 3rd and 4th channels will be dropped, whereas converting from 2 to 4 channels will put silence into the 3rd and 4th channels.
712
713 The `ma_channel_mix_mode_rectangle` mode uses spacial locality based on a rectangle to compute a simple distribution between input and output. Imagine sitting
714 in the middle of a room, with speakers on the walls representing channel positions. The MA_CHANNEL_FRONT_LEFT position can be thought of as being in the corner
715 of the front and left walls.
716
717 Finally, the `ma_channel_mix_mode_custom_weights` mode can be used to use custom user-defined weights. Custom weights can be passed in as the last parameter of
718 `ma_channel_converter_config_init()`.
719
720 Predefined channel maps can be retrieved with `ma_get_standard_channel_map()`. This takes a `ma_standard_channel_map` enum as it's first parameter, which can
721 be one of the following:
722
723     +-----------------------------------+-----------------------------------------------------------+
724     | Name                              | Description                                               |
725     +-----------------------------------+-----------------------------------------------------------+
726     | ma_standard_channel_map_default   | Default channel map used by miniaudio. See below.         |
727     | ma_standard_channel_map_microsoft | Channel map used by Microsoft's bitfield channel maps.    |
728     | ma_standard_channel_map_alsa      | Default ALSA channel map.                                 |
729     | ma_standard_channel_map_rfc3551   | RFC 3551. Based on AIFF.                                  |
730     | ma_standard_channel_map_flac      | FLAC channel map.                                         |
731     | ma_standard_channel_map_vorbis    | Vorbis channel map.                                       |
732     | ma_standard_channel_map_sound4    | FreeBSD's sound(4).                                       |
733     | ma_standard_channel_map_sndio     | sndio channel map. http://www.sndio.org/tips.html.        |
734     | ma_standard_channel_map_webaudio  | https://webaudio.github.io/web-audio-api/#ChannelOrdering |
735     +-----------------------------------+-----------------------------------------------------------+
736
737 Below are the channel maps used by default in miniaudio (`ma_standard_channel_map_default`):
738
739     +---------------+---------------------------------+
740     | Channel Count | Mapping                         |
741     +---------------+---------------------------------+
742     | 1 (Mono)      | 0: MA_CHANNEL_MONO              |
743     +---------------+---------------------------------+
744     | 2 (Stereo)    | 0: MA_CHANNEL_FRONT_LEFT   <br> |
745     |               | 1: MA_CHANNEL_FRONT_RIGHT       |
746     +---------------+---------------------------------+
747     | 3             | 0: MA_CHANNEL_FRONT_LEFT   <br> |
748     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
749     |               | 2: MA_CHANNEL_FRONT_CENTER      |
750     +---------------+---------------------------------+
751     | 4 (Surround)  | 0: MA_CHANNEL_FRONT_LEFT   <br> |
752     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
753     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
754     |               | 3: MA_CHANNEL_BACK_CENTER       |
755     +---------------+---------------------------------+
756     | 5             | 0: MA_CHANNEL_FRONT_LEFT   <br> |
757     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
758     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
759     |               | 3: MA_CHANNEL_BACK_LEFT    <br> |
760     |               | 4: MA_CHANNEL_BACK_RIGHT        |
761     +---------------+---------------------------------+
762     | 6 (5.1)       | 0: MA_CHANNEL_FRONT_LEFT   <br> |
763     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
764     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
765     |               | 3: MA_CHANNEL_LFE          <br> |
766     |               | 4: MA_CHANNEL_SIDE_LEFT    <br> |
767     |               | 5: MA_CHANNEL_SIDE_RIGHT        |
768     +---------------+---------------------------------+
769     | 7             | 0: MA_CHANNEL_FRONT_LEFT   <br> |
770     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
771     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
772     |               | 3: MA_CHANNEL_LFE          <br> |
773     |               | 4: MA_CHANNEL_BACK_CENTER  <br> |
774     |               | 4: MA_CHANNEL_SIDE_LEFT    <br> |
775     |               | 5: MA_CHANNEL_SIDE_RIGHT        |
776     +---------------+---------------------------------+
777     | 8 (7.1)       | 0: MA_CHANNEL_FRONT_LEFT   <br> |
778     |               | 1: MA_CHANNEL_FRONT_RIGHT  <br> |
779     |               | 2: MA_CHANNEL_FRONT_CENTER <br> |
780     |               | 3: MA_CHANNEL_LFE          <br> |
781     |               | 4: MA_CHANNEL_BACK_LEFT    <br> |
782     |               | 5: MA_CHANNEL_BACK_RIGHT   <br> |
783     |               | 6: MA_CHANNEL_SIDE_LEFT    <br> |
784     |               | 7: MA_CHANNEL_SIDE_RIGHT        |
785     +---------------+---------------------------------+
786     | Other         | All channels set to 0. This     |
787     |               | is equivalent to the same       |
788     |               | mapping as the device.          |
789     +---------------+---------------------------------+
790
791
792
793 6.3. Resampling
794 ---------------
795 Resampling is achieved with the `ma_resampler` object. To create a resampler object, do something like the following:
796
797     ```c
798     ma_resampler_config config = ma_resampler_config_init(
799         ma_format_s16,
800         channels,
801         sampleRateIn,
802         sampleRateOut,
803         ma_resample_algorithm_linear);
804
805     ma_resampler resampler;
806     ma_result result = ma_resampler_init(&config, &resampler);
807     if (result != MA_SUCCESS) {
808         // An error occurred...
809     }
810     ```
811
812 Do the following to uninitialize the resampler:
813
814     ```c
815     ma_resampler_uninit(&resampler);
816     ```
817
818 The following example shows how data can be processed
819
820     ```c
821     ma_uint64 frameCountIn  = 1000;
822     ma_uint64 frameCountOut = 2000;
823     ma_result result = ma_resampler_process_pcm_frames(&resampler, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut);
824     if (result != MA_SUCCESS) {
825         // An error occurred...
826     }
827
828     // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the
829     // number of output frames written.
830     ```
831
832 To initialize the resampler you first need to set up a config (`ma_resampler_config`) with `ma_resampler_config_init()`. You need to specify the sample format
833 you want to use, the number of channels, the input and output sample rate, and the algorithm.
834
835 The sample format can be either `ma_format_s16` or `ma_format_f32`. If you need a different format you will need to perform pre- and post-conversions yourself
836 where necessary. Note that the format is the same for both input and output. The format cannot be changed after initialization.
837
838 The resampler supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization.
839
840 The sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the
841 only configuration property that can be changed after initialization.
842
843 The miniaudio resampler supports multiple algorithms:
844
845     +-----------+------------------------------+
846     | Algorithm | Enum Token                   |
847     +-----------+------------------------------+
848     | Linear    | ma_resample_algorithm_linear |
849     | Speex     | ma_resample_algorithm_speex  |
850     +-----------+------------------------------+
851
852 Because Speex is not public domain it is strictly opt-in and the code is stored in separate files. if you opt-in to the Speex backend you will need to consider
853 it's license, the text of which can be found in it's source files in "extras/speex_resampler". Details on how to opt-in to the Speex resampler is explained in
854 the Speex Resampler section below.
855
856 The algorithm cannot be changed after initialization.
857
858 Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process
859 frames, use `ma_resampler_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number of
860 input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the
861 number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large
862 buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek.
863
864 The sample rate can be changed dynamically on the fly. You can change this with explicit sample rates with `ma_resampler_set_rate()` and also with a decimal
865 ratio with `ma_resampler_set_rate_ratio()`. The ratio is in/out.
866
867 Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with
868 `ma_resampler_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of
869 input frames. You can do this with `ma_resampler_get_expected_output_frame_count()`.
870
871 Due to the nature of how resampling works, the resampler introduces some latency. This can be retrieved in terms of both the input rate and the output rate
872 with `ma_resampler_get_input_latency()` and `ma_resampler_get_output_latency()`.
873
874
875 6.3.1. Resampling Algorithms
876 ----------------------------
877 The choice of resampling algorithm depends on your situation and requirements. The linear resampler is the most efficient and has the least amount of latency,
878 but at the expense of poorer quality. The Speex resampler is higher quality, but slower with more latency. It also performs several heap allocations internally
879 for memory management.
880
881
882 6.3.1.1. Linear Resampling
883 --------------------------
884 The linear resampler is the fastest, but comes at the expense of poorer quality. There is, however, some control over the quality of the linear resampler which
885 may make it a suitable option depending on your requirements.
886
887 The linear resampler performs low-pass filtering before or after downsampling or upsampling, depending on the sample rates you're converting between. When
888 decreasing the sample rate, the low-pass filter will be applied before downsampling. When increasing the rate it will be performed after upsampling. By default
889 a fourth order low-pass filter will be applied. This can be configured via the `lpfOrder` configuration variable. Setting this to 0 will disable filtering.
890
891 The low-pass filter has a cutoff frequency which defaults to half the sample rate of the lowest of the input and output sample rates (Nyquist Frequency). This
892 can be controlled with the `lpfNyquistFactor` config variable. This defaults to 1, and should be in the range of 0..1, although a value of 0 does not make
893 sense and should be avoided. A value of 1 will use the Nyquist Frequency as the cutoff. A value of 0.5 will use half the Nyquist Frequency as the cutoff, etc.
894 Values less than 1 will result in more washed out sound due to more of the higher frequencies being removed. This config variable has no impact on performance
895 and is a purely perceptual configuration.
896
897 The API for the linear resampler is the same as the main resampler API, only it's called `ma_linear_resampler`.
898
899
900 6.3.1.2. Speex Resampling
901 -------------------------
902 The Speex resampler is made up of third party code which is released under the BSD license. Because it is licensed differently to miniaudio, which is public
903 domain, it is strictly opt-in and all of it's code is stored in separate files. If you opt-in to the Speex resampler you must consider the license text in it's
904 source files. To opt-in, you must first `#include` the following file before the implementation of miniaudio.h:
905
906     ```c
907     #include "extras/speex_resampler/ma_speex_resampler.h"
908     ```
909
910 Both the header and implementation is contained within the same file. The implementation can be included in your program like so:
911
912     ```c
913     #define MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION
914     #include "extras/speex_resampler/ma_speex_resampler.h"
915     ```
916
917 Note that even if you opt-in to the Speex backend, miniaudio won't use it unless you explicitly ask for it in the respective config of the object you are
918 initializing. If you try to use the Speex resampler without opting in, initialization of the `ma_resampler` object will fail with `MA_NO_BACKEND`.
919
920 The only configuration option to consider with the Speex resampler is the `speex.quality` config variable. This is a value between 0 and 10, with 0 being
921 the fastest with the poorest quality and 10 being the slowest with the highest quality. The default value is 3.
922
923
924
925 6.4. General Data Conversion
926 ----------------------------
927 The `ma_data_converter` API can be used to wrap sample format conversion, channel conversion and resampling into one operation. This is what miniaudio uses
928 internally to convert between the format requested when the device was initialized and the format of the backend's native device. The API for general data
929 conversion is very similar to the resampling API. Create a `ma_data_converter` object like this:
930
931     ```c
932     ma_data_converter_config config = ma_data_converter_config_init(
933         inputFormat,
934         outputFormat,
935         inputChannels,
936         outputChannels,
937         inputSampleRate,
938         outputSampleRate
939     );
940
941     ma_data_converter converter;
942     ma_result result = ma_data_converter_init(&config, &converter);
943     if (result != MA_SUCCESS) {
944         // An error occurred...
945     }
946     ```
947
948 In the example above we use `ma_data_converter_config_init()` to initialize the config, however there's many more properties that can be configured, such as
949 channel maps and resampling quality. Something like the following may be more suitable depending on your requirements:
950
951     ```c
952     ma_data_converter_config config = ma_data_converter_config_init_default();
953     config.formatIn = inputFormat;
954     config.formatOut = outputFormat;
955     config.channelsIn = inputChannels;
956     config.channelsOut = outputChannels;
957     config.sampleRateIn = inputSampleRate;
958     config.sampleRateOut = outputSampleRate;
959     ma_get_standard_channel_map(ma_standard_channel_map_flac, config.channelCountIn, config.channelMapIn);
960     config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER;
961     ```
962
963 Do the following to uninitialize the data converter:
964
965     ```c
966     ma_data_converter_uninit(&converter);
967     ```
968
969 The following example shows how data can be processed
970
971     ```c
972     ma_uint64 frameCountIn  = 1000;
973     ma_uint64 frameCountOut = 2000;
974     ma_result result = ma_data_converter_process_pcm_frames(&converter, pFramesIn, &frameCountIn, pFramesOut, &frameCountOut);
975     if (result != MA_SUCCESS) {
976         // An error occurred...
977     }
978
979     // At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the number
980     // of output frames written.
981     ```
982
983 The data converter supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization.
984
985 Sample rates can be anything other than zero, and are always specified in hertz. They should be set to something like 44100, etc. The sample rate is the only
986 configuration property that can be changed after initialization, but only if the `resampling.allowDynamicSampleRate` member of `ma_data_converter_config` is
987 set to `MA_TRUE`. To change the sample rate, use `ma_data_converter_set_rate()` or `ma_data_converter_set_rate_ratio()`. The ratio must be in/out. The
988 resampling algorithm cannot be changed after initialization.
989
990 Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process
991 frames, use `ma_data_converter_process_pcm_frames()`. On input, this function takes the number of output frames you can fit in the output buffer and the number
992 of input frames contained in the input buffer. On output these variables contain the number of output frames that were written to the output buffer and the
993 number of input frames that were consumed in the process. You can pass in NULL for the input buffer in which case it will be treated as an infinitely large
994 buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek.
995
996 Sometimes it's useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with
997 `ma_data_converter_get_required_input_frame_count()`. Likewise, it's sometimes useful to know exactly how many frames would be output given a certain number of
998 input frames. You can do this with `ma_data_converter_get_expected_output_frame_count()`.
999
1000 Due to the nature of how resampling works, the data converter introduces some latency if resampling is required. This can be retrieved in terms of both the
1001 input rate and the output rate with `ma_data_converter_get_input_latency()` and `ma_data_converter_get_output_latency()`.
1002
1003
1004
1005 7. Filtering
1006 ============
1007
1008 7.1. Biquad Filtering
1009 ---------------------
1010 Biquad filtering is achieved with the `ma_biquad` API. Example:
1011
1012     ```c
1013     ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2);
1014     ma_result result = ma_biquad_init(&config, &biquad);
1015     if (result != MA_SUCCESS) {
1016         // Error.
1017     }
1018
1019     ...
1020
1021     ma_biquad_process_pcm_frames(&biquad, pFramesOut, pFramesIn, frameCount);
1022     ```
1023
1024 Biquad filtering is implemented using transposed direct form 2. The numerator coefficients are b0, b1 and b2, and the denominator coefficients are a0, a1 and
1025 a2. The a0 coefficient is required and coefficients must not be pre-normalized.
1026
1027 Supported formats are `ma_format_s16` and `ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. When using
1028 `ma_format_s16` the biquad filter will use fixed point arithmetic. When using `ma_format_f32`, floating point arithmetic will be used.
1029
1030 Input and output frames are always interleaved.
1031
1032 Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
1033
1034     ```c
1035     ma_biquad_process_pcm_frames(&biquad, pMyData, pMyData, frameCount);
1036     ```
1037
1038 If you need to change the values of the coefficients, but maintain the values in the registers you can do so with `ma_biquad_reinit()`. This is useful if you
1039 need to change the properties of the filter while keeping the values of registers valid to avoid glitching. Do not use `ma_biquad_init()` for this as it will
1040 do a full initialization which involves clearing the registers to 0. Note that changing the format or channel count after initialization is invalid and will
1041 result in an error.
1042
1043
1044 7.2. Low-Pass Filtering
1045 -----------------------
1046 Low-pass filtering is achieved with the following APIs:
1047
1048     +---------+------------------------------------------+
1049     | API     | Description                              |
1050     +---------+------------------------------------------+
1051     | ma_lpf1 | First order low-pass filter              |
1052     | ma_lpf2 | Second order low-pass filter             |
1053     | ma_lpf  | High order low-pass filter (Butterworth) |
1054     +---------+------------------------------------------+
1055
1056 Low-pass filter example:
1057
1058     ```c
1059     ma_lpf_config config = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order);
1060     ma_result result = ma_lpf_init(&config, &lpf);
1061     if (result != MA_SUCCESS) {
1062         // Error.
1063     }
1064
1065     ...
1066
1067     ma_lpf_process_pcm_frames(&lpf, pFramesOut, pFramesIn, frameCount);
1068     ```
1069
1070 Supported formats are `ma_format_s16` and` ma_format_f32`. If you need to use a different format you need to convert it yourself beforehand. Input and output
1071 frames are always interleaved.
1072
1073 Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
1074
1075     ```c
1076     ma_lpf_process_pcm_frames(&lpf, pMyData, pMyData, frameCount);
1077     ```
1078
1079 The maximum filter order is limited to `MA_MAX_FILTER_ORDER` which is set to 8. If you need more, you can chain first and second order filters together.
1080
1081     ```c
1082     for (iFilter = 0; iFilter < filterCount; iFilter += 1) {
1083         ma_lpf2_process_pcm_frames(&lpf2[iFilter], pMyData, pMyData, frameCount);
1084     }
1085     ```
1086
1087 If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with `ma_lpf_reinit()`. This may be
1088 useful if you need to change the sample rate and/or cutoff frequency dynamically while maintaing smooth transitions. Note that changing the format or channel
1089 count after initialization is invalid and will result in an error.
1090
1091 The `ma_lpf` object supports a configurable order, but if you only need a first order filter you may want to consider using `ma_lpf1`. Likewise, if you only
1092 need a second order filter you can use `ma_lpf2`. The advantage of this is that they're lighter weight and a bit more efficient.
1093
1094 If an even filter order is specified, a series of second order filters will be processed in a chain. If an odd filter order is specified, a first order filter
1095 will be applied, followed by a series of second order filters in a chain.
1096
1097
1098 7.3. High-Pass Filtering
1099 ------------------------
1100 High-pass filtering is achieved with the following APIs:
1101
1102     +---------+-------------------------------------------+
1103     | API     | Description                               |
1104     +---------+-------------------------------------------+
1105     | ma_hpf1 | First order high-pass filter              |
1106     | ma_hpf2 | Second order high-pass filter             |
1107     | ma_hpf  | High order high-pass filter (Butterworth) |
1108     +---------+-------------------------------------------+
1109
1110 High-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_hpf1`, `ma_hpf2` and `ma_hpf`. See example code for low-pass filters
1111 for example usage.
1112
1113
1114 7.4. Band-Pass Filtering
1115 ------------------------
1116 Band-pass filtering is achieved with the following APIs:
1117
1118     +---------+-------------------------------+
1119     | API     | Description                   |
1120     +---------+-------------------------------+
1121     | ma_bpf2 | Second order band-pass filter |
1122     | ma_bpf  | High order band-pass filter   |
1123     +---------+-------------------------------+
1124
1125 Band-pass filters work exactly the same as low-pass filters, only the APIs are called `ma_bpf2` and `ma_hpf`. See example code for low-pass filters for example
1126 usage. Note that the order for band-pass filters must be an even number which means there is no first order band-pass filter, unlike low-pass and high-pass
1127 filters.
1128
1129
1130 7.5. Notch Filtering
1131 --------------------
1132 Notch filtering is achieved with the following APIs:
1133
1134     +-----------+------------------------------------------+
1135     | API       | Description                              |
1136     +-----------+------------------------------------------+
1137     | ma_notch2 | Second order notching filter             |
1138     +-----------+------------------------------------------+
1139
1140
1141 7.6. Peaking EQ Filtering
1142 -------------------------
1143 Peaking filtering is achieved with the following APIs:
1144
1145     +----------+------------------------------------------+
1146     | API      | Description                              |
1147     +----------+------------------------------------------+
1148     | ma_peak2 | Second order peaking filter              |
1149     +----------+------------------------------------------+
1150
1151
1152 7.7. Low Shelf Filtering
1153 ------------------------
1154 Low shelf filtering is achieved with the following APIs:
1155
1156     +-------------+------------------------------------------+
1157     | API         | Description                              |
1158     +-------------+------------------------------------------+
1159     | ma_loshelf2 | Second order low shelf filter            |
1160     +-------------+------------------------------------------+
1161
1162 Where a high-pass filter is used to eliminate lower frequencies, a low shelf filter can be used to just turn them down rather than eliminate them entirely.
1163
1164
1165 7.8. High Shelf Filtering
1166 -------------------------
1167 High shelf filtering is achieved with the following APIs:
1168
1169     +-------------+------------------------------------------+
1170     | API         | Description                              |
1171     +-------------+------------------------------------------+
1172     | ma_hishelf2 | Second order high shelf filter           |
1173     +-------------+------------------------------------------+
1174
1175 The high shelf filter has the same API as the low shelf filter, only you would use `ma_hishelf` instead of `ma_loshelf`. Where a low shelf filter is used to
1176 adjust the volume of low frequencies, the high shelf filter does the same thing for high frequencies.
1177
1178
1179
1180
1181 8. Waveform and Noise Generation
1182 ================================
1183
1184 8.1. Waveforms
1185 --------------
1186 miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved with the `ma_waveform` API. Example:
1187
1188     ```c
1189     ma_waveform_config config = ma_waveform_config_init(
1190         FORMAT,
1191         CHANNELS,
1192         SAMPLE_RATE,
1193         ma_waveform_type_sine,
1194         amplitude,
1195         frequency);
1196
1197     ma_waveform waveform;
1198     ma_result result = ma_waveform_init(&config, &waveform);
1199     if (result != MA_SUCCESS) {
1200         // Error.
1201     }
1202
1203     ...
1204
1205     ma_waveform_read_pcm_frames(&waveform, pOutput, frameCount);
1206     ```
1207
1208 The amplitude, frequency, type, and sample rate can be changed dynamically with `ma_waveform_set_amplitude()`, `ma_waveform_set_frequency()`,
1209 `ma_waveform_set_type()`, and `ma_waveform_set_sample_rate()` respectively.
1210
1211 You can invert the waveform by setting the amplitude to a negative value. You can use this to control whether or not a sawtooth has a positive or negative
1212 ramp, for example.
1213
1214 Below are the supported waveform types:
1215
1216     +---------------------------+
1217     | Enum Name                 |
1218     +---------------------------+
1219     | ma_waveform_type_sine     |
1220     | ma_waveform_type_square   |
1221     | ma_waveform_type_triangle |
1222     | ma_waveform_type_sawtooth |
1223     +---------------------------+
1224
1225
1226
1227 8.2. Noise
1228 ----------
1229 miniaudio supports generation of white, pink and Brownian noise via the `ma_noise` API. Example:
1230
1231     ```c
1232     ma_noise_config config = ma_noise_config_init(
1233         FORMAT,
1234         CHANNELS,
1235         ma_noise_type_white,
1236         SEED,
1237         amplitude);
1238
1239     ma_noise noise;
1240     ma_result result = ma_noise_init(&config, &noise);
1241     if (result != MA_SUCCESS) {
1242         // Error.
1243     }
1244
1245     ...
1246
1247     ma_noise_read_pcm_frames(&noise, pOutput, frameCount);
1248     ```
1249
1250 The noise API uses simple LCG random number generation. It supports a custom seed which is useful for things like automated testing requiring reproducibility.
1251 Setting the seed to zero will default to `MA_DEFAULT_LCG_SEED`.
1252
1253 The amplitude, seed, and type can be changed dynamically with `ma_noise_set_amplitude()`, `ma_noise_set_seed()`, and `ma_noise_set_type()` respectively.
1254
1255 By default, the noise API will use different values for different channels. So, for example, the left side in a stereo stream will be different to the right
1256 side. To instead have each channel use the same random value, set the `duplicateChannels` member of the noise config to true, like so:
1257
1258     ```c
1259     config.duplicateChannels = MA_TRUE;
1260     ```
1261
1262 Below are the supported noise types.
1263
1264     +------------------------+
1265     | Enum Name              |
1266     +------------------------+
1267     | ma_noise_type_white    |
1268     | ma_noise_type_pink     |
1269     | ma_noise_type_brownian |
1270     +------------------------+
1271
1272
1273
1274 9. Audio Buffers
1275 ================
1276 miniaudio supports reading from a buffer of raw audio data via the `ma_audio_buffer` API. This can read from memory that's managed by the application, but
1277 can also handle the memory management for you internally. Memory management is flexible and should support most use cases.
1278
1279 Audio buffers are initialised using the standard configuration system used everywhere in miniaudio:
1280
1281     ```c
1282     ma_audio_buffer_config config = ma_audio_buffer_config_init(
1283         format,
1284         channels,
1285         sizeInFrames,
1286         pExistingData,
1287         &allocationCallbacks);
1288
1289     ma_audio_buffer buffer;
1290     result = ma_audio_buffer_init(&config, &buffer);
1291     if (result != MA_SUCCESS) {
1292         // Error.
1293     }
1294
1295     ...
1296
1297     ma_audio_buffer_uninit(&buffer);
1298     ```
1299
1300 In the example above, the memory pointed to by `pExistingData` will *not* be copied and is how an application can do self-managed memory allocation. If you
1301 would rather make a copy of the data, use `ma_audio_buffer_init_copy()`. To uninitialize the buffer, use `ma_audio_buffer_uninit()`.
1302
1303 Sometimes it can be convenient to allocate the memory for the `ma_audio_buffer` structure and the raw audio data in a contiguous block of memory. That is,
1304 the raw audio data will be located immediately after the `ma_audio_buffer` structure. To do this, use `ma_audio_buffer_alloc_and_init()`:
1305
1306     ```c
1307     ma_audio_buffer_config config = ma_audio_buffer_config_init(
1308         format,
1309         channels,
1310         sizeInFrames,
1311         pExistingData,
1312         &allocationCallbacks);
1313
1314     ma_audio_buffer* pBuffer
1315     result = ma_audio_buffer_alloc_and_init(&config, &pBuffer);
1316     if (result != MA_SUCCESS) {
1317         // Error
1318     }
1319
1320     ...
1321
1322     ma_audio_buffer_uninit_and_free(&buffer);
1323     ```
1324
1325 If you initialize the buffer with `ma_audio_buffer_alloc_and_init()` you should uninitialize it with `ma_audio_buffer_uninit_and_free()`. In the example above,
1326 the memory pointed to by `pExistingData` will be copied into the buffer, which is contrary to the behavior of `ma_audio_buffer_init()`.
1327
1328 An audio buffer has a playback cursor just like a decoder. As you read frames from the buffer, the cursor moves forward. The last parameter (`loop`) can be
1329 used to determine if the buffer should loop. The return value is the number of frames actually read. If this is less than the number of frames requested it
1330 means the end has been reached. This should never happen if the `loop` parameter is set to true. If you want to manually loop back to the start, you can do so
1331 with with `ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)`. Below is an example for reading data from an audio buffer.
1332
1333     ```c
1334     ma_uint64 framesRead = ma_audio_buffer_read_pcm_frames(pAudioBuffer, pFramesOut, desiredFrameCount, isLooping);
1335     if (framesRead < desiredFrameCount) {
1336         // If not looping, this means the end has been reached. This should never happen in looping mode with valid input.
1337     }
1338     ```
1339
1340 Sometimes you may want to avoid the cost of data movement between the internal buffer and the output buffer. Instead you can use memory mapping to retrieve a
1341 pointer to a segment of data:
1342
1343     ```c
1344     void* pMappedFrames;
1345     ma_uint64 frameCount = frameCountToTryMapping;
1346     ma_result result = ma_audio_buffer_map(pAudioBuffer, &pMappedFrames, &frameCount);
1347     if (result == MA_SUCCESS) {
1348         // Map was successful. The value in frameCount will be how many frames were _actually_ mapped, which may be
1349         // less due to the end of the buffer being reached.
1350         ma_copy_pcm_frames(pFramesOut, pMappedFrames, frameCount, pAudioBuffer->format, pAudioBuffer->channels);
1351
1352         // You must unmap the buffer.
1353         ma_audio_buffer_unmap(pAudioBuffer, frameCount);
1354     }
1355     ```
1356
1357 When you use memory mapping, the read cursor is increment by the frame count passed in to `ma_audio_buffer_unmap()`. If you decide not to process every frame
1358 you can pass in a value smaller than the value returned by `ma_audio_buffer_map()`. The disadvantage to using memory mapping is that it does not handle looping
1359 for you. You can determine if the buffer is at the end for the purpose of looping with `ma_audio_buffer_at_end()` or by inspecting the return value of
1360 `ma_audio_buffer_unmap()` and checking if it equals `MA_AT_END`. You should not treat `MA_AT_END` as an error when returned by `ma_audio_buffer_unmap()`.
1361
1362
1363
1364 10. Ring Buffers
1365 ================
1366 miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via the `ma_rb` and `ma_pcm_rb` APIs. The `ma_rb` API operates
1367 on bytes, whereas the `ma_pcm_rb` operates on PCM frames. They are otherwise identical as `ma_pcm_rb` is just a wrapper around `ma_rb`.
1368
1369 Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved streams. The caller can also allocate their own backing memory for
1370 the ring buffer to use internally for added flexibility. Otherwise the ring buffer will manage it's internal memory for you.
1371
1372 The examples below use the PCM frame variant of the ring buffer since that's most likely the one you will want to use. To initialize a ring buffer, do
1373 something like the following:
1374
1375     ```c
1376     ma_pcm_rb rb;
1377     ma_result result = ma_pcm_rb_init(FORMAT, CHANNELS, BUFFER_SIZE_IN_FRAMES, NULL, NULL, &rb);
1378     if (result != MA_SUCCESS) {
1379         // Error
1380     }
1381     ```
1382
1383 The `ma_pcm_rb_init()` function takes the sample format and channel count as parameters because it's the PCM varient of the ring buffer API. For the regular
1384 ring buffer that operates on bytes you would call `ma_rb_init()` which leaves these out and just takes the size of the buffer in bytes instead of frames. The
1385 fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a `ma_allocation_callbacks` structure for custom memory allocation
1386 routines. Passing in `NULL` for this results in `MA_MALLOC()` and `MA_FREE()` being used.
1387
1388 Use `ma_pcm_rb_init_ex()` if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. To manage your
1389 sub-buffers you can use `ma_pcm_rb_get_subbuffer_stride()`, `ma_pcm_rb_get_subbuffer_offset()` and `ma_pcm_rb_get_subbuffer_ptr()`.
1390
1391 Use `ma_pcm_rb_acquire_read()` and `ma_pcm_rb_acquire_write()` to retrieve a pointer to a section of the ring buffer. You specify the number of frames you
1392 need, and on output it will set to what was actually acquired. If the read or write pointer is positioned such that the number of frames requested will require
1393 a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you're given may be less than the number you requested.
1394
1395 After calling `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()`, you do your work on the buffer and then "commit" it with `ma_pcm_rb_commit_read()` or
1396 `ma_pcm_rb_commit_write()`. This is where the read/write pointers are updated. When you commit you need to pass in the buffer that was returned by the earlier
1397 call to `ma_pcm_rb_acquire_read()` or `ma_pcm_rb_acquire_write()` and is only used for validation. The number of frames passed to `ma_pcm_rb_commit_read()` and
1398 `ma_pcm_rb_commit_write()` is what's used to increment the pointers, and can be less that what was originally requested.
1399
1400 If you want to correct for drift between the write pointer and the read pointer you can use a combination of `ma_pcm_rb_pointer_distance()`,
1401 `ma_pcm_rb_seek_read()` and `ma_pcm_rb_seek_write()`. Note that you can only move the pointers forward, and you should only move the read pointer forward via
1402 the consumer thread, and the write pointer forward by the producer thread. If there is too much space between the pointers, move the read pointer forward. If
1403 there is too little space between the pointers, move the write pointer forward.
1404
1405 You can use a ring buffer at the byte level instead of the PCM frame level by using the `ma_rb` API. This is exactly the same, only you will use the `ma_rb`
1406 functions instead of `ma_pcm_rb` and instead of frame counts you will pass around byte counts.
1407
1408 The maximum size of the buffer in bytes is `0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)` due to the most significant bit being used to encode a loop flag and the internally
1409 managed buffers always being aligned to MA_SIMD_ALIGNMENT.
1410
1411 Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread.
1412
1413
1414
1415 11. Backends
1416 ============
1417 The following backends are supported by miniaudio.
1418
1419     +-------------+-----------------------+--------------------------------------------------------+
1420     | Name        | Enum Name             | Supported Operating Systems                            |
1421     +-------------+-----------------------+--------------------------------------------------------+
1422     | WASAPI      | ma_backend_wasapi     | Windows Vista+                                         |
1423     | DirectSound | ma_backend_dsound     | Windows XP+                                            |
1424     | WinMM       | ma_backend_winmm      | Windows XP+ (may work on older versions, but untested) |
1425     | Core Audio  | ma_backend_coreaudio  | macOS, iOS                                             |
1426     | ALSA        | ma_backend_alsa       | Linux                                                  |
1427     | PulseAudio  | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android)  |
1428     | JACK        | ma_backend_jack       | Cross Platform (disabled on BSD and Android)           |
1429     | sndio       | ma_backend_sndio      | OpenBSD                                                |
1430     | audio(4)    | ma_backend_audio4     | NetBSD, OpenBSD                                        |
1431     | OSS         | ma_backend_oss        | FreeBSD                                                |
1432     | AAudio      | ma_backend_aaudio     | Android 8+                                             |
1433     | OpenSL ES   | ma_backend_opensl     | Android (API level 16+)                                |
1434     | Web Audio   | ma_backend_webaudio   | Web (via Emscripten)                                   |
1435     | Custom      | ma_backend_custom     | Cross Platform                                         |
1436     | Null        | ma_backend_null       | Cross Platform (not used on Web)                       |
1437     +-------------+-----------------------+--------------------------------------------------------+
1438
1439 Some backends have some nuance details you may want to be aware of.
1440
1441 11.1. WASAPI
1442 ------------
1443 - Low-latency shared mode will be disabled when using an application-defined sample rate which is different to the device's native sample rate. To work around
1444   this, set `wasapi.noAutoConvertSRC` to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing when the
1445   `AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM` flag is specified. Setting wasapi.noAutoConvertSRC will result in miniaudio's internal resampler being used instead
1446   which will in turn enable the use of low-latency shared mode.
1447
1448 11.2. PulseAudio
1449 ----------------
1450 - If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki:
1451   https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling. Alternatively, consider using a different backend such as ALSA.
1452
1453 11.3. Android
1454 -------------
1455 - To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: `<uses-permission android:name="android.permission.RECORD_AUDIO" />`
1456 - With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES.
1457 - With AAudio, only default devices are enumerated. This is due to AAudio not having an enumeration API (devices are enumerated through Java). You can however
1458   perform your own device enumeration through Java and then set the ID in the ma_device_id structure (ma_device_id.aaudio) and pass it to ma_device_init().
1459 - The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio's built-in resampler is to take advantage of any
1460   potential device-specific optimizations the driver may implement.
1461
1462 11.4. UWP
1463 ---------
1464 - UWP only supports default playback and capture devices.
1465 - UWP requires the Microphone capability to be enabled in the application's manifest (Package.appxmanifest):
1466
1467     ```
1468     <Package ...>
1469         ...
1470         <Capabilities>
1471             <DeviceCapability Name="microphone" />
1472         </Capabilities>
1473     </Package>
1474     ```
1475
1476 11.5. Web Audio / Emscripten
1477 ----------------------------
1478 - You cannot use `-std=c*` compiler flags, nor `-ansi`. This only applies to the Emscripten build.
1479 - The first time a context is initialized it will create a global object called "miniaudio" whose primary purpose is to act as a factory for device objects.
1480 - Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated.
1481 - Google has implemented a policy in their browsers that prevent automatic media output without first receiving some kind of user input. The following web page
1482   has additional details: https://developers.google.com/web/updates/2017/09/autoplay-policy-changes. Starting the device may fail if you try to start playback
1483   without first handling some kind of user input.
1484
1485
1486
1487 12. Miscellaneous Notes
1488 =======================
1489 - Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as
1490   PulseAudio may naturally support it, though not all have been tested.
1491 - The contents of the output buffer passed into the data callback will always be pre-initialized to silence unless the `noPreZeroedOutputBuffer` config variable
1492   in `ma_device_config` is set to true, in which case it'll be undefined which will require you to write something to the entire buffer.
1493 - By default miniaudio will automatically clip samples. This only applies when the playback sample format is configured as `ma_format_f32`. If you are doing
1494   clipping yourself, you can disable this overhead by setting `noClip` to true in the device config.
1495 - The sndio backend is currently only enabled on OpenBSD builds.
1496 - The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it.
1497 - Note that GCC and Clang requires `-msse2`, `-mavx2`, etc. for SIMD optimizations.
1498 - When compiling with VC6 and earlier, decoding is restricted to files less than 2GB in size. This is due to 64-bit file APIs not being available.
1499 */
1500
1501 #ifndef miniaudio_h
1502 #define miniaudio_h
1503
1504 #ifdef __cplusplus
1505 extern "C" {
1506 #endif
1507
1508 #define MA_STRINGIFY(x)     #x
1509 #define MA_XSTRINGIFY(x)    MA_STRINGIFY(x)
1510
1511 #define MA_VERSION_MAJOR    0
1512 #define MA_VERSION_MINOR    10
1513 #define MA_VERSION_REVISION 33
1514 #define MA_VERSION_STRING   MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
1515
1516 #if defined(_MSC_VER) && !defined(__clang__)
1517     #pragma warning(push)
1518     #pragma warning(disable:4201)   /* nonstandard extension used: nameless struct/union */
1519     #pragma warning(disable:4214)   /* nonstandard extension used: bit field types other than int */
1520     #pragma warning(disable:4324)   /* structure was padded due to alignment specifier */
1521 #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
1522     #pragma GCC diagnostic push
1523     #pragma GCC diagnostic ignored "-Wpedantic" /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
1524     #if defined(__clang__)
1525         #pragma GCC diagnostic ignored "-Wc11-extensions"   /* anonymous unions are a C11 extension */
1526     #endif
1527 #endif
1528
1529 /* Platform/backend detection. */
1530 #ifdef _WIN32
1531     #define MA_WIN32
1532     #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
1533         #define MA_WIN32_UWP
1534     #else
1535         #define MA_WIN32_DESKTOP
1536     #endif
1537 #else
1538     #define MA_POSIX
1539     #include <pthread.h>    /* Unfortunate #include, but needed for pthread_t, pthread_mutex_t and pthread_cond_t types. */
1540
1541     #ifdef __unix__
1542         #define MA_UNIX
1543         #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
1544             #define MA_BSD
1545         #endif
1546     #endif
1547     #ifdef __linux__
1548         #define MA_LINUX
1549     #endif
1550     #ifdef __APPLE__
1551         #define MA_APPLE
1552     #endif
1553     #ifdef __ANDROID__
1554         #define MA_ANDROID
1555     #endif
1556     #ifdef __EMSCRIPTEN__
1557         #define MA_EMSCRIPTEN
1558     #endif
1559 #endif
1560
1561 #include <stddef.h> /* For size_t. */
1562
1563 /* Sized types. */
1564 typedef   signed char           ma_int8;
1565 typedef unsigned char           ma_uint8;
1566 typedef   signed short          ma_int16;
1567 typedef unsigned short          ma_uint16;
1568 typedef   signed int            ma_int32;
1569 typedef unsigned int            ma_uint32;
1570 #if defined(_MSC_VER)
1571     typedef   signed __int64    ma_int64;
1572     typedef unsigned __int64    ma_uint64;
1573 #else
1574     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
1575         #pragma GCC diagnostic push
1576         #pragma GCC diagnostic ignored "-Wlong-long"
1577         #if defined(__clang__)
1578             #pragma GCC diagnostic ignored "-Wc++11-long-long"
1579         #endif
1580     #endif
1581     typedef   signed long long  ma_int64;
1582     typedef unsigned long long  ma_uint64;
1583     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
1584         #pragma GCC diagnostic pop
1585     #endif
1586 #endif
1587 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
1588     typedef ma_uint64           ma_uintptr;
1589 #else
1590     typedef ma_uint32           ma_uintptr;
1591 #endif
1592
1593 typedef ma_uint8    ma_bool8;
1594 typedef ma_uint32   ma_bool32;
1595 #define MA_TRUE     1
1596 #define MA_FALSE    0
1597
1598 typedef void* ma_handle;
1599 typedef void* ma_ptr;
1600 typedef void (* ma_proc)(void);
1601
1602 #if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED)
1603 typedef ma_uint16 wchar_t;
1604 #endif
1605
1606 /* Define NULL for some compilers. */
1607 #ifndef NULL
1608 #define NULL 0
1609 #endif
1610
1611 #if defined(SIZE_MAX)
1612     #define MA_SIZE_MAX    SIZE_MAX
1613 #else
1614     #define MA_SIZE_MAX    0xFFFFFFFF  /* When SIZE_MAX is not defined by the standard library just default to the maximum 32-bit unsigned integer. */
1615 #endif
1616
1617
1618 #ifdef _MSC_VER
1619     #define MA_INLINE __forceinline
1620 #elif defined(__GNUC__)
1621     /*
1622     I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
1623     the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
1624     case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
1625     command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
1626     I am using "__inline__" only when we're compiling in strict ANSI mode.
1627     */
1628     #if defined(__STRICT_ANSI__)
1629         #define MA_INLINE __inline__ __attribute__((always_inline))
1630     #else
1631         #define MA_INLINE inline __attribute__((always_inline))
1632     #endif
1633 #elif defined(__WATCOMC__)
1634     #define MA_INLINE __inline
1635 #else
1636     #define MA_INLINE
1637 #endif
1638
1639 #if !defined(MA_API)
1640     #if defined(MA_DLL)
1641         #if defined(_WIN32)
1642             #define MA_DLL_IMPORT  __declspec(dllimport)
1643             #define MA_DLL_EXPORT  __declspec(dllexport)
1644             #define MA_DLL_PRIVATE static
1645         #else
1646             #if defined(__GNUC__) && __GNUC__ >= 4
1647                 #define MA_DLL_IMPORT  __attribute__((visibility("default")))
1648                 #define MA_DLL_EXPORT  __attribute__((visibility("default")))
1649                 #define MA_DLL_PRIVATE __attribute__((visibility("hidden")))
1650             #else
1651                 #define MA_DLL_IMPORT
1652                 #define MA_DLL_EXPORT
1653                 #define MA_DLL_PRIVATE static
1654             #endif
1655         #endif
1656
1657         #if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION)
1658             #define MA_API  MA_DLL_EXPORT
1659         #else
1660             #define MA_API  MA_DLL_IMPORT
1661         #endif
1662         #define MA_PRIVATE MA_DLL_PRIVATE
1663     #else
1664         #define MA_API extern
1665         #define MA_PRIVATE static
1666     #endif
1667 #endif
1668
1669 /* SIMD alignment in bytes. Currently set to 64 bytes in preparation for future AVX-512 optimizations. */
1670 #define MA_SIMD_ALIGNMENT  64
1671
1672
1673 /*
1674 Logging Levels
1675 ==============
1676 A log level will automatically include the lower levels. For example, verbose logging will enable everything. The warning log level will only include warnings
1677 and errors, but will ignore informational and verbose logging. If you only want to handle a specific log level, implement a custom log callback (see
1678 ma_context_init() for details) and interrogate the `logLevel` parameter.
1679
1680 By default the log level will be set to MA_LOG_LEVEL_ERROR, but you can change this by defining MA_LOG_LEVEL before the implementation of miniaudio.
1681
1682 MA_LOG_LEVEL_VERBOSE
1683     Mainly intended for debugging. This will enable all log levels and can be triggered from within the data callback so care must be taken when enabling this
1684     in production environments.
1685
1686 MA_LOG_LEVEL_INFO
1687     Informational logging. Useful for debugging. This will also enable warning and error logs. This will never be called from within the data callback.
1688
1689 MA_LOG_LEVEL_WARNING
1690     Warnings. You should enable this in you development builds and action them when encounted. This will also enable error logs. These logs usually indicate a
1691     potential problem or misconfiguration, but still allow you to keep running. This will never be called from within the data callback.
1692
1693 MA_LOG_LEVEL_ERROR
1694     Error logging. This will be fired when an operation fails and is subsequently aborted. This can be fired from within the data callback, in which case the
1695     device will be stopped. You should always have this log level enabled.
1696 */
1697 #define MA_LOG_LEVEL_VERBOSE   4
1698 #define MA_LOG_LEVEL_INFO      3
1699 #define MA_LOG_LEVEL_WARNING   2
1700 #define MA_LOG_LEVEL_ERROR     1
1701
1702 #ifndef MA_LOG_LEVEL
1703 #define MA_LOG_LEVEL           MA_LOG_LEVEL_ERROR
1704 #endif
1705
1706 /*
1707 An annotation for variables which must be used atomically. This doesn't actually do anything - it's
1708 just used as a way for humans to identify variables that should be used atomically.
1709 */
1710 #define MA_ATOMIC
1711
1712 typedef struct ma_context ma_context;
1713 typedef struct ma_device ma_device;
1714
1715 typedef ma_uint8 ma_channel;
1716 #define MA_CHANNEL_NONE                                0
1717 #define MA_CHANNEL_MONO                                1
1718 #define MA_CHANNEL_FRONT_LEFT                          2
1719 #define MA_CHANNEL_FRONT_RIGHT                         3
1720 #define MA_CHANNEL_FRONT_CENTER                        4
1721 #define MA_CHANNEL_LFE                                 5
1722 #define MA_CHANNEL_BACK_LEFT                           6
1723 #define MA_CHANNEL_BACK_RIGHT                          7
1724 #define MA_CHANNEL_FRONT_LEFT_CENTER                   8
1725 #define MA_CHANNEL_FRONT_RIGHT_CENTER                  9
1726 #define MA_CHANNEL_BACK_CENTER                         10
1727 #define MA_CHANNEL_SIDE_LEFT                           11
1728 #define MA_CHANNEL_SIDE_RIGHT                          12
1729 #define MA_CHANNEL_TOP_CENTER                          13
1730 #define MA_CHANNEL_TOP_FRONT_LEFT                      14
1731 #define MA_CHANNEL_TOP_FRONT_CENTER                    15
1732 #define MA_CHANNEL_TOP_FRONT_RIGHT                     16
1733 #define MA_CHANNEL_TOP_BACK_LEFT                       17
1734 #define MA_CHANNEL_TOP_BACK_CENTER                     18
1735 #define MA_CHANNEL_TOP_BACK_RIGHT                      19
1736 #define MA_CHANNEL_AUX_0                               20
1737 #define MA_CHANNEL_AUX_1                               21
1738 #define MA_CHANNEL_AUX_2                               22
1739 #define MA_CHANNEL_AUX_3                               23
1740 #define MA_CHANNEL_AUX_4                               24
1741 #define MA_CHANNEL_AUX_5                               25
1742 #define MA_CHANNEL_AUX_6                               26
1743 #define MA_CHANNEL_AUX_7                               27
1744 #define MA_CHANNEL_AUX_8                               28
1745 #define MA_CHANNEL_AUX_9                               29
1746 #define MA_CHANNEL_AUX_10                              30
1747 #define MA_CHANNEL_AUX_11                              31
1748 #define MA_CHANNEL_AUX_12                              32
1749 #define MA_CHANNEL_AUX_13                              33
1750 #define MA_CHANNEL_AUX_14                              34
1751 #define MA_CHANNEL_AUX_15                              35
1752 #define MA_CHANNEL_AUX_16                              36
1753 #define MA_CHANNEL_AUX_17                              37
1754 #define MA_CHANNEL_AUX_18                              38
1755 #define MA_CHANNEL_AUX_19                              39
1756 #define MA_CHANNEL_AUX_20                              40
1757 #define MA_CHANNEL_AUX_21                              41
1758 #define MA_CHANNEL_AUX_22                              42
1759 #define MA_CHANNEL_AUX_23                              43
1760 #define MA_CHANNEL_AUX_24                              44
1761 #define MA_CHANNEL_AUX_25                              45
1762 #define MA_CHANNEL_AUX_26                              46
1763 #define MA_CHANNEL_AUX_27                              47
1764 #define MA_CHANNEL_AUX_28                              48
1765 #define MA_CHANNEL_AUX_29                              49
1766 #define MA_CHANNEL_AUX_30                              50
1767 #define MA_CHANNEL_AUX_31                              51
1768 #define MA_CHANNEL_LEFT                                MA_CHANNEL_FRONT_LEFT
1769 #define MA_CHANNEL_RIGHT                               MA_CHANNEL_FRONT_RIGHT
1770 #define MA_CHANNEL_POSITION_COUNT                      (MA_CHANNEL_AUX_31 + 1)
1771
1772
1773 typedef int ma_result;
1774 #define MA_SUCCESS                                      0
1775 #define MA_ERROR                                       -1   /* A generic error. */
1776 #define MA_INVALID_ARGS                                -2
1777 #define MA_INVALID_OPERATION                           -3
1778 #define MA_OUT_OF_MEMORY                               -4
1779 #define MA_OUT_OF_RANGE                                -5
1780 #define MA_ACCESS_DENIED                               -6
1781 #define MA_DOES_NOT_EXIST                              -7
1782 #define MA_ALREADY_EXISTS                              -8
1783 #define MA_TOO_MANY_OPEN_FILES                         -9
1784 #define MA_INVALID_FILE                                -10
1785 #define MA_TOO_BIG                                     -11
1786 #define MA_PATH_TOO_LONG                               -12
1787 #define MA_NAME_TOO_LONG                               -13
1788 #define MA_NOT_DIRECTORY                               -14
1789 #define MA_IS_DIRECTORY                                -15
1790 #define MA_DIRECTORY_NOT_EMPTY                         -16
1791 #define MA_END_OF_FILE                                 -17
1792 #define MA_NO_SPACE                                    -18
1793 #define MA_BUSY                                        -19
1794 #define MA_IO_ERROR                                    -20
1795 #define MA_INTERRUPT                                   -21
1796 #define MA_UNAVAILABLE                                 -22
1797 #define MA_ALREADY_IN_USE                              -23
1798 #define MA_BAD_ADDRESS                                 -24
1799 #define MA_BAD_SEEK                                    -25
1800 #define MA_BAD_PIPE                                    -26
1801 #define MA_DEADLOCK                                    -27
1802 #define MA_TOO_MANY_LINKS                              -28
1803 #define MA_NOT_IMPLEMENTED                             -29
1804 #define MA_NO_MESSAGE                                  -30
1805 #define MA_BAD_MESSAGE                                 -31
1806 #define MA_NO_DATA_AVAILABLE                           -32
1807 #define MA_INVALID_DATA                                -33
1808 #define MA_TIMEOUT                                     -34
1809 #define MA_NO_NETWORK                                  -35
1810 #define MA_NOT_UNIQUE                                  -36
1811 #define MA_NOT_SOCKET                                  -37
1812 #define MA_NO_ADDRESS                                  -38
1813 #define MA_BAD_PROTOCOL                                -39
1814 #define MA_PROTOCOL_UNAVAILABLE                        -40
1815 #define MA_PROTOCOL_NOT_SUPPORTED                      -41
1816 #define MA_PROTOCOL_FAMILY_NOT_SUPPORTED               -42
1817 #define MA_ADDRESS_FAMILY_NOT_SUPPORTED                -43
1818 #define MA_SOCKET_NOT_SUPPORTED                        -44
1819 #define MA_CONNECTION_RESET                            -45
1820 #define MA_ALREADY_CONNECTED                           -46
1821 #define MA_NOT_CONNECTED                               -47
1822 #define MA_CONNECTION_REFUSED                          -48
1823 #define MA_NO_HOST                                     -49
1824 #define MA_IN_PROGRESS                                 -50
1825 #define MA_CANCELLED                                   -51
1826 #define MA_MEMORY_ALREADY_MAPPED                       -52
1827 #define MA_AT_END                                      -53
1828
1829 /* General miniaudio-specific errors. */
1830 #define MA_FORMAT_NOT_SUPPORTED                        -100
1831 #define MA_DEVICE_TYPE_NOT_SUPPORTED                   -101
1832 #define MA_SHARE_MODE_NOT_SUPPORTED                    -102
1833 #define MA_NO_BACKEND                                  -103
1834 #define MA_NO_DEVICE                                   -104
1835 #define MA_API_NOT_FOUND                               -105
1836 #define MA_INVALID_DEVICE_CONFIG                       -106
1837 #define MA_LOOP                                        -107
1838
1839 /* State errors. */
1840 #define MA_DEVICE_NOT_INITIALIZED                      -200
1841 #define MA_DEVICE_ALREADY_INITIALIZED                  -201
1842 #define MA_DEVICE_NOT_STARTED                          -202
1843 #define MA_DEVICE_NOT_STOPPED                          -203
1844
1845 /* Operation errors. */
1846 #define MA_FAILED_TO_INIT_BACKEND                      -300
1847 #define MA_FAILED_TO_OPEN_BACKEND_DEVICE               -301
1848 #define MA_FAILED_TO_START_BACKEND_DEVICE              -302
1849 #define MA_FAILED_TO_STOP_BACKEND_DEVICE               -303
1850
1851
1852 #define MA_MIN_CHANNELS                                1
1853 #ifndef MA_MAX_CHANNELS
1854 #define MA_MAX_CHANNELS                                32
1855 #endif
1856
1857
1858 #ifndef MA_MAX_FILTER_ORDER
1859 #define MA_MAX_FILTER_ORDER                            8
1860 #endif
1861
1862 typedef enum
1863 {
1864     ma_stream_format_pcm = 0
1865 } ma_stream_format;
1866
1867 typedef enum
1868 {
1869     ma_stream_layout_interleaved = 0,
1870     ma_stream_layout_deinterleaved
1871 } ma_stream_layout;
1872
1873 typedef enum
1874 {
1875     ma_dither_mode_none = 0,
1876     ma_dither_mode_rectangle,
1877     ma_dither_mode_triangle
1878 } ma_dither_mode;
1879
1880 typedef enum
1881 {
1882     /*
1883     I like to keep these explicitly defined because they're used as a key into a lookup table. When items are
1884     added to this, make sure there are no gaps and that they're added to the lookup table in ma_get_bytes_per_sample().
1885     */
1886     ma_format_unknown = 0,     /* Mainly used for indicating an error, but also used as the default for the output format for decoders. */
1887     ma_format_u8      = 1,
1888     ma_format_s16     = 2,     /* Seems to be the most widely supported format. */
1889     ma_format_s24     = 3,     /* Tightly packed. 3 bytes per sample. */
1890     ma_format_s32     = 4,
1891     ma_format_f32     = 5,
1892     ma_format_count
1893 } ma_format;
1894
1895 typedef enum
1896 {
1897     /* Standard rates need to be in priority order. */
1898     ma_standard_sample_rate_48000  = 48000,     /* Most common */
1899     ma_standard_sample_rate_44100  = 44100,
1900
1901     ma_standard_sample_rate_32000  = 32000,     /* Lows */
1902     ma_standard_sample_rate_24000  = 24000,
1903     ma_standard_sample_rate_22050  = 22050,
1904     
1905     ma_standard_sample_rate_88200  = 88200,     /* Highs */
1906     ma_standard_sample_rate_96000  = 96000,
1907     ma_standard_sample_rate_176400 = 176400,
1908     ma_standard_sample_rate_192000 = 192000,
1909
1910     ma_standard_sample_rate_16000  = 16000,     /* Extreme lows */
1911     ma_standard_sample_rate_11025  = 11250,
1912     ma_standard_sample_rate_8000   = 8000,
1913
1914     ma_standard_sample_rate_352800 = 352800,    /* Extreme highs */
1915     ma_standard_sample_rate_384000 = 384000,
1916
1917     ma_standard_sample_rate_min    = ma_standard_sample_rate_8000,
1918     ma_standard_sample_rate_max    = ma_standard_sample_rate_384000,
1919     ma_standard_sample_rate_count  = 14         /* Need to maintain the count manually. Make sure this is updated if items are added to enum. */
1920 } ma_standard_sample_rate;
1921
1922 /* These are deprecated. Use ma_standard_sample_rate_min and ma_standard_sample_rate_max. */
1923 #define MA_MIN_SAMPLE_RATE  (ma_uint32)ma_standard_sample_rate_min
1924 #define MA_MAX_SAMPLE_RATE  (ma_uint32)ma_standard_sample_rate_max
1925
1926
1927 typedef enum
1928 {
1929     ma_channel_mix_mode_rectangular = 0,   /* Simple averaging based on the plane(s) the channel is sitting on. */
1930     ma_channel_mix_mode_simple,            /* Drop excess channels; zeroed out extra channels. */
1931     ma_channel_mix_mode_custom_weights,    /* Use custom weights specified in ma_channel_router_config. */
1932     ma_channel_mix_mode_planar_blend = ma_channel_mix_mode_rectangular,
1933     ma_channel_mix_mode_default = ma_channel_mix_mode_planar_blend
1934 } ma_channel_mix_mode;
1935
1936 typedef enum
1937 {
1938     ma_standard_channel_map_microsoft,
1939     ma_standard_channel_map_alsa,
1940     ma_standard_channel_map_rfc3551,   /* Based off AIFF. */
1941     ma_standard_channel_map_flac,
1942     ma_standard_channel_map_vorbis,
1943     ma_standard_channel_map_sound4,    /* FreeBSD's sound(4). */
1944     ma_standard_channel_map_sndio,     /* www.sndio.org/tips.html */
1945     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. */
1946     ma_standard_channel_map_default = ma_standard_channel_map_microsoft
1947 } ma_standard_channel_map;
1948
1949 typedef enum
1950 {
1951     ma_performance_profile_low_latency = 0,
1952     ma_performance_profile_conservative
1953 } ma_performance_profile;
1954
1955
1956 typedef struct
1957 {
1958     void* pUserData;
1959     void* (* onMalloc)(size_t sz, void* pUserData);
1960     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
1961     void  (* onFree)(void* p, void* pUserData);
1962 } ma_allocation_callbacks;
1963
1964 typedef struct
1965 {
1966     ma_int32 state;
1967 } ma_lcg;
1968
1969
1970 #ifndef MA_NO_THREADING
1971 /* Thread priorities should be ordered such that the default priority of the worker thread is 0. */
1972 typedef enum
1973 {
1974     ma_thread_priority_idle     = -5,
1975     ma_thread_priority_lowest   = -4,
1976     ma_thread_priority_low      = -3,
1977     ma_thread_priority_normal   = -2,
1978     ma_thread_priority_high     = -1,
1979     ma_thread_priority_highest  =  0,
1980     ma_thread_priority_realtime =  1,
1981     ma_thread_priority_default  =  0
1982 } ma_thread_priority;
1983
1984 /* Spinlocks are 32-bit for compatibility reasons. */
1985 typedef ma_uint32 ma_spinlock;
1986
1987 #if defined(MA_WIN32)
1988 typedef ma_handle ma_thread;
1989 #endif
1990 #if defined(MA_POSIX)
1991 typedef pthread_t ma_thread;
1992 #endif
1993
1994 #if defined(MA_WIN32)
1995 typedef ma_handle ma_mutex;
1996 #endif
1997 #if defined(MA_POSIX)
1998 typedef pthread_mutex_t ma_mutex;
1999 #endif
2000
2001 #if defined(MA_WIN32)
2002 typedef ma_handle ma_event;
2003 #endif
2004 #if defined(MA_POSIX)
2005 typedef struct
2006 {
2007     ma_uint32 value;
2008     pthread_mutex_t lock;
2009     pthread_cond_t cond;
2010 } ma_event;
2011 #endif  /* MA_POSIX */
2012
2013 #if defined(MA_WIN32)
2014 typedef ma_handle ma_semaphore;
2015 #endif
2016 #if defined(MA_POSIX)
2017 typedef struct
2018 {
2019     int value;
2020     pthread_mutex_t lock;
2021     pthread_cond_t cond;
2022 } ma_semaphore;
2023 #endif  /* MA_POSIX */
2024 #else
2025 /* 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. */
2026 #ifndef MA_NO_DEVICE_IO
2027 #error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
2028 #endif
2029 #endif  /* MA_NO_THREADING */
2030
2031
2032 /*
2033 Retrieves the version of miniaudio as separated integers. Each component can be NULL if it's not required.
2034 */
2035 MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision);
2036
2037 /*
2038 Retrieves the version of miniaudio as a string which can be useful for logging purposes.
2039 */
2040 MA_API const char* ma_version_string(void);
2041
2042
2043 /**************************************************************************************************************************************************************
2044
2045 Biquad Filtering
2046
2047 **************************************************************************************************************************************************************/
2048 typedef union
2049 {
2050     float    f32;
2051     ma_int32 s32;
2052 } ma_biquad_coefficient;
2053
2054 typedef struct
2055 {
2056     ma_format format;
2057     ma_uint32 channels;
2058     double b0;
2059     double b1;
2060     double b2;
2061     double a0;
2062     double a1;
2063     double a2;
2064 } ma_biquad_config;
2065
2066 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);
2067
2068 typedef struct
2069 {
2070     ma_format format;
2071     ma_uint32 channels;
2072     ma_biquad_coefficient b0;
2073     ma_biquad_coefficient b1;
2074     ma_biquad_coefficient b2;
2075     ma_biquad_coefficient a1;
2076     ma_biquad_coefficient a2;
2077     ma_biquad_coefficient r1[MA_MAX_CHANNELS];
2078     ma_biquad_coefficient r2[MA_MAX_CHANNELS];
2079 } ma_biquad;
2080
2081 MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ);
2082 MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ);
2083 MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2084 MA_API ma_uint32 ma_biquad_get_latency(const ma_biquad* pBQ);
2085
2086
2087 /**************************************************************************************************************************************************************
2088
2089 Low-Pass Filtering
2090
2091 **************************************************************************************************************************************************************/
2092 typedef struct
2093 {
2094     ma_format format;
2095     ma_uint32 channels;
2096     ma_uint32 sampleRate;
2097     double cutoffFrequency;
2098     double q;
2099 } ma_lpf1_config, ma_lpf2_config;
2100
2101 MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency);
2102 MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q);
2103
2104 typedef struct
2105 {
2106     ma_format format;
2107     ma_uint32 channels;
2108     ma_biquad_coefficient a;
2109     ma_biquad_coefficient r1[MA_MAX_CHANNELS];
2110 } ma_lpf1;
2111
2112 MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF);
2113 MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF);
2114 MA_API ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2115 MA_API ma_uint32 ma_lpf1_get_latency(const ma_lpf1* pLPF);
2116
2117 typedef struct
2118 {
2119     ma_biquad bq;   /* The second order low-pass filter is implemented as a biquad filter. */
2120 } ma_lpf2;
2121
2122 MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF);
2123 MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF);
2124 MA_API ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2125 MA_API ma_uint32 ma_lpf2_get_latency(const ma_lpf2* pLPF);
2126
2127
2128 typedef struct
2129 {
2130     ma_format format;
2131     ma_uint32 channels;
2132     ma_uint32 sampleRate;
2133     double cutoffFrequency;
2134     ma_uint32 order;    /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
2135 } ma_lpf_config;
2136
2137 MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
2138
2139 typedef struct
2140 {
2141     ma_format format;
2142     ma_uint32 channels;
2143     ma_uint32 sampleRate;
2144     ma_uint32 lpf1Count;
2145     ma_uint32 lpf2Count;
2146     ma_lpf1 lpf1[1];
2147     ma_lpf2 lpf2[MA_MAX_FILTER_ORDER/2];
2148 } ma_lpf;
2149
2150 MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF);
2151 MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF);
2152 MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2153 MA_API ma_uint32 ma_lpf_get_latency(const ma_lpf* pLPF);
2154
2155
2156 /**************************************************************************************************************************************************************
2157
2158 High-Pass Filtering
2159
2160 **************************************************************************************************************************************************************/
2161 typedef struct
2162 {
2163     ma_format format;
2164     ma_uint32 channels;
2165     ma_uint32 sampleRate;
2166     double cutoffFrequency;
2167     double q;
2168 } ma_hpf1_config, ma_hpf2_config;
2169
2170 MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency);
2171 MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q);
2172
2173 typedef struct
2174 {
2175     ma_format format;
2176     ma_uint32 channels;
2177     ma_biquad_coefficient a;
2178     ma_biquad_coefficient r1[MA_MAX_CHANNELS];
2179 } ma_hpf1;
2180
2181 MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF);
2182 MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF);
2183 MA_API ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2184 MA_API ma_uint32 ma_hpf1_get_latency(const ma_hpf1* pHPF);
2185
2186 typedef struct
2187 {
2188     ma_biquad bq;   /* The second order high-pass filter is implemented as a biquad filter. */
2189 } ma_hpf2;
2190
2191 MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF);
2192 MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF);
2193 MA_API ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2194 MA_API ma_uint32 ma_hpf2_get_latency(const ma_hpf2* pHPF);
2195
2196
2197 typedef struct
2198 {
2199     ma_format format;
2200     ma_uint32 channels;
2201     ma_uint32 sampleRate;
2202     double cutoffFrequency;
2203     ma_uint32 order;    /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
2204 } ma_hpf_config;
2205
2206 MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
2207
2208 typedef struct
2209 {
2210     ma_format format;
2211     ma_uint32 channels;
2212     ma_uint32 sampleRate;
2213     ma_uint32 hpf1Count;
2214     ma_uint32 hpf2Count;
2215     ma_hpf1 hpf1[1];
2216     ma_hpf2 hpf2[MA_MAX_FILTER_ORDER/2];
2217 } ma_hpf;
2218
2219 MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF);
2220 MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF);
2221 MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2222 MA_API ma_uint32 ma_hpf_get_latency(const ma_hpf* pHPF);
2223
2224
2225 /**************************************************************************************************************************************************************
2226
2227 Band-Pass Filtering
2228
2229 **************************************************************************************************************************************************************/
2230 typedef struct
2231 {
2232     ma_format format;
2233     ma_uint32 channels;
2234     ma_uint32 sampleRate;
2235     double cutoffFrequency;
2236     double q;
2237 } ma_bpf2_config;
2238
2239 MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q);
2240
2241 typedef struct
2242 {
2243     ma_biquad bq;   /* The second order band-pass filter is implemented as a biquad filter. */
2244 } ma_bpf2;
2245
2246 MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF);
2247 MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF);
2248 MA_API ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2249 MA_API ma_uint32 ma_bpf2_get_latency(const ma_bpf2* pBPF);
2250
2251
2252 typedef struct
2253 {
2254     ma_format format;
2255     ma_uint32 channels;
2256     ma_uint32 sampleRate;
2257     double cutoffFrequency;
2258     ma_uint32 order;    /* If set to 0, will be treated as a passthrough (no filtering will be applied). */
2259 } ma_bpf_config;
2260
2261 MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order);
2262
2263 typedef struct
2264 {
2265     ma_format format;
2266     ma_uint32 channels;
2267     ma_uint32 bpf2Count;
2268     ma_bpf2 bpf2[MA_MAX_FILTER_ORDER/2];
2269 } ma_bpf;
2270
2271 MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF);
2272 MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF);
2273 MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2274 MA_API ma_uint32 ma_bpf_get_latency(const ma_bpf* pBPF);
2275
2276
2277 /**************************************************************************************************************************************************************
2278
2279 Notching Filter
2280
2281 **************************************************************************************************************************************************************/
2282 typedef struct
2283 {
2284     ma_format format;
2285     ma_uint32 channels;
2286     ma_uint32 sampleRate;
2287     double q;
2288     double frequency;
2289 } ma_notch2_config;
2290
2291 MA_API ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency);
2292
2293 typedef struct
2294 {
2295     ma_biquad bq;
2296 } ma_notch2;
2297
2298 MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter);
2299 MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter);
2300 MA_API ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2301 MA_API ma_uint32 ma_notch2_get_latency(const ma_notch2* pFilter);
2302
2303
2304 /**************************************************************************************************************************************************************
2305
2306 Peaking EQ Filter
2307
2308 **************************************************************************************************************************************************************/
2309 typedef struct
2310 {
2311     ma_format format;
2312     ma_uint32 channels;
2313     ma_uint32 sampleRate;
2314     double gainDB;
2315     double q;
2316     double frequency;
2317 } ma_peak2_config;
2318
2319 MA_API ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency);
2320
2321 typedef struct
2322 {
2323     ma_biquad bq;
2324 } ma_peak2;
2325
2326 MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter);
2327 MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter);
2328 MA_API ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2329 MA_API ma_uint32 ma_peak2_get_latency(const ma_peak2* pFilter);
2330
2331
2332 /**************************************************************************************************************************************************************
2333
2334 Low Shelf Filter
2335
2336 **************************************************************************************************************************************************************/
2337 typedef struct
2338 {
2339     ma_format format;
2340     ma_uint32 channels;
2341     ma_uint32 sampleRate;
2342     double gainDB;
2343     double shelfSlope;
2344     double frequency;
2345 } ma_loshelf2_config;
2346
2347 MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency);
2348
2349 typedef struct
2350 {
2351     ma_biquad bq;
2352 } ma_loshelf2;
2353
2354 MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter);
2355 MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter);
2356 MA_API ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2357 MA_API ma_uint32 ma_loshelf2_get_latency(const ma_loshelf2* pFilter);
2358
2359
2360 /**************************************************************************************************************************************************************
2361
2362 High Shelf Filter
2363
2364 **************************************************************************************************************************************************************/
2365 typedef struct
2366 {
2367     ma_format format;
2368     ma_uint32 channels;
2369     ma_uint32 sampleRate;
2370     double gainDB;
2371     double shelfSlope;
2372     double frequency;
2373 } ma_hishelf2_config;
2374
2375 MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency);
2376
2377 typedef struct
2378 {
2379     ma_biquad bq;
2380 } ma_hishelf2;
2381
2382 MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter);
2383 MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter);
2384 MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2385 MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter);
2386
2387
2388
2389 /************************************************************************************************************************************************************
2390 *************************************************************************************************************************************************************
2391
2392 DATA CONVERSION
2393 ===============
2394
2395 This section contains the APIs for data conversion. You will find everything here for channel mapping, sample format conversion, resampling, etc.
2396
2397 *************************************************************************************************************************************************************
2398 ************************************************************************************************************************************************************/
2399
2400 /**************************************************************************************************************************************************************
2401
2402 Resampling
2403
2404 **************************************************************************************************************************************************************/
2405 typedef struct
2406 {
2407     ma_format format;
2408     ma_uint32 channels;
2409     ma_uint32 sampleRateIn;
2410     ma_uint32 sampleRateOut;
2411     ma_uint32 lpfOrder;         /* The low-pass filter order. Setting this to 0 will disable low-pass filtering. */
2412     double    lpfNyquistFactor; /* 0..1. Defaults to 1. 1 = Half the sampling frequency (Nyquist Frequency), 0.5 = Quarter the sampling frequency (half Nyquest Frequency), etc. */
2413 } ma_linear_resampler_config;
2414
2415 MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2416
2417 typedef struct
2418 {
2419     ma_linear_resampler_config config;
2420     ma_uint32 inAdvanceInt;
2421     ma_uint32 inAdvanceFrac;
2422     ma_uint32 inTimeInt;
2423     ma_uint32 inTimeFrac;
2424     union
2425     {
2426         float    f32[MA_MAX_CHANNELS];
2427         ma_int16 s16[MA_MAX_CHANNELS];
2428     } x0; /* The previous input frame. */
2429     union
2430     {
2431         float    f32[MA_MAX_CHANNELS];
2432         ma_int16 s16[MA_MAX_CHANNELS];
2433     } x1; /* The next input frame. */
2434     ma_lpf lpf;
2435 } ma_linear_resampler;
2436
2437 MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler);
2438 MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler);
2439 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);
2440 MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2441 MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut);
2442 MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount);
2443 MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount);
2444 MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler);
2445 MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler);
2446
2447 typedef enum
2448 {
2449     ma_resample_algorithm_linear = 0,   /* Fastest, lowest quality. Optional low-pass filtering. Default. */
2450     ma_resample_algorithm_speex
2451 } ma_resample_algorithm;
2452
2453 typedef struct
2454 {
2455     ma_format format;   /* Must be either ma_format_f32 or ma_format_s16. */
2456     ma_uint32 channels;
2457     ma_uint32 sampleRateIn;
2458     ma_uint32 sampleRateOut;
2459     ma_resample_algorithm algorithm;
2460     struct
2461     {
2462         ma_uint32 lpfOrder;
2463         double lpfNyquistFactor;
2464     } linear;
2465     struct
2466     {
2467         int quality;    /* 0 to 10. Defaults to 3. */
2468     } speex;
2469 } ma_resampler_config;
2470
2471 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);
2472
2473 typedef struct
2474 {
2475     ma_resampler_config config;
2476     union
2477     {
2478         ma_linear_resampler linear;
2479         struct
2480         {
2481             void* pSpeexResamplerState;   /* SpeexResamplerState* */
2482         } speex;
2483     } state;
2484 } ma_resampler;
2485
2486 /*
2487 Initializes a new resampler object from a config.
2488 */
2489 MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler);
2490
2491 /*
2492 Uninitializes a resampler.
2493 */
2494 MA_API void ma_resampler_uninit(ma_resampler* pResampler);
2495
2496 /*
2497 Converts the given input data.
2498
2499 Both the input and output frames must be in the format specified in the config when the resampler was initilized.
2500
2501 On input, [pFrameCountOut] contains the number of output frames to process. On output it contains the number of output frames that
2502 were actually processed, which may be less than the requested amount which will happen if there's not enough input data. You can use
2503 ma_resampler_get_expected_output_frame_count() to know how many output frames will be processed for a given number of input frames.
2504
2505 On input, [pFrameCountIn] contains the number of input frames contained in [pFramesIn]. On output it contains the number of whole
2506 input frames that were actually processed. You can use ma_resampler_get_required_input_frame_count() to know how many input frames
2507 you should provide for a given number of output frames. [pFramesIn] can be NULL, in which case zeroes will be used instead.
2508
2509 If [pFramesOut] is NULL, a seek is performed. In this case, if [pFrameCountOut] is not NULL it will seek by the specified number of
2510 output frames. Otherwise, if [pFramesCountOut] is NULL and [pFrameCountIn] is not NULL, it will seek by the specified number of input
2511 frames. When seeking, [pFramesIn] is allowed to NULL, in which case the internal timing state will be updated, but no input will be
2512 processed. In this case, any internal filter state will be updated as if zeroes were passed in.
2513
2514 It is an error for [pFramesOut] to be non-NULL and [pFrameCountOut] to be NULL.
2515
2516 It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
2517 */
2518 MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut);
2519
2520
2521 /*
2522 Sets the input and output sample sample rate.
2523 */
2524 MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2525
2526 /*
2527 Sets the input and output sample rate as a ratio.
2528
2529 The ration is in/out.
2530 */
2531 MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio);
2532
2533
2534 /*
2535 Calculates the number of whole input frames that would need to be read from the client in order to output the specified
2536 number of output frames.
2537
2538 The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
2539 read from the input buffer in order to output the specified number of output frames.
2540 */
2541 MA_API ma_uint64 ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount);
2542
2543 /*
2544 Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
2545 input frames.
2546 */
2547 MA_API ma_uint64 ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount);
2548
2549
2550 /*
2551 Retrieves the latency introduced by the resampler in input frames.
2552 */
2553 MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler);
2554
2555 /*
2556 Retrieves the latency introduced by the resampler in output frames.
2557 */
2558 MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler);
2559
2560
2561
2562 /**************************************************************************************************************************************************************
2563
2564 Channel Conversion
2565
2566 **************************************************************************************************************************************************************/
2567 typedef struct
2568 {
2569     ma_format format;
2570     ma_uint32 channelsIn;
2571     ma_uint32 channelsOut;
2572     ma_channel channelMapIn[MA_MAX_CHANNELS];
2573     ma_channel channelMapOut[MA_MAX_CHANNELS];
2574     ma_channel_mix_mode mixingMode;
2575     float weights[MA_MAX_CHANNELS][MA_MAX_CHANNELS];  /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
2576 } ma_channel_converter_config;
2577
2578 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);
2579
2580 typedef struct
2581 {
2582     ma_format format;
2583     ma_uint32 channelsIn;
2584     ma_uint32 channelsOut;
2585     ma_channel channelMapIn[MA_MAX_CHANNELS];
2586     ma_channel channelMapOut[MA_MAX_CHANNELS];
2587     ma_channel_mix_mode mixingMode;
2588     union
2589     {
2590         float    f32[MA_MAX_CHANNELS][MA_MAX_CHANNELS];
2591         ma_int32 s16[MA_MAX_CHANNELS][MA_MAX_CHANNELS];
2592     } weights;
2593     ma_bool8 isPassthrough;
2594     ma_bool8 isSimpleShuffle;
2595     ma_bool8 isSimpleMonoExpansion;
2596     ma_bool8 isStereoToMono;
2597     ma_uint8 shuffleTable[MA_MAX_CHANNELS];
2598 } ma_channel_converter;
2599
2600 MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, ma_channel_converter* pConverter);
2601 MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter);
2602 MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount);
2603
2604
2605 /**************************************************************************************************************************************************************
2606
2607 Data Conversion
2608
2609 **************************************************************************************************************************************************************/
2610 typedef struct
2611 {
2612     ma_format formatIn;
2613     ma_format formatOut;
2614     ma_uint32 channelsIn;
2615     ma_uint32 channelsOut;
2616     ma_uint32 sampleRateIn;
2617     ma_uint32 sampleRateOut;
2618     ma_channel channelMapIn[MA_MAX_CHANNELS];
2619     ma_channel channelMapOut[MA_MAX_CHANNELS];
2620     ma_dither_mode ditherMode;
2621     ma_channel_mix_mode channelMixMode;
2622     float channelWeights[MA_MAX_CHANNELS][MA_MAX_CHANNELS];  /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */
2623     struct
2624     {
2625         ma_resample_algorithm algorithm;
2626         ma_bool32 allowDynamicSampleRate;
2627         struct
2628         {
2629             ma_uint32 lpfOrder;
2630             double lpfNyquistFactor;
2631         } linear;
2632         struct
2633         {
2634             int quality;
2635         } speex;
2636     } resampling;
2637 } ma_data_converter_config;
2638
2639 MA_API ma_data_converter_config ma_data_converter_config_init_default(void);
2640 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);
2641
2642 typedef struct
2643 {
2644     ma_data_converter_config config;
2645     ma_channel_converter channelConverter;
2646     ma_resampler resampler;
2647     ma_bool8 hasPreFormatConversion;
2648     ma_bool8 hasPostFormatConversion;
2649     ma_bool8 hasChannelConverter;
2650     ma_bool8 hasResampler;
2651     ma_bool8 isPassthrough;
2652 } ma_data_converter;
2653
2654 MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, ma_data_converter* pConverter);
2655 MA_API void ma_data_converter_uninit(ma_data_converter* pConverter);
2656 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);
2657 MA_API ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut);
2658 MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut);
2659 MA_API ma_uint64 ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount);
2660 MA_API ma_uint64 ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount);
2661 MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter);
2662 MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* pConverter);
2663
2664
2665 /************************************************************************************************************************************************************
2666
2667 Format Conversion
2668
2669 ************************************************************************************************************************************************************/
2670 MA_API void ma_pcm_u8_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2671 MA_API void ma_pcm_u8_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2672 MA_API void ma_pcm_u8_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2673 MA_API void ma_pcm_u8_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2674 MA_API void ma_pcm_s16_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2675 MA_API void ma_pcm_s16_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2676 MA_API void ma_pcm_s16_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2677 MA_API void ma_pcm_s16_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2678 MA_API void ma_pcm_s24_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2679 MA_API void ma_pcm_s24_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2680 MA_API void ma_pcm_s24_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2681 MA_API void ma_pcm_s24_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2682 MA_API void ma_pcm_s32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2683 MA_API void ma_pcm_s32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2684 MA_API void ma_pcm_s32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2685 MA_API void ma_pcm_s32_to_f32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2686 MA_API void ma_pcm_f32_to_u8(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2687 MA_API void ma_pcm_f32_to_s16(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2688 MA_API void ma_pcm_f32_to_s24(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2689 MA_API void ma_pcm_f32_to_s32(void* pOut, const void* pIn, ma_uint64 count, ma_dither_mode ditherMode);
2690 MA_API void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode);
2691 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);
2692
2693 /*
2694 Deinterleaves an interleaved buffer.
2695 */
2696 MA_API void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames);
2697
2698 /*
2699 Interleaves a group of deinterleaved buffers.
2700 */
2701 MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames);
2702
2703
2704 /************************************************************************************************************************************************************
2705
2706 Channel Maps
2707
2708 ************************************************************************************************************************************************************/
2709
2710 /*
2711 Initializes a blank channel map.
2712
2713 When a blank channel map is specified anywhere it indicates that the native channel map should be used.
2714 */
2715 MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap);
2716
2717 /*
2718 Helper for retrieving a standard channel map.
2719
2720 The output channel map buffer must have a capacity of at least `channels`.
2721 */
2722 MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap);
2723
2724 /*
2725 Copies a channel map.
2726
2727 Both input and output channel map buffers must have a capacity of at at least `channels`.
2728 */
2729 MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels);
2730
2731 /*
2732 Copies a channel map if one is specified, otherwise copies the default channel map.
2733
2734 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`.
2735 */
2736 MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels);
2737
2738
2739 /*
2740 Determines whether or not a channel map is valid.
2741
2742 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
2743 is usually treated as a passthrough.
2744
2745 Invalid channel maps:
2746   - A channel map with no channels
2747   - A channel map with more than one channel and a mono channel
2748
2749 The channel map buffer must have a capacity of at least `channels`.
2750 */
2751 MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap);
2752
2753 /*
2754 Helper for comparing two channel maps for equality.
2755
2756 This assumes the channel count is the same between the two.
2757
2758 Both channels map buffers must have a capacity of at least `channels`.
2759 */
2760 MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB);
2761
2762 /*
2763 Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE).
2764
2765 The channel map buffer must have a capacity of at least `channels`.
2766 */
2767 MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap);
2768
2769 /*
2770 Helper for determining whether or not a channel is present in the given channel map.
2771
2772 The channel map buffer must have a capacity of at least `channels`.
2773 */
2774 MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition);
2775
2776
2777 /************************************************************************************************************************************************************
2778
2779 Conversion Helpers
2780
2781 ************************************************************************************************************************************************************/
2782
2783 /*
2784 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
2785 determine the required size of the output buffer. frameCountOut should be set to the capacity of pOut. If pOut is NULL, frameCountOut is
2786 ignored.
2787
2788 A return value of 0 indicates an error.
2789
2790 This function is useful for one-off bulk conversions, but if you're streaming data you should use the ma_data_converter APIs instead.
2791 */
2792 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);
2793 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);
2794
2795
2796 /************************************************************************************************************************************************************
2797
2798 Ring Buffer
2799
2800 ************************************************************************************************************************************************************/
2801 typedef struct
2802 {
2803     void* pBuffer;
2804     ma_uint32 subbufferSizeInBytes;
2805     ma_uint32 subbufferCount;
2806     ma_uint32 subbufferStrideInBytes;
2807     MA_ATOMIC ma_uint32 encodedReadOffset;  /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */
2808     MA_ATOMIC ma_uint32 encodedWriteOffset; /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */
2809     ma_bool8 ownsBuffer;                    /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */
2810     ma_bool8 clearOnWriteAcquire;           /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */
2811     ma_allocation_callbacks allocationCallbacks;
2812 } ma_rb;
2813
2814 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);
2815 MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB);
2816 MA_API void ma_rb_uninit(ma_rb* pRB);
2817 MA_API void ma_rb_reset(ma_rb* pRB);
2818 MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
2819 MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut);
2820 MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut);
2821 MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut);
2822 MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes);
2823 MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes);
2824 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. */
2825 MA_API ma_uint32 ma_rb_available_read(ma_rb* pRB);
2826 MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB);
2827 MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB);
2828 MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB);
2829 MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex);
2830 MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer);
2831
2832
2833 typedef struct
2834 {
2835     ma_rb rb;
2836     ma_format format;
2837     ma_uint32 channels;
2838 } ma_pcm_rb;
2839
2840 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);
2841 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);
2842 MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB);
2843 MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB);
2844 MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
2845 MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut);
2846 MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut);
2847 MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut);
2848 MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
2849 MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames);
2850 MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB); /* Return value is in frames. */
2851 MA_API ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb* pRB);
2852 MA_API ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb* pRB);
2853 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB);
2854 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB);
2855 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex);
2856 MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer);
2857
2858
2859 /*
2860 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
2861 capture device writes to it, and then a playback device reads from it.
2862
2863 At the moment this is just a simple naive implementation, but in the future I want to implement some dynamic resampling to seamlessly
2864 handle desyncs. Note that the API is work in progress and may change at any time in any version.
2865
2866 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
2867 in frames. The internal sample rate of the capture device is also needed in order to calculate the size.
2868 */
2869 typedef struct
2870 {
2871     ma_pcm_rb rb;
2872 } ma_duplex_rb;
2873
2874 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);
2875 MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB);
2876
2877
2878 /************************************************************************************************************************************************************
2879
2880 Miscellaneous Helpers
2881
2882 ************************************************************************************************************************************************************/
2883 /*
2884 Retrieves a human readable description of the given result code.
2885 */
2886 MA_API const char* ma_result_description(ma_result result);
2887
2888 /*
2889 malloc(). Calls MA_MALLOC().
2890 */
2891 MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
2892
2893 /*
2894 realloc(). Calls MA_REALLOC().
2895 */
2896 MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks);
2897
2898 /*
2899 free(). Calls MA_FREE().
2900 */
2901 MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
2902
2903 /*
2904 Performs an aligned malloc, with the assumption that the alignment is a power of 2.
2905 */
2906 MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks);
2907
2908 /*
2909 Free's an aligned malloc'd buffer.
2910 */
2911 MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks);
2912
2913 /*
2914 Retrieves a friendly name for a format.
2915 */
2916 MA_API const char* ma_get_format_name(ma_format format);
2917
2918 /*
2919 Blends two frames in floating point format.
2920 */
2921 MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels);
2922
2923 /*
2924 Retrieves the size of a sample in bytes for the given format.
2925
2926 This API is efficient and is implemented using a lookup table.
2927
2928 Thread Safety: SAFE
2929   This API is pure.
2930 */
2931 MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format);
2932 static MA_INLINE ma_uint32 ma_get_bytes_per_frame(ma_format format, ma_uint32 channels) { return ma_get_bytes_per_sample(format) * channels; }
2933
2934 /*
2935 Converts a log level to a string.
2936 */
2937 MA_API const char* ma_log_level_to_string(ma_uint32 logLevel);
2938
2939
2940
2941 /************************************************************************************************************************************************************
2942 *************************************************************************************************************************************************************
2943
2944 DEVICE I/O
2945 ==========
2946
2947 This section contains the APIs for device playback and capture. Here is where you'll find ma_device_init(), etc.
2948
2949 *************************************************************************************************************************************************************
2950 ************************************************************************************************************************************************************/
2951 #ifndef MA_NO_DEVICE_IO
2952 /* Some backends are only supported on certain platforms. */
2953 #if defined(MA_WIN32)
2954     #define MA_SUPPORT_WASAPI
2955     #if defined(MA_WIN32_DESKTOP)  /* DirectSound and WinMM backends are only supported on desktops. */
2956         #define MA_SUPPORT_DSOUND
2957         #define MA_SUPPORT_WINMM
2958         #define MA_SUPPORT_JACK    /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */
2959     #endif
2960 #endif
2961 #if defined(MA_UNIX)
2962     #if defined(MA_LINUX)
2963         #if !defined(MA_ANDROID)   /* ALSA is not supported on Android. */
2964             #define MA_SUPPORT_ALSA
2965         #endif
2966     #endif
2967     #if !defined(MA_BSD) && !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN)
2968         #define MA_SUPPORT_PULSEAUDIO
2969         #define MA_SUPPORT_JACK
2970     #endif
2971     #if defined(MA_ANDROID)
2972         #define MA_SUPPORT_AAUDIO
2973         #define MA_SUPPORT_OPENSL
2974     #endif
2975     #if defined(__OpenBSD__)        /* <-- Change this to "#if defined(MA_BSD)" to enable sndio on all BSD flavors. */
2976         #define MA_SUPPORT_SNDIO    /* sndio is only supported on OpenBSD for now. May be expanded later if there's demand. */
2977     #endif
2978     #if defined(__NetBSD__) || defined(__OpenBSD__)
2979         #define MA_SUPPORT_AUDIO4   /* Only support audio(4) on platforms with known support. */
2980     #endif
2981     #if defined(__FreeBSD__) || defined(__DragonFly__)
2982         #define MA_SUPPORT_OSS      /* Only support OSS on specific platforms with known support. */
2983     #endif
2984 #endif
2985 #if defined(MA_APPLE)
2986     #define MA_SUPPORT_COREAUDIO
2987 #endif
2988 #if defined(MA_EMSCRIPTEN)
2989     #define MA_SUPPORT_WEBAUDIO
2990 #endif
2991
2992 /* All platforms should support custom backends. */
2993 #define MA_SUPPORT_CUSTOM
2994
2995 /* Explicitly disable the Null backend for Emscripten because it uses a background thread which is not properly supported right now. */
2996 #if !defined(MA_EMSCRIPTEN)
2997 #define MA_SUPPORT_NULL
2998 #endif
2999
3000
3001 #if defined(MA_SUPPORT_WASAPI) && !defined(MA_NO_WASAPI) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WASAPI))
3002     #define MA_HAS_WASAPI
3003 #endif
3004 #if defined(MA_SUPPORT_DSOUND) && !defined(MA_NO_DSOUND) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_DSOUND))
3005     #define MA_HAS_DSOUND
3006 #endif
3007 #if defined(MA_SUPPORT_WINMM) && !defined(MA_NO_WINMM) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WINMM))
3008     #define MA_HAS_WINMM
3009 #endif
3010 #if defined(MA_SUPPORT_ALSA) && !defined(MA_NO_ALSA) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_ALSA))
3011     #define MA_HAS_ALSA
3012 #endif
3013 #if defined(MA_SUPPORT_PULSEAUDIO) && !defined(MA_NO_PULSEAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_PULSEAUDIO))
3014     #define MA_HAS_PULSEAUDIO
3015 #endif
3016 #if defined(MA_SUPPORT_JACK) && !defined(MA_NO_JACK) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_JACK))
3017     #define MA_HAS_JACK
3018 #endif
3019 #if defined(MA_SUPPORT_COREAUDIO) && !defined(MA_NO_COREAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_COREAUDIO))
3020     #define MA_HAS_COREAUDIO
3021 #endif
3022 #if defined(MA_SUPPORT_SNDIO) && !defined(MA_NO_SNDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_SNDIO))
3023     #define MA_HAS_SNDIO
3024 #endif
3025 #if defined(MA_SUPPORT_AUDIO4) && !defined(MA_NO_AUDIO4) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_AUDIO4))
3026     #define MA_HAS_AUDIO4
3027 #endif
3028 #if defined(MA_SUPPORT_OSS) && !defined(MA_NO_OSS) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_OSS))
3029     #define MA_HAS_OSS
3030 #endif
3031 #if defined(MA_SUPPORT_AAUDIO) && !defined(MA_NO_AAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_AAUDIO))
3032     #define MA_HAS_AAUDIO
3033 #endif
3034 #if defined(MA_SUPPORT_OPENSL) && !defined(MA_NO_OPENSL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_OPENSL))
3035     #define MA_HAS_OPENSL
3036 #endif
3037 #if defined(MA_SUPPORT_WEBAUDIO) && !defined(MA_NO_WEBAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_WEBAUDIO))
3038     #define MA_HAS_WEBAUDIO
3039 #endif
3040 #if defined(MA_SUPPORT_CUSTOM) && !defined(MA_NO_CUSTOM) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_CUSTOM))
3041     #define MA_HAS_CUSTOM
3042 #endif
3043 #if defined(MA_SUPPORT_NULL) && !defined(MA_NO_NULL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_NULL))
3044     #define MA_HAS_NULL
3045 #endif
3046
3047 #define MA_STATE_UNINITIALIZED     0
3048 #define MA_STATE_STOPPED           1   /* The device's default state after initialization. */
3049 #define MA_STATE_STARTED           2   /* The device is started and is requesting and/or delivering audio data. */
3050 #define MA_STATE_STARTING          3   /* Transitioning from a stopped state to started. */
3051 #define MA_STATE_STOPPING          4   /* Transitioning from a started state to stopped. */
3052
3053 #ifdef MA_SUPPORT_WASAPI
3054 /* We need a IMMNotificationClient object for WASAPI. */
3055 typedef struct
3056 {
3057     void* lpVtbl;
3058     ma_uint32 counter;
3059     ma_device* pDevice;
3060 } ma_IMMNotificationClient;
3061 #endif
3062
3063 /* Backend enums must be in priority order. */
3064 typedef enum
3065 {
3066     ma_backend_wasapi,
3067     ma_backend_dsound,
3068     ma_backend_winmm,
3069     ma_backend_coreaudio,
3070     ma_backend_sndio,
3071     ma_backend_audio4,
3072     ma_backend_oss,
3073     ma_backend_pulseaudio,
3074     ma_backend_alsa,
3075     ma_backend_jack,
3076     ma_backend_aaudio,
3077     ma_backend_opensl,
3078     ma_backend_webaudio,
3079     ma_backend_custom,  /* <-- Custom backend, with callbacks defined by the context config. */
3080     ma_backend_null     /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
3081 } ma_backend;
3082
3083 #define MA_BACKEND_COUNT (ma_backend_null+1)
3084
3085
3086 /*
3087 The callback for processing audio data from the device.
3088
3089 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
3090 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
3091 callback will be fired with a consistent frame count.
3092
3093
3094 Parameters
3095 ----------
3096 pDevice (in)
3097     A pointer to the relevant device.
3098
3099 pOutput (out)
3100     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
3101     full-duplex device and null for a capture and loopback device.
3102
3103 pInput (in)
3104     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
3105     playback device.
3106
3107 frameCount (in)
3108     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
3109     `periodSizeInFrames` and `periodSizeInMilliseconds` members of the device config are just hints, and are not necessarily exactly what you'll get. You must
3110     not assume this will always be the same value each time the callback is fired.
3111
3112
3113 Remarks
3114 -------
3115 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
3116 callback. The following APIs cannot be called from inside the callback:
3117
3118     ma_device_init()
3119     ma_device_init_ex()
3120     ma_device_uninit()
3121     ma_device_start()
3122     ma_device_stop()
3123
3124 The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread.
3125 */
3126 typedef void (* ma_device_callback_proc)(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
3127
3128 /*
3129 The callback for when the device has been stopped.
3130
3131 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
3132 such as being unplugged or an internal error occuring.
3133
3134
3135 Parameters
3136 ----------
3137 pDevice (in)
3138     A pointer to the device that has just stopped.
3139
3140
3141 Remarks
3142 -------
3143 Do not restart or uninitialize the device from the callback.
3144 */
3145 typedef void (* ma_stop_proc)(ma_device* pDevice);
3146
3147 /*
3148 The callback for handling log messages.
3149
3150
3151 Parameters
3152 ----------
3153 pContext (in)
3154     A pointer to the context the log message originated from.
3155
3156 pDevice (in)
3157     A pointer to the device the log message originate from, if any. This can be null, in which case the message came from the context.
3158
3159 logLevel (in)
3160     The log level. This can be one of the following:
3161
3162     +----------------------+
3163     | Log Level            |
3164     +----------------------+
3165     | MA_LOG_LEVEL_VERBOSE |
3166     | MA_LOG_LEVEL_INFO    |
3167     | MA_LOG_LEVEL_WARNING |
3168     | MA_LOG_LEVEL_ERROR   |
3169     +----------------------+
3170
3171 message (in)
3172     The log message.
3173
3174
3175 Remarks
3176 -------
3177 Do not modify the state of the device from inside the callback.
3178 */
3179 typedef void (* ma_log_proc)(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message);
3180
3181 typedef enum
3182 {
3183     ma_device_type_playback = 1,
3184     ma_device_type_capture  = 2,
3185     ma_device_type_duplex   = ma_device_type_playback | ma_device_type_capture, /* 3 */
3186     ma_device_type_loopback = 4
3187 } ma_device_type;
3188
3189 typedef enum
3190 {
3191     ma_share_mode_shared = 0,
3192     ma_share_mode_exclusive
3193 } ma_share_mode;
3194
3195 /* iOS/tvOS/watchOS session categories. */
3196 typedef enum
3197 {
3198     ma_ios_session_category_default = 0,        /* AVAudioSessionCategoryPlayAndRecord with AVAudioSessionCategoryOptionDefaultToSpeaker. */
3199     ma_ios_session_category_none,               /* Leave the session category unchanged. */
3200     ma_ios_session_category_ambient,            /* AVAudioSessionCategoryAmbient */
3201     ma_ios_session_category_solo_ambient,       /* AVAudioSessionCategorySoloAmbient */
3202     ma_ios_session_category_playback,           /* AVAudioSessionCategoryPlayback */
3203     ma_ios_session_category_record,             /* AVAudioSessionCategoryRecord */
3204     ma_ios_session_category_play_and_record,    /* AVAudioSessionCategoryPlayAndRecord */
3205     ma_ios_session_category_multi_route         /* AVAudioSessionCategoryMultiRoute */
3206 } ma_ios_session_category;
3207
3208 /* iOS/tvOS/watchOS session category options */
3209 typedef enum
3210 {
3211     ma_ios_session_category_option_mix_with_others                            = 0x01,   /* AVAudioSessionCategoryOptionMixWithOthers */
3212     ma_ios_session_category_option_duck_others                                = 0x02,   /* AVAudioSessionCategoryOptionDuckOthers */
3213     ma_ios_session_category_option_allow_bluetooth                            = 0x04,   /* AVAudioSessionCategoryOptionAllowBluetooth */
3214     ma_ios_session_category_option_default_to_speaker                         = 0x08,   /* AVAudioSessionCategoryOptionDefaultToSpeaker */
3215     ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others = 0x11,   /* AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers */
3216     ma_ios_session_category_option_allow_bluetooth_a2dp                       = 0x20,   /* AVAudioSessionCategoryOptionAllowBluetoothA2DP */
3217     ma_ios_session_category_option_allow_air_play                             = 0x40,   /* AVAudioSessionCategoryOptionAllowAirPlay */
3218 } ma_ios_session_category_option;
3219
3220 /* OpenSL stream types. */
3221 typedef enum
3222 {
3223     ma_opensl_stream_type_default = 0,              /* Leaves the stream type unset. */
3224     ma_opensl_stream_type_voice,                    /* SL_ANDROID_STREAM_VOICE */
3225     ma_opensl_stream_type_system,                   /* SL_ANDROID_STREAM_SYSTEM */
3226     ma_opensl_stream_type_ring,                     /* SL_ANDROID_STREAM_RING */
3227     ma_opensl_stream_type_media,                    /* SL_ANDROID_STREAM_MEDIA */
3228     ma_opensl_stream_type_alarm,                    /* SL_ANDROID_STREAM_ALARM */
3229     ma_opensl_stream_type_notification              /* SL_ANDROID_STREAM_NOTIFICATION */
3230 } ma_opensl_stream_type;
3231
3232 /* OpenSL recording presets. */
3233 typedef enum
3234 {
3235     ma_opensl_recording_preset_default = 0,         /* Leaves the input preset unset. */
3236     ma_opensl_recording_preset_generic,             /* SL_ANDROID_RECORDING_PRESET_GENERIC */
3237     ma_opensl_recording_preset_camcorder,           /* SL_ANDROID_RECORDING_PRESET_CAMCORDER */
3238     ma_opensl_recording_preset_voice_recognition,   /* SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION */
3239     ma_opensl_recording_preset_voice_communication, /* SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION */
3240     ma_opensl_recording_preset_voice_unprocessed    /* SL_ANDROID_RECORDING_PRESET_UNPROCESSED */
3241 } ma_opensl_recording_preset;
3242
3243 /* AAudio usage types. */
3244 typedef enum
3245 {
3246     ma_aaudio_usage_default = 0,                    /* Leaves the usage type unset. */
3247     ma_aaudio_usage_announcement,                   /* AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT */
3248     ma_aaudio_usage_emergency,                      /* AAUDIO_SYSTEM_USAGE_EMERGENCY */
3249     ma_aaudio_usage_safety,                         /* AAUDIO_SYSTEM_USAGE_SAFETY */
3250     ma_aaudio_usage_vehicle_status,                 /* AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS */
3251     ma_aaudio_usage_alarm,                          /* AAUDIO_USAGE_ALARM */
3252     ma_aaudio_usage_assistance_accessibility,       /* AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY */
3253     ma_aaudio_usage_assistance_navigation_guidance, /* AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE */
3254     ma_aaudio_usage_assistance_sonification,        /* AAUDIO_USAGE_ASSISTANCE_SONIFICATION */
3255     ma_aaudio_usage_assitant,                       /* AAUDIO_USAGE_ASSISTANT */
3256     ma_aaudio_usage_game,                           /* AAUDIO_USAGE_GAME */
3257     ma_aaudio_usage_media,                          /* AAUDIO_USAGE_MEDIA */
3258     ma_aaudio_usage_notification,                   /* AAUDIO_USAGE_NOTIFICATION */
3259     ma_aaudio_usage_notification_event,             /* AAUDIO_USAGE_NOTIFICATION_EVENT */
3260     ma_aaudio_usage_notification_ringtone,          /* AAUDIO_USAGE_NOTIFICATION_RINGTONE */
3261     ma_aaudio_usage_voice_communication,            /* AAUDIO_USAGE_VOICE_COMMUNICATION */
3262     ma_aaudio_usage_voice_communication_signalling  /* AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING */
3263 } ma_aaudio_usage;
3264
3265 /* AAudio content types. */
3266 typedef enum
3267 {
3268     ma_aaudio_content_type_default = 0,             /* Leaves the content type unset. */
3269     ma_aaudio_content_type_movie,                   /* AAUDIO_CONTENT_TYPE_MOVIE */
3270     ma_aaudio_content_type_music,                   /* AAUDIO_CONTENT_TYPE_MUSIC */
3271     ma_aaudio_content_type_sonification,            /* AAUDIO_CONTENT_TYPE_SONIFICATION */
3272     ma_aaudio_content_type_speech                   /* AAUDIO_CONTENT_TYPE_SPEECH */
3273 } ma_aaudio_content_type;
3274
3275 /* AAudio input presets. */
3276 typedef enum
3277 {
3278     ma_aaudio_input_preset_default = 0,             /* Leaves the input preset unset. */
3279     ma_aaudio_input_preset_generic,                 /* AAUDIO_INPUT_PRESET_GENERIC */
3280     ma_aaudio_input_preset_camcorder,               /* AAUDIO_INPUT_PRESET_CAMCORDER */
3281     ma_aaudio_input_preset_unprocessed,             /* AAUDIO_INPUT_PRESET_UNPROCESSED */
3282     ma_aaudio_input_preset_voice_recognition,       /* AAUDIO_INPUT_PRESET_VOICE_RECOGNITION */
3283     ma_aaudio_input_preset_voice_communication,     /* AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION */
3284     ma_aaudio_input_preset_voice_performance        /* AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE */
3285 } ma_aaudio_input_preset;
3286
3287
3288 typedef union
3289 {
3290     ma_int64 counter;
3291     double counterD;
3292 } ma_timer;
3293
3294 typedef union
3295 {
3296     wchar_t wasapi[64];             /* WASAPI uses a wchar_t string for identification. */
3297     ma_uint8 dsound[16];            /* DirectSound uses a GUID for identification. */
3298     /*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. */
3299     char alsa[256];                 /* ALSA uses a name string for identification. */
3300     char pulse[256];                /* PulseAudio uses a name string for identification. */
3301     int jack;                       /* JACK always uses default devices. */
3302     char coreaudio[256];            /* Core Audio uses a string for identification. */
3303     char sndio[256];                /* "snd/0", etc. */
3304     char audio4[256];               /* "/dev/audio", etc. */
3305     char oss[64];                   /* "dev/dsp0", etc. "dev/dsp" for the default device. */
3306     ma_int32 aaudio;                /* AAudio uses a 32-bit integer for identification. */
3307     ma_uint32 opensl;               /* OpenSL|ES uses a 32-bit unsigned integer for identification. */
3308     char webaudio[32];              /* Web Audio always uses default devices for now, but if this changes it'll be a GUID. */
3309     union
3310     {
3311         int i;
3312         char s[256];
3313         void* p;
3314     } custom;                       /* The custom backend could be anything. Give them a few options. */
3315     int nullbackend;                /* The null backend uses an integer for device IDs. */
3316 } ma_device_id;
3317
3318
3319 typedef struct ma_context_config    ma_context_config;
3320 typedef struct ma_device_config     ma_device_config;
3321 typedef struct ma_backend_callbacks ma_backend_callbacks;
3322
3323 #define MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE (1U << 1)    /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
3324
3325 typedef struct
3326 {
3327     /* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
3328     ma_device_id id;
3329     char name[256];
3330     ma_bool32 isDefault;
3331
3332     /*
3333     Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize
3334     a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion
3335     pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided
3336     here mainly for informational purposes or in the rare case that someone might find it useful.
3337
3338     These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices().
3339     */
3340     ma_uint32 formatCount;
3341     ma_format formats[ma_format_count];
3342     ma_uint32 minChannels;
3343     ma_uint32 maxChannels;
3344     ma_uint32 minSampleRate;
3345     ma_uint32 maxSampleRate;
3346
3347
3348     /* Experimental. Don't use these right now. */
3349     ma_uint32 nativeDataFormatCount;
3350     struct
3351     {
3352         ma_format format;       /* Sample format. If set to ma_format_unknown, all sample formats are supported. */
3353         ma_uint32 channels;     /* If set to 0, all channels are supported. */
3354         ma_uint32 sampleRate;   /* If set to 0, all sample rates are supported. */
3355         ma_uint32 flags;        /* A combination of MA_DATA_FORMAT_FLAG_* flags. */
3356     } 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. */
3357 } ma_device_info;
3358
3359 struct ma_device_config
3360 {
3361     ma_device_type deviceType;
3362     ma_uint32 sampleRate;
3363     ma_uint32 periodSizeInFrames;
3364     ma_uint32 periodSizeInMilliseconds;
3365     ma_uint32 periods;
3366     ma_performance_profile performanceProfile;
3367     ma_bool8 noPreZeroedOutputBuffer;   /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
3368     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. */
3369     ma_device_callback_proc dataCallback;
3370     ma_stop_proc stopCallback;
3371     void* pUserData;
3372     struct
3373     {
3374         ma_resample_algorithm algorithm;
3375         struct
3376         {
3377             ma_uint32 lpfOrder;
3378         } linear;
3379         struct
3380         {
3381             int quality;
3382         } speex;
3383     } resampling;
3384     struct
3385     {
3386         const ma_device_id* pDeviceID;
3387         ma_format format;
3388         ma_uint32 channels;
3389         ma_channel channelMap[MA_MAX_CHANNELS];
3390         ma_channel_mix_mode channelMixMode;
3391         ma_share_mode shareMode;
3392     } playback;
3393     struct
3394     {
3395         const ma_device_id* pDeviceID;
3396         ma_format format;
3397         ma_uint32 channels;
3398         ma_channel channelMap[MA_MAX_CHANNELS];
3399         ma_channel_mix_mode channelMixMode;
3400         ma_share_mode shareMode;
3401     } capture;
3402
3403     struct
3404     {
3405         ma_bool8 noAutoConvertSRC;     /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
3406         ma_bool8 noDefaultQualitySRC;  /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
3407         ma_bool8 noAutoStreamRouting;  /* Disables automatic stream routing. */
3408         ma_bool8 noHardwareOffloading; /* Disables WASAPI's hardware offloading feature. */
3409     } wasapi;
3410     struct
3411     {
3412         ma_bool32 noMMap;           /* Disables MMap mode. */
3413         ma_bool32 noAutoFormat;     /* Opens the ALSA device with SND_PCM_NO_AUTO_FORMAT. */
3414         ma_bool32 noAutoChannels;   /* Opens the ALSA device with SND_PCM_NO_AUTO_CHANNELS. */
3415         ma_bool32 noAutoResample;   /* Opens the ALSA device with SND_PCM_NO_AUTO_RESAMPLE. */
3416     } alsa;
3417     struct
3418     {
3419         const char* pStreamNamePlayback;
3420         const char* pStreamNameCapture;
3421     } pulse;
3422     struct
3423     {
3424         ma_bool32 allowNominalSampleRateChange; /* Desktop only. When enabled, allows changing of the sample rate at the operating system level. */
3425     } coreaudio;
3426     struct
3427     {
3428         ma_opensl_stream_type streamType;
3429         ma_opensl_recording_preset recordingPreset;
3430     } opensl;
3431     struct
3432     {
3433         ma_aaudio_usage usage;
3434         ma_aaudio_content_type contentType;
3435         ma_aaudio_input_preset inputPreset;
3436     } aaudio;
3437 };
3438
3439
3440 /*
3441 The callback for handling device enumeration. This is fired from `ma_context_enumerated_devices()`.
3442
3443
3444 Parameters
3445 ----------
3446 pContext (in)
3447     A pointer to the context performing the enumeration.
3448
3449 deviceType (in)
3450     The type of the device being enumerated. This will always be either `ma_device_type_playback` or `ma_device_type_capture`.
3451
3452 pInfo (in)
3453     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,
3454     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
3455     is too inefficient.
3456
3457 pUserData (in)
3458     The user data pointer passed into `ma_context_enumerate_devices()`.
3459 */
3460 typedef ma_bool32 (* ma_enum_devices_callback_proc)(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData);
3461
3462
3463 /*
3464 Describes some basic details about a playback or capture device.
3465 */
3466 typedef struct
3467 {
3468     const ma_device_id* pDeviceID;
3469     ma_share_mode shareMode;
3470     ma_format format;
3471     ma_uint32 channels;
3472     ma_uint32 sampleRate;
3473     ma_channel channelMap[MA_MAX_CHANNELS];
3474     ma_uint32 periodSizeInFrames;
3475     ma_uint32 periodSizeInMilliseconds;
3476     ma_uint32 periodCount;
3477 } ma_device_descriptor;
3478
3479 /*
3480 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
3481 to many devices. A device is created from a context.
3482
3483 The general flow goes like this:
3484
3485   1) A context is created with `onContextInit()`
3486      1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required.
3487      1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required.
3488   2) A device is created from the context that was created in the first step using `onDeviceInit()`, and optionally a device ID that was
3489      selected from device enumeration via `onContextEnumerateDevices()`.
3490   3) A device is started or stopped with `onDeviceStart()` / `onDeviceStop()`
3491   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
3492      to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by
3493      miniaudio internally.
3494
3495 Initialization of the context is quite simple. You need to do any necessary initialization of internal objects and then output the
3496 callbacks defined in this structure.
3497
3498 Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
3499 physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the
3500 given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration
3501 needs to stop and the `onContextEnumerateDevices()` function return with a success code.
3502
3503 Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID,
3504 and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the
3505 case when the device ID is NULL, in which case information about the default device needs to be retrieved.
3506
3507 Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created.
3508 This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a
3509 device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input,
3510 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
3511 the requested format. The conversion between the format requested by the application and the device's native format will be handled
3512 internally by miniaudio.
3513
3514 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
3515 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
3516 sample rate. For the channel map, the default should be used when `ma_channel_map_blank()` returns true (all channels set to
3517 `MA_CHANNEL_NONE`). On input, the `periodSizeInFrames` or `periodSizeInMilliseconds` option should always be set. The backend should
3518 inspect both of these variables. If `periodSizeInFrames` is set, it should take priority, otherwise it needs to be derived from the period
3519 size in milliseconds (`periodSizeInMilliseconds`) and the sample rate, keeping in mind that the sample rate may be 0, in which case the
3520 sample rate will need to be determined before calculating the period size in frames. On output, all members of the `ma_device_data_format`
3521 object should be set to a valid value, except for `periodSizeInMilliseconds` which is optional (`periodSizeInFrames` *must* be set).
3522
3523 Starting and stopping of the device is done with `onDeviceStart()` and `onDeviceStop()` and should be self-explanatory. If the backend uses
3524 asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should always be implemented.
3525
3526 The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit
3527 easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the `onDeviceRead()` and
3528 `onDeviceWrite()` callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the
3529 backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within it's callback.
3530 This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback.
3531
3532 If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceWorkerThread()` callback
3533 which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional.
3534
3535 The audio thread should run data delivery logic in a loop while `ma_device_get_state() == MA_STATE_STARTED` and no errors have been
3536 encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback.
3537
3538 The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this
3539 callback. When the device is stopped, the `ma_device_get_state() == MA_STATE_STARTED` condition will fail and the loop will be terminated
3540 which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback,
3541 look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to
3542 wake up the audio thread.
3543 */
3544 struct ma_backend_callbacks
3545 {
3546     ma_result (* onContextInit)(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks);
3547     ma_result (* onContextUninit)(ma_context* pContext);
3548     ma_result (* onContextEnumerateDevices)(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData);
3549     ma_result (* onContextGetDeviceInfo)(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo);
3550     ma_result (* onDeviceInit)(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture);
3551     ma_result (* onDeviceUninit)(ma_device* pDevice);
3552     ma_result (* onDeviceStart)(ma_device* pDevice);
3553     ma_result (* onDeviceStop)(ma_device* pDevice);
3554     ma_result (* onDeviceRead)(ma_device* pDevice, void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesRead);
3555     ma_result (* onDeviceWrite)(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten);
3556     ma_result (* onDeviceDataLoop)(ma_device* pDevice);
3557     ma_result (* onDeviceDataLoopWakeup)(ma_device* pDevice);
3558 };
3559
3560 struct ma_context_config
3561 {
3562     ma_log_proc logCallback;
3563     ma_thread_priority threadPriority;
3564     size_t threadStackSize;
3565     void* pUserData;
3566     ma_allocation_callbacks allocationCallbacks;
3567     struct
3568     {
3569         ma_bool32 useVerboseDeviceEnumeration;
3570     } alsa;
3571     struct
3572     {
3573         const char* pApplicationName;
3574         const char* pServerName;
3575         ma_bool32 tryAutoSpawn; /* Enables autospawning of the PulseAudio daemon if necessary. */
3576     } pulse;
3577     struct
3578     {
3579         ma_ios_session_category sessionCategory;
3580         ma_uint32 sessionCategoryOptions;
3581         ma_bool32 noAudioSessionActivate;   /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:true] on initialization. */
3582         ma_bool32 noAudioSessionDeactivate; /* iOS only. When set to true, does not perform an explicit [[AVAudioSession sharedInstace] setActive:false] on uninitialization. */
3583     } coreaudio;
3584     struct
3585     {
3586         const char* pClientName;
3587         ma_bool32 tryStartServer;
3588     } jack;
3589     ma_backend_callbacks custom;
3590 };
3591
3592 /* WASAPI specific structure for some commands which must run on a common thread due to bugs in WASAPI. */
3593 typedef struct
3594 {
3595     int code;
3596     ma_event* pEvent;   /* This will be signalled when the event is complete. */
3597     union
3598     {
3599         struct
3600         {
3601             int _unused;
3602         } quit;
3603         struct
3604         {
3605             ma_device_type deviceType;
3606             void* pAudioClient;
3607             void** ppAudioClientService;
3608             ma_result result;   /* The result from creating the audio client service. */
3609         } createAudioClient;
3610         struct
3611         {
3612             ma_device* pDevice;
3613             ma_device_type deviceType;
3614         } releaseAudioClient;
3615     } data;
3616 } ma_context_command__wasapi;
3617
3618 struct ma_context
3619 {
3620     ma_backend_callbacks callbacks;
3621     ma_backend backend;                 /* DirectSound, ALSA, etc. */
3622     ma_log_proc logCallback;
3623     ma_thread_priority threadPriority;
3624     size_t threadStackSize;
3625     void* pUserData;
3626     ma_allocation_callbacks allocationCallbacks;
3627     ma_mutex deviceEnumLock;            /* Used to make ma_context_get_devices() thread safe. */
3628     ma_mutex deviceInfoLock;            /* Used to make ma_context_get_device_info() thread safe. */
3629     ma_uint32 deviceInfoCapacity;       /* Total capacity of pDeviceInfos. */
3630     ma_uint32 playbackDeviceInfoCount;
3631     ma_uint32 captureDeviceInfoCount;
3632     ma_device_info* pDeviceInfos;       /* Playback devices first, then capture. */
3633
3634     union
3635     {
3636 #ifdef MA_SUPPORT_WASAPI
3637         struct
3638         {
3639             ma_thread commandThread;
3640             ma_mutex commandLock;
3641             ma_semaphore commandSem;
3642             ma_uint32 commandIndex;
3643             ma_uint32 commandCount;
3644             ma_context_command__wasapi commands[4];
3645         } wasapi;
3646 #endif
3647 #ifdef MA_SUPPORT_DSOUND
3648         struct
3649         {
3650             ma_handle hDSoundDLL;
3651             ma_proc DirectSoundCreate;
3652             ma_proc DirectSoundEnumerateA;
3653             ma_proc DirectSoundCaptureCreate;
3654             ma_proc DirectSoundCaptureEnumerateA;
3655         } dsound;
3656 #endif
3657 #ifdef MA_SUPPORT_WINMM
3658         struct
3659         {
3660             ma_handle hWinMM;
3661             ma_proc waveOutGetNumDevs;
3662             ma_proc waveOutGetDevCapsA;
3663             ma_proc waveOutOpen;
3664             ma_proc waveOutClose;
3665             ma_proc waveOutPrepareHeader;
3666             ma_proc waveOutUnprepareHeader;
3667             ma_proc waveOutWrite;
3668             ma_proc waveOutReset;
3669             ma_proc waveInGetNumDevs;
3670             ma_proc waveInGetDevCapsA;
3671             ma_proc waveInOpen;
3672             ma_proc waveInClose;
3673             ma_proc waveInPrepareHeader;
3674             ma_proc waveInUnprepareHeader;
3675             ma_proc waveInAddBuffer;
3676             ma_proc waveInStart;
3677             ma_proc waveInReset;
3678         } winmm;
3679 #endif
3680 #ifdef MA_SUPPORT_ALSA
3681         struct
3682         {
3683             ma_handle asoundSO;
3684             ma_proc snd_pcm_open;
3685             ma_proc snd_pcm_close;
3686             ma_proc snd_pcm_hw_params_sizeof;
3687             ma_proc snd_pcm_hw_params_any;
3688             ma_proc snd_pcm_hw_params_set_format;
3689             ma_proc snd_pcm_hw_params_set_format_first;
3690             ma_proc snd_pcm_hw_params_get_format_mask;
3691             ma_proc snd_pcm_hw_params_set_channels;
3692             ma_proc snd_pcm_hw_params_set_channels_near;
3693             ma_proc snd_pcm_hw_params_set_channels_minmax;
3694             ma_proc snd_pcm_hw_params_set_rate_resample;
3695             ma_proc snd_pcm_hw_params_set_rate;
3696             ma_proc snd_pcm_hw_params_set_rate_near;
3697             ma_proc snd_pcm_hw_params_set_buffer_size_near;
3698             ma_proc snd_pcm_hw_params_set_periods_near;
3699             ma_proc snd_pcm_hw_params_set_access;
3700             ma_proc snd_pcm_hw_params_get_format;
3701             ma_proc snd_pcm_hw_params_get_channels;
3702             ma_proc snd_pcm_hw_params_get_channels_min;
3703             ma_proc snd_pcm_hw_params_get_channels_max;
3704             ma_proc snd_pcm_hw_params_get_rate;
3705             ma_proc snd_pcm_hw_params_get_rate_min;
3706             ma_proc snd_pcm_hw_params_get_rate_max;
3707             ma_proc snd_pcm_hw_params_get_buffer_size;
3708             ma_proc snd_pcm_hw_params_get_periods;
3709             ma_proc snd_pcm_hw_params_get_access;
3710             ma_proc snd_pcm_hw_params_test_format;
3711             ma_proc snd_pcm_hw_params_test_channels;
3712             ma_proc snd_pcm_hw_params_test_rate;
3713             ma_proc snd_pcm_hw_params;
3714             ma_proc snd_pcm_sw_params_sizeof;
3715             ma_proc snd_pcm_sw_params_current;
3716             ma_proc snd_pcm_sw_params_get_boundary;
3717             ma_proc snd_pcm_sw_params_set_avail_min;
3718             ma_proc snd_pcm_sw_params_set_start_threshold;
3719             ma_proc snd_pcm_sw_params_set_stop_threshold;
3720             ma_proc snd_pcm_sw_params;
3721             ma_proc snd_pcm_format_mask_sizeof;
3722             ma_proc snd_pcm_format_mask_test;
3723             ma_proc snd_pcm_get_chmap;
3724             ma_proc snd_pcm_state;
3725             ma_proc snd_pcm_prepare;
3726             ma_proc snd_pcm_start;
3727             ma_proc snd_pcm_drop;
3728             ma_proc snd_pcm_drain;
3729             ma_proc snd_device_name_hint;
3730             ma_proc snd_device_name_get_hint;
3731             ma_proc snd_card_get_index;
3732             ma_proc snd_device_name_free_hint;
3733             ma_proc snd_pcm_mmap_begin;
3734             ma_proc snd_pcm_mmap_commit;
3735             ma_proc snd_pcm_recover;
3736             ma_proc snd_pcm_readi;
3737             ma_proc snd_pcm_writei;
3738             ma_proc snd_pcm_avail;
3739             ma_proc snd_pcm_avail_update;
3740             ma_proc snd_pcm_wait;
3741             ma_proc snd_pcm_info;
3742             ma_proc snd_pcm_info_sizeof;
3743             ma_proc snd_pcm_info_get_name;
3744             ma_proc snd_config_update_free_global;
3745
3746             ma_mutex internalDeviceEnumLock;
3747             ma_bool32 useVerboseDeviceEnumeration;
3748         } alsa;
3749 #endif
3750 #ifdef MA_SUPPORT_PULSEAUDIO
3751         struct
3752         {
3753             ma_handle pulseSO;
3754             ma_proc pa_mainloop_new;
3755             ma_proc pa_mainloop_free;
3756             ma_proc pa_mainloop_quit;
3757             ma_proc pa_mainloop_get_api;
3758             ma_proc pa_mainloop_iterate;
3759             ma_proc pa_mainloop_wakeup;
3760             ma_proc pa_threaded_mainloop_new;
3761             ma_proc pa_threaded_mainloop_free;
3762             ma_proc pa_threaded_mainloop_start;
3763             ma_proc pa_threaded_mainloop_stop;
3764             ma_proc pa_threaded_mainloop_lock;
3765             ma_proc pa_threaded_mainloop_unlock;
3766             ma_proc pa_threaded_mainloop_wait;
3767             ma_proc pa_threaded_mainloop_signal;
3768             ma_proc pa_threaded_mainloop_accept;
3769             ma_proc pa_threaded_mainloop_get_retval;
3770             ma_proc pa_threaded_mainloop_get_api;
3771             ma_proc pa_threaded_mainloop_in_thread;
3772             ma_proc pa_threaded_mainloop_set_name;
3773             ma_proc pa_context_new;
3774             ma_proc pa_context_unref;
3775             ma_proc pa_context_connect;
3776             ma_proc pa_context_disconnect;
3777             ma_proc pa_context_set_state_callback;
3778             ma_proc pa_context_get_state;
3779             ma_proc pa_context_get_sink_info_list;
3780             ma_proc pa_context_get_source_info_list;
3781             ma_proc pa_context_get_sink_info_by_name;
3782             ma_proc pa_context_get_source_info_by_name;
3783             ma_proc pa_operation_unref;
3784             ma_proc pa_operation_get_state;
3785             ma_proc pa_channel_map_init_extend;
3786             ma_proc pa_channel_map_valid;
3787             ma_proc pa_channel_map_compatible;
3788             ma_proc pa_stream_new;
3789             ma_proc pa_stream_unref;
3790             ma_proc pa_stream_connect_playback;
3791             ma_proc pa_stream_connect_record;
3792             ma_proc pa_stream_disconnect;
3793             ma_proc pa_stream_get_state;
3794             ma_proc pa_stream_get_sample_spec;
3795             ma_proc pa_stream_get_channel_map;
3796             ma_proc pa_stream_get_buffer_attr;
3797             ma_proc pa_stream_set_buffer_attr;
3798             ma_proc pa_stream_get_device_name;
3799             ma_proc pa_stream_set_write_callback;
3800             ma_proc pa_stream_set_read_callback;
3801             ma_proc pa_stream_flush;
3802             ma_proc pa_stream_drain;
3803             ma_proc pa_stream_is_corked;
3804             ma_proc pa_stream_cork;
3805             ma_proc pa_stream_trigger;
3806             ma_proc pa_stream_begin_write;
3807             ma_proc pa_stream_write;
3808             ma_proc pa_stream_peek;
3809             ma_proc pa_stream_drop;
3810             ma_proc pa_stream_writable_size;
3811             ma_proc pa_stream_readable_size;
3812
3813             /*pa_mainloop**/ ma_ptr pMainLoop;
3814             /*pa_context**/ ma_ptr pPulseContext;
3815         } pulse;
3816 #endif
3817 #ifdef MA_SUPPORT_JACK
3818         struct
3819         {
3820             ma_handle jackSO;
3821             ma_proc jack_client_open;
3822             ma_proc jack_client_close;
3823             ma_proc jack_client_name_size;
3824             ma_proc jack_set_process_callback;
3825             ma_proc jack_set_buffer_size_callback;
3826             ma_proc jack_on_shutdown;
3827             ma_proc jack_get_sample_rate;
3828             ma_proc jack_get_buffer_size;
3829             ma_proc jack_get_ports;
3830             ma_proc jack_activate;
3831             ma_proc jack_deactivate;
3832             ma_proc jack_connect;
3833             ma_proc jack_port_register;
3834             ma_proc jack_port_name;
3835             ma_proc jack_port_get_buffer;
3836             ma_proc jack_free;
3837
3838             char* pClientName;
3839             ma_bool32 tryStartServer;
3840         } jack;
3841 #endif
3842 #ifdef MA_SUPPORT_COREAUDIO
3843         struct
3844         {
3845             ma_handle hCoreFoundation;
3846             ma_proc CFStringGetCString;
3847             ma_proc CFRelease;
3848
3849             ma_handle hCoreAudio;
3850             ma_proc AudioObjectGetPropertyData;
3851             ma_proc AudioObjectGetPropertyDataSize;
3852             ma_proc AudioObjectSetPropertyData;
3853             ma_proc AudioObjectAddPropertyListener;
3854             ma_proc AudioObjectRemovePropertyListener;
3855
3856             ma_handle hAudioUnit;  /* Could possibly be set to AudioToolbox on later versions of macOS. */
3857             ma_proc AudioComponentFindNext;
3858             ma_proc AudioComponentInstanceDispose;
3859             ma_proc AudioComponentInstanceNew;
3860             ma_proc AudioOutputUnitStart;
3861             ma_proc AudioOutputUnitStop;
3862             ma_proc AudioUnitAddPropertyListener;
3863             ma_proc AudioUnitGetPropertyInfo;
3864             ma_proc AudioUnitGetProperty;
3865             ma_proc AudioUnitSetProperty;
3866             ma_proc AudioUnitInitialize;
3867             ma_proc AudioUnitRender;
3868
3869             /*AudioComponent*/ ma_ptr component;
3870             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(). */
3871         } coreaudio;
3872 #endif
3873 #ifdef MA_SUPPORT_SNDIO
3874         struct
3875         {
3876             ma_handle sndioSO;
3877             ma_proc sio_open;
3878             ma_proc sio_close;
3879             ma_proc sio_setpar;
3880             ma_proc sio_getpar;
3881             ma_proc sio_getcap;
3882             ma_proc sio_start;
3883             ma_proc sio_stop;
3884             ma_proc sio_read;
3885             ma_proc sio_write;
3886             ma_proc sio_onmove;
3887             ma_proc sio_nfds;
3888             ma_proc sio_pollfd;
3889             ma_proc sio_revents;
3890             ma_proc sio_eof;
3891             ma_proc sio_setvol;
3892             ma_proc sio_onvol;
3893             ma_proc sio_initpar;
3894         } sndio;
3895 #endif
3896 #ifdef MA_SUPPORT_AUDIO4
3897         struct
3898         {
3899             int _unused;
3900         } audio4;
3901 #endif
3902 #ifdef MA_SUPPORT_OSS
3903         struct
3904         {
3905             int versionMajor;
3906             int versionMinor;
3907         } oss;
3908 #endif
3909 #ifdef MA_SUPPORT_AAUDIO
3910         struct
3911         {
3912             ma_handle hAAudio; /* libaaudio.so */
3913             ma_proc AAudio_createStreamBuilder;
3914             ma_proc AAudioStreamBuilder_delete;
3915             ma_proc AAudioStreamBuilder_setDeviceId;
3916             ma_proc AAudioStreamBuilder_setDirection;
3917             ma_proc AAudioStreamBuilder_setSharingMode;
3918             ma_proc AAudioStreamBuilder_setFormat;
3919             ma_proc AAudioStreamBuilder_setChannelCount;
3920             ma_proc AAudioStreamBuilder_setSampleRate;
3921             ma_proc AAudioStreamBuilder_setBufferCapacityInFrames;
3922             ma_proc AAudioStreamBuilder_setFramesPerDataCallback;
3923             ma_proc AAudioStreamBuilder_setDataCallback;
3924             ma_proc AAudioStreamBuilder_setErrorCallback;
3925             ma_proc AAudioStreamBuilder_setPerformanceMode;
3926             ma_proc AAudioStreamBuilder_setUsage;
3927             ma_proc AAudioStreamBuilder_setContentType;
3928             ma_proc AAudioStreamBuilder_setInputPreset;
3929             ma_proc AAudioStreamBuilder_openStream;
3930             ma_proc AAudioStream_close;
3931             ma_proc AAudioStream_getState;
3932             ma_proc AAudioStream_waitForStateChange;
3933             ma_proc AAudioStream_getFormat;
3934             ma_proc AAudioStream_getChannelCount;
3935             ma_proc AAudioStream_getSampleRate;
3936             ma_proc AAudioStream_getBufferCapacityInFrames;
3937             ma_proc AAudioStream_getFramesPerDataCallback;
3938             ma_proc AAudioStream_getFramesPerBurst;
3939             ma_proc AAudioStream_requestStart;
3940             ma_proc AAudioStream_requestStop;
3941         } aaudio;
3942 #endif
3943 #ifdef MA_SUPPORT_OPENSL
3944         struct
3945         {
3946             ma_handle libOpenSLES;
3947             ma_handle SL_IID_ENGINE;
3948             ma_handle SL_IID_AUDIOIODEVICECAPABILITIES;
3949             ma_handle SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
3950             ma_handle SL_IID_RECORD;
3951             ma_handle SL_IID_PLAY;
3952             ma_handle SL_IID_OUTPUTMIX;
3953             ma_handle SL_IID_ANDROIDCONFIGURATION;
3954             ma_proc   slCreateEngine;
3955         } opensl;
3956 #endif
3957 #ifdef MA_SUPPORT_WEBAUDIO
3958         struct
3959         {
3960             int _unused;
3961         } webaudio;
3962 #endif
3963 #ifdef MA_SUPPORT_NULL
3964         struct
3965         {
3966             int _unused;
3967         } null_backend;
3968 #endif
3969     };
3970
3971     union
3972     {
3973 #ifdef MA_WIN32
3974         struct
3975         {
3976             /*HMODULE*/ ma_handle hOle32DLL;
3977             ma_proc CoInitializeEx;
3978             ma_proc CoUninitialize;
3979             ma_proc CoCreateInstance;
3980             ma_proc CoTaskMemFree;
3981             ma_proc PropVariantClear;
3982             ma_proc StringFromGUID2;
3983
3984             /*HMODULE*/ ma_handle hUser32DLL;
3985             ma_proc GetForegroundWindow;
3986             ma_proc GetDesktopWindow;
3987
3988             /*HMODULE*/ ma_handle hAdvapi32DLL;
3989             ma_proc RegOpenKeyExA;
3990             ma_proc RegCloseKey;
3991             ma_proc RegQueryValueExA;
3992         } win32;
3993 #endif
3994 #ifdef MA_POSIX
3995         struct
3996         {
3997             ma_handle pthreadSO;
3998             ma_proc pthread_create;
3999             ma_proc pthread_join;
4000             ma_proc pthread_mutex_init;
4001             ma_proc pthread_mutex_destroy;
4002             ma_proc pthread_mutex_lock;
4003             ma_proc pthread_mutex_unlock;
4004             ma_proc pthread_cond_init;
4005             ma_proc pthread_cond_destroy;
4006             ma_proc pthread_cond_wait;
4007             ma_proc pthread_cond_signal;
4008             ma_proc pthread_attr_init;
4009             ma_proc pthread_attr_destroy;
4010             ma_proc pthread_attr_setschedpolicy;
4011             ma_proc pthread_attr_getschedparam;
4012             ma_proc pthread_attr_setschedparam;
4013         } posix;
4014 #endif
4015         int _unused;
4016     };
4017 };
4018
4019 struct ma_device
4020 {
4021     ma_context* pContext;
4022     ma_device_type type;
4023     ma_uint32 sampleRate;
4024     MA_ATOMIC ma_uint32 state;              /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */
4025     ma_device_callback_proc onData;         /* Set once at initialization time and should not be changed after. */
4026     ma_stop_proc onStop;                    /* Set once at initialization time and should not be changed after. */
4027     void* pUserData;                        /* Application defined data. */
4028     ma_mutex startStopLock;
4029     ma_event wakeupEvent;
4030     ma_event startEvent;
4031     ma_event stopEvent;
4032     ma_thread thread;
4033     ma_result workResult;                   /* This is set by the worker thread after it's finished doing a job. */
4034     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(). */
4035     ma_bool8 noPreZeroedOutputBuffer;
4036     ma_bool8 noClip;
4037     MA_ATOMIC float masterVolumeFactor;     /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
4038     ma_duplex_rb duplexRB;                  /* Intermediary buffer for duplex device on asynchronous backends. */
4039     struct
4040     {
4041         ma_resample_algorithm algorithm;
4042         struct
4043         {
4044             ma_uint32 lpfOrder;
4045         } linear;
4046         struct
4047         {
4048             int quality;
4049         } speex;
4050     } resampling;
4051     struct
4052     {
4053         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. */
4054         char name[256];                     /* Maybe temporary. Likely to be replaced with a query API. */
4055         ma_share_mode shareMode;            /* Set to whatever was passed in when the device was initialized. */
4056         ma_format format;
4057         ma_uint32 channels;
4058         ma_channel channelMap[MA_MAX_CHANNELS];
4059         ma_format internalFormat;
4060         ma_uint32 internalChannels;
4061         ma_uint32 internalSampleRate;
4062         ma_channel internalChannelMap[MA_MAX_CHANNELS];
4063         ma_uint32 internalPeriodSizeInFrames;
4064         ma_uint32 internalPeriods;
4065         ma_channel_mix_mode channelMixMode;
4066         ma_data_converter converter;
4067     } playback;
4068     struct
4069     {
4070         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. */
4071         char name[256];                     /* Maybe temporary. Likely to be replaced with a query API. */
4072         ma_share_mode shareMode;            /* Set to whatever was passed in when the device was initialized. */
4073         ma_format format;
4074         ma_uint32 channels;
4075         ma_channel channelMap[MA_MAX_CHANNELS];
4076         ma_format internalFormat;
4077         ma_uint32 internalChannels;
4078         ma_uint32 internalSampleRate;
4079         ma_channel internalChannelMap[MA_MAX_CHANNELS];
4080         ma_uint32 internalPeriodSizeInFrames;
4081         ma_uint32 internalPeriods;
4082         ma_channel_mix_mode channelMixMode;
4083         ma_data_converter converter;
4084     } capture;
4085
4086     union
4087     {
4088 #ifdef MA_SUPPORT_WASAPI
4089         struct
4090         {
4091             /*IAudioClient**/ ma_ptr pAudioClientPlayback;
4092             /*IAudioClient**/ ma_ptr pAudioClientCapture;
4093             /*IAudioRenderClient**/ ma_ptr pRenderClient;
4094             /*IAudioCaptureClient**/ ma_ptr pCaptureClient;
4095             /*IMMDeviceEnumerator**/ ma_ptr pDeviceEnumerator;      /* Used for IMMNotificationClient notifications. Required for detecting default device changes. */
4096             ma_IMMNotificationClient notificationClient;
4097             /*HANDLE*/ ma_handle hEventPlayback;                    /* Auto reset. Initialized to signaled. */
4098             /*HANDLE*/ ma_handle hEventCapture;                     /* Auto reset. Initialized to unsignaled. */
4099             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. */
4100             ma_uint32 actualPeriodSizeInFramesCapture;
4101             ma_uint32 originalPeriodSizeInFrames;
4102             ma_uint32 originalPeriodSizeInMilliseconds;
4103             ma_uint32 originalPeriods;
4104             ma_performance_profile originalPerformanceProfile;
4105             ma_uint32 periodSizeInFramesPlayback;
4106             ma_uint32 periodSizeInFramesCapture;
4107             MA_ATOMIC ma_bool32 isStartedCapture;                   /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
4108             MA_ATOMIC ma_bool32 isStartedPlayback;                  /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
4109             ma_bool8 noAutoConvertSRC;                              /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
4110             ma_bool8 noDefaultQualitySRC;                           /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
4111             ma_bool8 noHardwareOffloading;
4112             ma_bool8 allowCaptureAutoStreamRouting;
4113             ma_bool8 allowPlaybackAutoStreamRouting;
4114             ma_bool8 isDetachedPlayback;
4115             ma_bool8 isDetachedCapture;
4116         } wasapi;
4117 #endif
4118 #ifdef MA_SUPPORT_DSOUND
4119         struct
4120         {
4121             /*LPDIRECTSOUND*/ ma_ptr pPlayback;
4122             /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackPrimaryBuffer;
4123             /*LPDIRECTSOUNDBUFFER*/ ma_ptr pPlaybackBuffer;
4124             /*LPDIRECTSOUNDCAPTURE*/ ma_ptr pCapture;
4125             /*LPDIRECTSOUNDCAPTUREBUFFER*/ ma_ptr pCaptureBuffer;
4126         } dsound;
4127 #endif
4128 #ifdef MA_SUPPORT_WINMM
4129         struct
4130         {
4131             /*HWAVEOUT*/ ma_handle hDevicePlayback;
4132             /*HWAVEIN*/ ma_handle hDeviceCapture;
4133             /*HANDLE*/ ma_handle hEventPlayback;
4134             /*HANDLE*/ ma_handle hEventCapture;
4135             ma_uint32 fragmentSizeInFrames;
4136             ma_uint32 iNextHeaderPlayback;             /* [0,periods). Used as an index into pWAVEHDRPlayback. */
4137             ma_uint32 iNextHeaderCapture;              /* [0,periods). Used as an index into pWAVEHDRCapture. */
4138             ma_uint32 headerFramesConsumedPlayback;    /* The number of PCM frames consumed in the buffer in pWAVEHEADER[iNextHeader]. */
4139             ma_uint32 headerFramesConsumedCapture;     /* ^^^ */
4140             /*WAVEHDR**/ ma_uint8* pWAVEHDRPlayback;   /* One instantiation for each period. */
4141             /*WAVEHDR**/ ma_uint8* pWAVEHDRCapture;    /* One instantiation for each period. */
4142             ma_uint8* pIntermediaryBufferPlayback;
4143             ma_uint8* pIntermediaryBufferCapture;
4144             ma_uint8* _pHeapData;                      /* Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. */
4145         } winmm;
4146 #endif
4147 #ifdef MA_SUPPORT_ALSA
4148         struct
4149         {
4150             /*snd_pcm_t**/ ma_ptr pPCMPlayback;
4151             /*snd_pcm_t**/ ma_ptr pPCMCapture;
4152             ma_bool8 isUsingMMapPlayback;
4153             ma_bool8 isUsingMMapCapture;
4154         } alsa;
4155 #endif
4156 #ifdef MA_SUPPORT_PULSEAUDIO
4157         struct
4158         {
4159             /*pa_stream**/ ma_ptr pStreamPlayback;
4160             /*pa_stream**/ ma_ptr pStreamCapture;
4161         } pulse;
4162 #endif
4163 #ifdef MA_SUPPORT_JACK
4164         struct
4165         {
4166             /*jack_client_t**/ ma_ptr pClient;
4167             /*jack_port_t**/ ma_ptr pPortsPlayback[MA_MAX_CHANNELS];
4168             /*jack_port_t**/ ma_ptr pPortsCapture[MA_MAX_CHANNELS];
4169             float* pIntermediaryBufferPlayback; /* Typed as a float because JACK is always floating point. */
4170             float* pIntermediaryBufferCapture;
4171         } jack;
4172 #endif
4173 #ifdef MA_SUPPORT_COREAUDIO
4174         struct
4175         {
4176             ma_uint32 deviceObjectIDPlayback;
4177             ma_uint32 deviceObjectIDCapture;
4178             /*AudioUnit*/ ma_ptr audioUnitPlayback;
4179             /*AudioUnit*/ ma_ptr audioUnitCapture;
4180             /*AudioBufferList**/ ma_ptr pAudioBufferList;   /* Only used for input devices. */
4181             ma_uint32 audioBufferCapInFrames;               /* Only used for input devices. The capacity in frames of each buffer in pAudioBufferList. */
4182             ma_event stopEvent;
4183             ma_uint32 originalPeriodSizeInFrames;
4184             ma_uint32 originalPeriodSizeInMilliseconds;
4185             ma_uint32 originalPeriods;
4186             ma_performance_profile originalPerformanceProfile;
4187             ma_bool32 isDefaultPlaybackDevice;
4188             ma_bool32 isDefaultCaptureDevice;
4189             ma_bool32 isSwitchingPlaybackDevice;   /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
4190             ma_bool32 isSwitchingCaptureDevice;    /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
4191             void* pRouteChangeHandler;             /* Only used on mobile platforms. Obj-C object for handling route changes. */
4192         } coreaudio;
4193 #endif
4194 #ifdef MA_SUPPORT_SNDIO
4195         struct
4196         {
4197             ma_ptr handlePlayback;
4198             ma_ptr handleCapture;
4199             ma_bool32 isStartedPlayback;
4200             ma_bool32 isStartedCapture;
4201         } sndio;
4202 #endif
4203 #ifdef MA_SUPPORT_AUDIO4
4204         struct
4205         {
4206             int fdPlayback;
4207             int fdCapture;
4208         } audio4;
4209 #endif
4210 #ifdef MA_SUPPORT_OSS
4211         struct
4212         {
4213             int fdPlayback;
4214             int fdCapture;
4215         } oss;
4216 #endif
4217 #ifdef MA_SUPPORT_AAUDIO
4218         struct
4219         {
4220             /*AAudioStream**/ ma_ptr pStreamPlayback;
4221             /*AAudioStream**/ ma_ptr pStreamCapture;
4222         } aaudio;
4223 #endif
4224 #ifdef MA_SUPPORT_OPENSL
4225         struct
4226         {
4227             /*SLObjectItf*/ ma_ptr pOutputMixObj;
4228             /*SLOutputMixItf*/ ma_ptr pOutputMix;
4229             /*SLObjectItf*/ ma_ptr pAudioPlayerObj;
4230             /*SLPlayItf*/ ma_ptr pAudioPlayer;
4231             /*SLObjectItf*/ ma_ptr pAudioRecorderObj;
4232             /*SLRecordItf*/ ma_ptr pAudioRecorder;
4233             /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueuePlayback;
4234             /*SLAndroidSimpleBufferQueueItf*/ ma_ptr pBufferQueueCapture;
4235             ma_bool32 isDrainingCapture;
4236             ma_bool32 isDrainingPlayback;
4237             ma_uint32 currentBufferIndexPlayback;
4238             ma_uint32 currentBufferIndexCapture;
4239             ma_uint8* pBufferPlayback;      /* This is malloc()'d and is used for storing audio data. Typed as ma_uint8 for easy offsetting. */
4240             ma_uint8* pBufferCapture;
4241         } opensl;
4242 #endif
4243 #ifdef MA_SUPPORT_WEBAUDIO
4244         struct
4245         {
4246             int indexPlayback;              /* We use a factory on the JavaScript side to manage devices and use an index for JS/C interop. */
4247             int indexCapture;
4248         } webaudio;
4249 #endif
4250 #ifdef MA_SUPPORT_NULL
4251         struct
4252         {
4253             ma_thread deviceThread;
4254             ma_event operationEvent;
4255             ma_event operationCompletionEvent;
4256             ma_semaphore operationSemaphore;
4257             ma_uint32 operation;
4258             ma_result operationResult;
4259             ma_timer timer;
4260             double priorRunTime;
4261             ma_uint32 currentPeriodFramesRemainingPlayback;
4262             ma_uint32 currentPeriodFramesRemainingCapture;
4263             ma_uint64 lastProcessedFramePlayback;
4264             ma_uint64 lastProcessedFrameCapture;
4265             MA_ATOMIC ma_bool32 isStarted;   /* Read and written by multiple threads. Must be used atomically, and must be 32-bit for compiler compatibility. */
4266         } null_device;
4267 #endif
4268     };
4269 };
4270 #if defined(_MSC_VER) && !defined(__clang__)
4271     #pragma warning(pop)
4272 #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
4273     #pragma GCC diagnostic pop  /* For ISO C99 doesn't support unnamed structs/unions [-Wpedantic] */
4274 #endif
4275
4276 /*
4277 Initializes a `ma_context_config` object.
4278
4279
4280 Return Value
4281 ------------
4282 A `ma_context_config` initialized to defaults.
4283
4284
4285 Remarks
4286 -------
4287 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
4288 is updated and new members are added to `ma_context_config`. It also sets logical defaults.
4289
4290 You can override members of the returned object by changing it's members directly.
4291
4292
4293 See Also
4294 --------
4295 ma_context_init()
4296 */
4297 MA_API ma_context_config ma_context_config_init(void);
4298
4299 /*
4300 Initializes a context.
4301
4302 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
4303 device. There is one context to many devices, and a device is created from a context. A context is required to enumerate devices.
4304
4305
4306 Parameters
4307 ----------
4308 backends (in, optional)
4309     A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
4310
4311 backendCount (in, optional)
4312     The number of items in `backend`. Ignored if `backend` is NULL.
4313
4314 pConfig (in, optional)
4315     The context configuration.
4316
4317 pContext (in)
4318     A pointer to the context object being initialized.
4319
4320
4321 Return Value
4322 ------------
4323 MA_SUCCESS if successful; any other error code otherwise.
4324
4325
4326 Thread Safety
4327 -------------
4328 Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
4329
4330
4331 Remarks
4332 -------
4333 When `backends` is NULL, the default priority order will be used. Below is a list of backends in priority order:
4334
4335     |-------------|-----------------------|--------------------------------------------------------|
4336     | Name        | Enum Name             | Supported Operating Systems                            |
4337     |-------------|-----------------------|--------------------------------------------------------|
4338     | WASAPI      | ma_backend_wasapi     | Windows Vista+                                         |
4339     | DirectSound | ma_backend_dsound     | Windows XP+                                            |
4340     | WinMM       | ma_backend_winmm      | Windows XP+ (may work on older versions, but untested) |
4341     | Core Audio  | ma_backend_coreaudio  | macOS, iOS                                             |
4342     | ALSA        | ma_backend_alsa       | Linux                                                  |
4343     | PulseAudio  | ma_backend_pulseaudio | Cross Platform (disabled on Windows, BSD and Android)  |
4344     | JACK        | ma_backend_jack       | Cross Platform (disabled on BSD and Android)           |
4345     | sndio       | ma_backend_sndio      | OpenBSD                                                |
4346     | audio(4)    | ma_backend_audio4     | NetBSD, OpenBSD                                        |
4347     | OSS         | ma_backend_oss        | FreeBSD                                                |
4348     | AAudio      | ma_backend_aaudio     | Android 8+                                             |
4349     | OpenSL|ES   | ma_backend_opensl     | Android (API level 16+)                                |
4350     | Web Audio   | ma_backend_webaudio   | Web (via Emscripten)                                   |
4351     | Null        | ma_backend_null       | Cross Platform (not used on Web)                       |
4352     |-------------|-----------------------|--------------------------------------------------------|
4353
4354 The context can be configured via the `pConfig` argument. The config object is initialized with `ma_context_config_init()`. Individual configuration settings
4355 can then be set directly on the structure. Below are the members of the `ma_context_config` object.
4356
4357     logCallback
4358         Callback for handling log messages from miniaudio.
4359
4360     threadPriority
4361         The desired priority to use for the audio thread. Allowable values include the following:
4362
4363         |--------------------------------------|
4364         | Thread Priority                      |
4365         |--------------------------------------|
4366         | ma_thread_priority_idle              |
4367         | ma_thread_priority_lowest            |
4368         | ma_thread_priority_low               |
4369         | ma_thread_priority_normal            |
4370         | ma_thread_priority_high              |
4371         | ma_thread_priority_highest (default) |
4372         | ma_thread_priority_realtime          |
4373         | ma_thread_priority_default           |
4374         |--------------------------------------|
4375
4376     pUserData
4377         A pointer to application-defined data. This can be accessed from the context object directly such as `context.pUserData`.
4378
4379     allocationCallbacks
4380         Structure containing custom allocation callbacks. Leaving this at defaults will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. These allocation
4381         callbacks will be used for anything tied to the context, including devices.
4382
4383     alsa.useVerboseDeviceEnumeration
4384         ALSA will typically enumerate many different devices which can be intrusive and not user-friendly. To combat this, miniaudio will enumerate only unique
4385         card/device pairs by default. The problem with this is that you lose a bit of flexibility and control. Setting alsa.useVerboseDeviceEnumeration makes
4386         it so the ALSA backend includes all devices. Defaults to false.
4387
4388     pulse.pApplicationName
4389         PulseAudio only. The application name to use when initializing the PulseAudio context with `pa_context_new()`.
4390
4391     pulse.pServerName
4392         PulseAudio only. The name of the server to connect to with `pa_context_connect()`.
4393
4394     pulse.tryAutoSpawn
4395         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
4396         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
4397         intrusive for the end user.
4398
4399     coreaudio.sessionCategory
4400         iOS only. The session category to use for the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
4401
4402         |-----------------------------------------|-------------------------------------|
4403         | miniaudio Token                         | Core Audio Token                    |
4404         |-----------------------------------------|-------------------------------------|
4405         | ma_ios_session_category_ambient         | AVAudioSessionCategoryAmbient       |
4406         | ma_ios_session_category_solo_ambient    | AVAudioSessionCategorySoloAmbient   |
4407         | ma_ios_session_category_playback        | AVAudioSessionCategoryPlayback      |
4408         | ma_ios_session_category_record          | AVAudioSessionCategoryRecord        |
4409         | ma_ios_session_category_play_and_record | AVAudioSessionCategoryPlayAndRecord |
4410         | ma_ios_session_category_multi_route     | AVAudioSessionCategoryMultiRoute    |
4411         | ma_ios_session_category_none            | AVAudioSessionCategoryAmbient       |
4412         | ma_ios_session_category_default         | AVAudioSessionCategoryAmbient       |
4413         |-----------------------------------------|-------------------------------------|
4414
4415     coreaudio.sessionCategoryOptions
4416         iOS only. Session category options to use with the shared AudioSession instance. Below is a list of allowable values and their Core Audio equivalents.
4417
4418         |---------------------------------------------------------------------------|------------------------------------------------------------------|
4419         | miniaudio Token                                                           | Core Audio Token                                                 |
4420         |---------------------------------------------------------------------------|------------------------------------------------------------------|
4421         | ma_ios_session_category_option_mix_with_others                            | AVAudioSessionCategoryOptionMixWithOthers                        |
4422         | ma_ios_session_category_option_duck_others                                | AVAudioSessionCategoryOptionDuckOthers                           |
4423         | ma_ios_session_category_option_allow_bluetooth                            | AVAudioSessionCategoryOptionAllowBluetooth                       |
4424         | ma_ios_session_category_option_default_to_speaker                         | AVAudioSessionCategoryOptionDefaultToSpeaker                     |
4425         | ma_ios_session_category_option_interrupt_spoken_audio_and_mix_with_others | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers |
4426         | ma_ios_session_category_option_allow_bluetooth_a2dp                       | AVAudioSessionCategoryOptionAllowBluetoothA2DP                   |
4427         | ma_ios_session_category_option_allow_air_play                             | AVAudioSessionCategoryOptionAllowAirPlay                         |
4428         |---------------------------------------------------------------------------|------------------------------------------------------------------|
4429
4430     jack.pClientName
4431         The name of the client to pass to `jack_client_open()`.
4432
4433     jack.tryStartServer
4434         Whether or not to try auto-starting the JACK server. Defaults to false.
4435
4436
4437 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
4438 relevant backends every time it's initialized.
4439
4440 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
4441 reason for this is that a pointer to the context is stored in the `ma_device` structure.
4442
4443
4444 Example 1 - Default Initialization
4445 ----------------------------------
4446 The example below shows how to initialize the context using the default configuration.
4447
4448 ```c
4449 ma_context context;
4450 ma_result result = ma_context_init(NULL, 0, NULL, &context);
4451 if (result != MA_SUCCESS) {
4452     // Error.
4453 }
4454 ```
4455
4456
4457 Example 2 - Custom Configuration
4458 --------------------------------
4459 The example below shows how to initialize the context using custom backend priorities and a custom configuration. In this hypothetical example, the program
4460 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
4461 want an error to be returned if no valid backend is available which they achieve by excluding the Null backend.
4462
4463 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.
4464
4465 ```c
4466 ma_backend backends[] = {
4467     ma_backend_alsa,
4468     ma_backend_pulseaudio,
4469     ma_backend_wasapi,
4470     ma_backend_dsound
4471 };
4472
4473 ma_context_config config = ma_context_config_init();
4474 config.logCallback = my_log_callback;
4475 config.pUserData   = pMyUserData;
4476
4477 ma_context context;
4478 ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &config, &context);
4479 if (result != MA_SUCCESS) {
4480     // Error.
4481     if (result == MA_NO_BACKEND) {
4482         // Couldn't find an appropriate backend.
4483     }
4484 }
4485 ```
4486
4487
4488 See Also
4489 --------
4490 ma_context_config_init()
4491 ma_context_uninit()
4492 */
4493 MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext);
4494
4495 /*
4496 Uninitializes a context.
4497
4498
4499 Return Value
4500 ------------
4501 MA_SUCCESS if successful; any other error code otherwise.
4502
4503
4504 Thread Safety
4505 -------------
4506 Unsafe. Do not call this function across multiple threads as some backends read and write to global state.
4507
4508
4509 Remarks
4510 -------
4511 Results are undefined if you call this while any device created by this context is still active.
4512
4513
4514 See Also
4515 --------
4516 ma_context_init()
4517 */
4518 MA_API ma_result ma_context_uninit(ma_context* pContext);
4519
4520 /*
4521 Retrieves the size of the ma_context object.
4522
4523 This is mainly for the purpose of bindings to know how much memory to allocate.
4524 */
4525 MA_API size_t ma_context_sizeof(void);
4526
4527 /*
4528 Enumerates over every device (both playback and capture).
4529
4530 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
4531 an internal heap allocation, or it simply suits your code better.
4532
4533 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
4534 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,
4535 but don't call it from within the enumeration callback.
4536
4537 Returning false from the callback will stop enumeration. Returning true will continue enumeration.
4538
4539
4540 Parameters
4541 ----------
4542 pContext (in)
4543     A pointer to the context performing the enumeration.
4544
4545 callback (in)
4546     The callback to fire for each enumerated device.
4547
4548 pUserData (in)
4549     A pointer to application-defined data passed to the callback.
4550
4551
4552 Return Value
4553 ------------
4554 MA_SUCCESS if successful; any other error code otherwise.
4555
4556
4557 Thread Safety
4558 -------------
4559 Safe. This is guarded using a simple mutex lock.
4560
4561
4562 Remarks
4563 -------
4564 Do _not_ assume the first enumerated device of a given type is the default device.
4565
4566 Some backends and platforms may only support default playback and capture devices.
4567
4568 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,
4569 do not try to call `ma_context_get_device_info()` from within the callback.
4570
4571 Consider using `ma_context_get_devices()` for a simpler and safer API, albeit at the expense of an internal heap allocation.
4572
4573
4574 Example 1 - Simple Enumeration
4575 ------------------------------
4576 ma_bool32 ma_device_enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
4577 {
4578     printf("Device Name: %s\n", pInfo->name);
4579     return MA_TRUE;
4580 }
4581
4582 ma_result result = ma_context_enumerate_devices(&context, my_device_enum_callback, pMyUserData);
4583 if (result != MA_SUCCESS) {
4584     // Error.
4585 }
4586
4587
4588 See Also
4589 --------
4590 ma_context_get_devices()
4591 */
4592 MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData);
4593
4594 /*
4595 Retrieves basic information about every active playback and/or capture device.
4596
4597 This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos`
4598 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.
4599
4600
4601 Parameters
4602 ----------
4603 pContext (in)
4604     A pointer to the context performing the enumeration.
4605
4606 ppPlaybackDeviceInfos (out)
4607     A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for playback devices.
4608
4609 pPlaybackDeviceCount (out)
4610     A pointer to an unsigned integer that will receive the number of playback devices.
4611
4612 ppCaptureDeviceInfos (out)
4613     A pointer to a pointer that will receive the address of a buffer containing the list of `ma_device_info` structures for capture devices.
4614
4615 pCaptureDeviceCount (out)
4616     A pointer to an unsigned integer that will receive the number of capture devices.
4617
4618
4619 Return Value
4620 ------------
4621 MA_SUCCESS if successful; any other error code otherwise.
4622
4623
4624 Thread Safety
4625 -------------
4626 Unsafe. Since each call to this function invalidates the pointers from the previous call, you should not be calling this simultaneously across multiple
4627 threads. Instead, you need to make a copy of the returned data with your own higher level synchronization.
4628
4629
4630 Remarks
4631 -------
4632 It is _not_ safe to assume the first device in the list is the default device.
4633
4634 You can pass in NULL for the playback or capture lists in which case they'll be ignored.
4635
4636 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.
4637
4638
4639 See Also
4640 --------
4641 ma_context_get_devices()
4642 */
4643 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);
4644
4645 /*
4646 Retrieves information about a device of the given type, with the specified ID and share mode.
4647
4648
4649 Parameters
4650 ----------
4651 pContext (in)
4652     A pointer to the context performing the query.
4653
4654 deviceType (in)
4655     The type of the device being queried. Must be either `ma_device_type_playback` or `ma_device_type_capture`.
4656
4657 pDeviceID (in)
4658     The ID of the device being queried.
4659
4660 shareMode (in)
4661     The share mode to query for device capabilities. This should be set to whatever you're intending on using when initializing the device. If you're unsure,
4662     set this to `ma_share_mode_shared`.
4663
4664 pDeviceInfo (out)
4665     A pointer to the `ma_device_info` structure that will receive the device information.
4666
4667
4668 Return Value
4669 ------------
4670 MA_SUCCESS if successful; any other error code otherwise.
4671
4672
4673 Thread Safety
4674 -------------
4675 Safe. This is guarded using a simple mutex lock.
4676
4677
4678 Remarks
4679 -------
4680 Do _not_ call this from within the `ma_context_enumerate_devices()` callback.
4681
4682 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
4683 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
4684 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
4685 the requested share mode is unsupported.
4686
4687 This leaves pDeviceInfo unmodified in the result of an error.
4688 */
4689 MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo);
4690
4691 /*
4692 Determines if the given context supports loopback mode.
4693
4694
4695 Parameters
4696 ----------
4697 pContext (in)
4698     A pointer to the context getting queried.
4699
4700
4701 Return Value
4702 ------------
4703 MA_TRUE if the context supports loopback mode; MA_FALSE otherwise.
4704 */
4705 MA_API ma_bool32 ma_context_is_loopback_supported(ma_context* pContext);
4706
4707
4708
4709 /*
4710 Initializes a device config with default settings.
4711
4712
4713 Parameters
4714 ----------
4715 deviceType (in)
4716     The type of the device this config is being initialized for. This must set to one of the following:
4717
4718     |-------------------------|
4719     | Device Type             |
4720     |-------------------------|
4721     | ma_device_type_playback |
4722     | ma_device_type_capture  |
4723     | ma_device_type_duplex   |
4724     | ma_device_type_loopback |
4725     |-------------------------|
4726
4727
4728 Return Value
4729 ------------
4730 A new device config object with default settings. You will typically want to adjust the config after this function returns. See remarks.
4731
4732
4733 Thread Safety
4734 -------------
4735 Safe.
4736
4737
4738 Callback Safety
4739 ---------------
4740 Safe, but don't try initializing a device in a callback.
4741
4742
4743 Remarks
4744 -------
4745 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
4746 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
4747 before initializing the device.
4748
4749 See `ma_device_init()` for details on specific configuration options.
4750
4751
4752 Example 1 - Simple Configuration
4753 --------------------------------
4754 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
4755 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
4756 to the `ma_device_config` structure.
4757
4758 ```c
4759 ma_device_config config = ma_device_config_init(ma_device_type_playback);
4760 config.playback.format   = ma_format_f32;
4761 config.playback.channels = 2;
4762 config.sampleRate        = 48000;
4763 config.dataCallback      = ma_data_callback;
4764 config.pUserData         = pMyUserData;
4765 ```
4766
4767
4768 See Also
4769 --------
4770 ma_device_init()
4771 ma_device_init_ex()
4772 */
4773 MA_API ma_device_config ma_device_config_init(ma_device_type deviceType);
4774
4775
4776 /*
4777 Initializes a device.
4778
4779 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
4780 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
4781 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
4782 device is done via a callback which is fired by miniaudio at periodic time intervals.
4783
4784 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
4785 or milliseconds, whichever is more convenient. Generally speaking, the smaller the period, the lower the latency at the expense of higher CPU usage and
4786 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
4787 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
4788 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
4789 backend is ultimately responsible for what it gives you. You cannot assume you will get exactly what you ask for.
4790
4791 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
4792 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
4793 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.
4794
4795
4796 Parameters
4797 ----------
4798 pContext (in, optional)
4799     A pointer to the context that owns the device. This can be null, in which case it creates a default context internally.
4800
4801 pConfig (in)
4802     A pointer to the device configuration. Cannot be null. See remarks for details.
4803
4804 pDevice (out)
4805     A pointer to the device object being initialized.
4806
4807
4808 Return Value
4809 ------------
4810 MA_SUCCESS if successful; any other error code otherwise.
4811
4812
4813 Thread Safety
4814 -------------
4815 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
4816 calling this at the same time as `ma_device_uninit()`.
4817
4818
4819 Callback Safety
4820 ---------------
4821 Unsafe. It is not safe to call this inside any callback.
4822
4823
4824 Remarks
4825 -------
4826 Setting `pContext` to NULL will result in miniaudio creating a default context internally and is equivalent to passing in a context initialized like so:
4827
4828     ```c
4829     ma_context_init(NULL, 0, NULL, &context);
4830     ```
4831
4832 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
4833 device.pContext for the initialization of other devices.
4834
4835 The device can be configured via the `pConfig` argument. The config object is initialized with `ma_device_config_init()`. Individual configuration settings can
4836 then be set directly on the structure. Below are the members of the `ma_device_config` object.
4837
4838     deviceType
4839         Must be `ma_device_type_playback`, `ma_device_type_capture`, `ma_device_type_duplex` of `ma_device_type_loopback`.
4840
4841     sampleRate
4842         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.
4843
4844     periodSizeInFrames
4845         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
4846         be used depending on the selected performance profile. This value affects latency. See below for details.
4847
4848     periodSizeInMilliseconds
4849         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
4850         used depending on the selected performance profile. The value affects latency. See below for details.
4851
4852     periods
4853         The number of periods making up the device's entire buffer. The total buffer size is `periodSizeInFrames` or `periodSizeInMilliseconds` multiplied by
4854         this value. This is just a hint as backends will be the ones who ultimately decide how your periods will be configured.
4855
4856     performanceProfile
4857         A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or
4858         `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value.
4859
4860     noPreZeroedOutputBuffer
4861         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
4862         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
4863         callback will write to every sample in the output buffer, or if you are doing your own clearing.
4864
4865     noClip
4866         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
4867         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
4868         applies when the playback sample format is f32.
4869
4870     dataCallback
4871         The callback to fire whenever data is ready to be delivered to or from the device.
4872
4873     stopCallback
4874         The callback to fire whenever the device has stopped, either explicitly via `ma_device_stop()`, or implicitly due to things like the device being
4875         disconnected.
4876
4877     pUserData
4878         The user data pointer to use with the device. You can access this directly from the device object like `device.pUserData`.
4879
4880     resampling.algorithm
4881         The resampling algorithm to use when miniaudio needs to perform resampling between the rate specified by `sampleRate` and the device's native rate. The
4882         default value is `ma_resample_algorithm_linear`, and the quality can be configured with `resampling.linear.lpfOrder`.
4883
4884     resampling.linear.lpfOrder
4885         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
4886         the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is
4887         `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`.
4888
4889     playback.pDeviceID
4890         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
4891         default playback device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration.
4892
4893     playback.format
4894         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
4895         initialization from the device object directly with `device.playback.format`.
4896
4897     playback.channels
4898         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
4899         from the device object directly with `device.playback.channels`.
4900
4901     playback.channelMap
4902         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
4903         device object direct with `device.playback.channelMap`.
4904
4905     playback.shareMode
4906         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
4907         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
4908         ma_share_mode_shared and reinitializing.
4909
4910     capture.pDeviceID
4911         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
4912         default capture device. Retrieve the device ID from the `ma_device_info` structure, which can be retrieved using device enumeration.
4913
4914     capture.format
4915         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
4916         initialization from the device object directly with `device.capture.format`.
4917
4918     capture.channels
4919         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
4920         from the device object directly with `device.capture.channels`.
4921
4922     capture.channelMap
4923         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
4924         device object direct with `device.capture.channelMap`.
4925
4926     capture.shareMode
4927         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
4928         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
4929         ma_share_mode_shared and reinitializing.
4930
4931     wasapi.noAutoConvertSRC
4932         WASAPI only. When set to true, disables WASAPI's automatic resampling and forces the use of miniaudio's resampler. Defaults to false.
4933
4934     wasapi.noDefaultQualitySRC
4935         WASAPI only. Only used when `wasapi.noAutoConvertSRC` is set to false. When set to true, disables the use of `AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY`.
4936         You should usually leave this set to false, which is the default.
4937
4938     wasapi.noAutoStreamRouting
4939         WASAPI only. When set to true, disables automatic stream routing on the WASAPI backend. Defaults to false.
4940
4941     wasapi.noHardwareOffloading
4942         WASAPI only. When set to true, disables the use of WASAPI's hardware offloading feature. Defaults to false.
4943
4944     alsa.noMMap
4945         ALSA only. When set to true, disables MMap mode. Defaults to false.
4946
4947     alsa.noAutoFormat
4948         ALSA only. When set to true, disables ALSA's automatic format conversion by including the SND_PCM_NO_AUTO_FORMAT flag. Defaults to false.
4949
4950     alsa.noAutoChannels
4951         ALSA only. When set to true, disables ALSA's automatic channel conversion by including the SND_PCM_NO_AUTO_CHANNELS flag. Defaults to false.
4952
4953     alsa.noAutoResample
4954         ALSA only. When set to true, disables ALSA's automatic resampling by including the SND_PCM_NO_AUTO_RESAMPLE flag. Defaults to false.
4955
4956     pulse.pStreamNamePlayback
4957         PulseAudio only. Sets the stream name for playback.
4958
4959     pulse.pStreamNameCapture
4960         PulseAudio only. Sets the stream name for capture.
4961
4962     coreaudio.allowNominalSampleRateChange
4963         Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This
4964         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
4965         that is known to be natively supported by the hardware thereby avoiding the cost of resampling. When set to true, miniaudio will
4966         find the closest match between the sample rate requested in the device config and the sample rates natively supported by the
4967         hardware. When set to false, the sample rate currently set by the operating system will always be used.
4968
4969
4970 Once initialized, the device's config is immutable. If you need to change the config you will need to initialize a new device.
4971
4972 After initializing the device it will be in a stopped state. To start it, use `ma_device_start()`.
4973
4974 If both `periodSizeInFrames` and `periodSizeInMilliseconds` are set to zero, it will default to `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY` or
4975 `MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE`, depending on whether or not `performanceProfile` is set to `ma_performance_profile_low_latency` or
4976 `ma_performance_profile_conservative`.
4977
4978 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
4979 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
4980 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,
4981 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.
4982 Starting with Windows 10, miniaudio will use low-latency shared mode where possible which may make exclusive mode unnecessary.
4983
4984 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
4985 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
4986 on an optimized pass-through fast path. You can retrieve the format, channel count and sample rate by inspecting the `playback/capture.format`,
4987 `playback/capture.channels` and `sampleRate` members of the device object.
4988
4989 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
4990 asking for permissions. Please refer to the official documentation for ActivateAudioInterfaceAsync() for more information.
4991
4992 ALSA Specific: When initializing the default device, requesting shared mode will try using the "dmix" device for playback and the "dsnoop" device for capture.
4993 If these fail it will try falling back to the "hw" device.
4994
4995
4996 Example 1 - Simple Initialization
4997 ---------------------------------
4998 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
4999 playback device this is usually all you need.
5000
5001 ```c
5002 ma_device_config config = ma_device_config_init(ma_device_type_playback);
5003 config.playback.format   = ma_format_f32;
5004 config.playback.channels = 2;
5005 config.sampleRate        = 48000;
5006 config.dataCallback      = ma_data_callback;
5007 config.pMyUserData       = pMyUserData;
5008
5009 ma_device device;
5010 ma_result result = ma_device_init(NULL, &config, &device);
5011 if (result != MA_SUCCESS) {
5012     // Error
5013 }
5014 ```
5015
5016
5017 Example 2 - Advanced Initialization
5018 -----------------------------------
5019 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
5020 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
5021 enumeration.
5022
5023 ```c
5024 ma_context context;
5025 ma_result result = ma_context_init(NULL, 0, NULL, &context);
5026 if (result != MA_SUCCESS) {
5027     // Error
5028 }
5029
5030 ma_device_info* pPlaybackDeviceInfos;
5031 ma_uint32 playbackDeviceCount;
5032 result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL);
5033 if (result != MA_SUCCESS) {
5034     // Error
5035 }
5036
5037 // ... choose a device from pPlaybackDeviceInfos ...
5038
5039 ma_device_config config = ma_device_config_init(ma_device_type_playback);
5040 config.playback.pDeviceID       = pMyChosenDeviceID;    // <-- Get this from the `id` member of one of the `ma_device_info` objects returned by ma_context_get_devices().
5041 config.playback.format          = ma_format_f32;
5042 config.playback.channels        = 2;
5043 config.sampleRate               = 48000;
5044 config.dataCallback             = ma_data_callback;
5045 config.pUserData                = pMyUserData;
5046 config.periodSizeInMilliseconds = 10;
5047 config.periods                  = 3;
5048
5049 ma_device device;
5050 result = ma_device_init(&context, &config, &device);
5051 if (result != MA_SUCCESS) {
5052     // Error
5053 }
5054 ```
5055
5056
5057 See Also
5058 --------
5059 ma_device_config_init()
5060 ma_device_uninit()
5061 ma_device_start()
5062 ma_context_init()
5063 ma_context_get_devices()
5064 ma_context_enumerate_devices()
5065 */
5066 MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice);
5067
5068 /*
5069 Initializes a device without a context, with extra parameters for controlling the configuration of the internal self-managed context.
5070
5071 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
5072 allows you to configure the internally created context.
5073
5074
5075 Parameters
5076 ----------
5077 backends (in, optional)
5078     A list of backends to try initializing, in priority order. Can be NULL, in which case it uses default priority order.
5079
5080 backendCount (in, optional)
5081     The number of items in `backend`. Ignored if `backend` is NULL.
5082
5083 pContextConfig (in, optional)
5084     The context configuration.
5085
5086 pConfig (in)
5087     A pointer to the device configuration. Cannot be null. See remarks for details.
5088
5089 pDevice (out)
5090     A pointer to the device object being initialized.
5091
5092
5093 Return Value
5094 ------------
5095 MA_SUCCESS if successful; any other error code otherwise.
5096
5097
5098 Thread Safety
5099 -------------
5100 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
5101 calling this at the same time as `ma_device_uninit()`.
5102
5103
5104 Callback Safety
5105 ---------------
5106 Unsafe. It is not safe to call this inside any callback.
5107
5108
5109 Remarks
5110 -------
5111 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
5112 your own context.
5113
5114 See the documentation for `ma_context_init()` for information on the different context configuration options.
5115
5116
5117 See Also
5118 --------
5119 ma_device_init()
5120 ma_device_uninit()
5121 ma_device_config_init()
5122 ma_context_init()
5123 */
5124 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);
5125
5126 /*
5127 Uninitializes a device.
5128
5129 This will explicitly stop the device. You do not need to call `ma_device_stop()` beforehand, but it's harmless if you do.
5130
5131
5132 Parameters
5133 ----------
5134 pDevice (in)
5135     A pointer to the device to stop.
5136
5137
5138 Return Value
5139 ------------
5140 Nothing
5141
5142
5143 Thread Safety
5144 -------------
5145 Unsafe. As soon as this API is called the device should be considered undefined.
5146
5147
5148 Callback Safety
5149 ---------------
5150 Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
5151
5152
5153 See Also
5154 --------
5155 ma_device_init()
5156 ma_device_stop()
5157 */
5158 MA_API void ma_device_uninit(ma_device* pDevice);
5159
5160 /*
5161 Starts the device. For playback devices this begins playback. For capture devices it begins recording.
5162
5163 Use `ma_device_stop()` to stop the device.
5164
5165
5166 Parameters
5167 ----------
5168 pDevice (in)
5169     A pointer to the device to start.
5170
5171
5172 Return Value
5173 ------------
5174 MA_SUCCESS if successful; any other error code otherwise.
5175
5176
5177 Thread Safety
5178 -------------
5179 Safe. It's safe to call this from any thread with the exception of the callback thread.
5180
5181
5182 Callback Safety
5183 ---------------
5184 Unsafe. It is not safe to call this inside any callback.
5185
5186
5187 Remarks
5188 -------
5189 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
5190 audio data in the buffer, which needs to be done before the device begins playback.
5191
5192 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.
5193
5194 Do not call this in any callback.
5195
5196
5197 See Also
5198 --------
5199 ma_device_stop()
5200 */
5201 MA_API ma_result ma_device_start(ma_device* pDevice);
5202
5203 /*
5204 Stops the device. For playback devices this stops playback. For capture devices it stops recording.
5205
5206 Use `ma_device_start()` to start the device again.
5207
5208
5209 Parameters
5210 ----------
5211 pDevice (in)
5212     A pointer to the device to stop.
5213
5214
5215 Return Value
5216 ------------
5217 MA_SUCCESS if successful; any other error code otherwise.
5218
5219
5220 Thread Safety
5221 -------------
5222 Safe. It's safe to call this from any thread with the exception of the callback thread.
5223
5224
5225 Callback Safety
5226 ---------------
5227 Unsafe. It is not safe to call this inside any callback. Doing this will result in a deadlock.
5228
5229
5230 Remarks
5231 -------
5232 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
5233 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
5234 that was specified at initialization time).
5235
5236 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
5237 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
5238 speakers or received from the microphone which can in turn result in de-syncs.
5239
5240 Do not call this in any callback.
5241
5242 This will be called implicitly by `ma_device_uninit()`.
5243
5244
5245 See Also
5246 --------
5247 ma_device_start()
5248 */
5249 MA_API ma_result ma_device_stop(ma_device* pDevice);
5250
5251 /*
5252 Determines whether or not the device is started.
5253
5254
5255 Parameters
5256 ----------
5257 pDevice (in)
5258     A pointer to the device whose start state is being retrieved.
5259
5260
5261 Return Value
5262 ------------
5263 True if the device is started, false otherwise.
5264
5265
5266 Thread Safety
5267 -------------
5268 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
5269 value will be out of sync.
5270
5271
5272 Callback Safety
5273 ---------------
5274 Safe. This is implemented as a simple accessor.
5275
5276
5277 See Also
5278 --------
5279 ma_device_start()
5280 ma_device_stop()
5281 */
5282 MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice);
5283
5284
5285 /*
5286 Retrieves the state of the device.
5287
5288
5289 Parameters
5290 ----------
5291 pDevice (in)
5292     A pointer to the device whose state is being retrieved.
5293
5294
5295 Return Value
5296 ------------
5297 The current state of the device. The return value will be one of the following:
5298
5299     +------------------------+------------------------------------------------------------------------------+
5300     | MA_STATE_UNINITIALIZED | Will only be returned if the device is in the middle of initialization.      |
5301     +------------------------+------------------------------------------------------------------------------+
5302     | MA_STATE_STOPPED       | The device is stopped. The initial state of the device after initialization. |
5303     +------------------------+------------------------------------------------------------------------------+
5304     | MA_STATE_STARTED       | The device started and requesting and/or delivering audio data.              |
5305     +------------------------+------------------------------------------------------------------------------+
5306     | MA_STATE_STARTING      | The device is in the process of starting.                                    |
5307     +------------------------+------------------------------------------------------------------------------+
5308     | MA_STATE_STOPPING      | The device is in the process of stopping.                                    |
5309     +------------------------+------------------------------------------------------------------------------+
5310
5311
5312 Thread Safety
5313 -------------
5314 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,
5315 there's a possibility the return value could be out of sync. See remarks.
5316
5317
5318 Callback Safety
5319 ---------------
5320 Safe. This is implemented as a simple accessor.
5321
5322
5323 Remarks
5324 -------
5325 The general flow of a devices state goes like this:
5326
5327     ```
5328     ma_device_init()  -> MA_STATE_UNINITIALIZED -> MA_STATE_STOPPED
5329     ma_device_start() -> MA_STATE_STARTING      -> MA_STATE_STARTED
5330     ma_device_stop()  -> MA_STATE_STOPPING      -> MA_STATE_STOPPED
5331     ```
5332
5333 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
5334 value returned by this function could potentially be out of sync. If this is significant to your program you need to implement your own
5335 synchronization.
5336 */
5337 MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice);
5338
5339
5340 /*
5341 Sets the master volume factor for the device.
5342
5343 The volume factor must be between 0 (silence) and 1 (full volume). Use `ma_device_set_master_gain_db()` to use decibel notation, where 0 is full volume and
5344 values less than 0 decreases the volume.
5345
5346
5347 Parameters
5348 ----------
5349 pDevice (in)
5350     A pointer to the device whose volume is being set.
5351
5352 volume (in)
5353     The new volume factor. Must be within the range of [0, 1].
5354
5355
5356 Return Value
5357 ------------
5358 MA_SUCCESS if the volume was set successfully.
5359 MA_INVALID_ARGS if pDevice is NULL.
5360 MA_INVALID_ARGS if the volume factor is not within the range of [0, 1].
5361
5362
5363 Thread Safety
5364 -------------
5365 Safe. This just sets a local member of the device object.
5366
5367
5368 Callback Safety
5369 ---------------
5370 Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied.
5371
5372
5373 Remarks
5374 -------
5375 This applies the volume factor across all channels.
5376
5377 This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream.
5378
5379
5380 See Also
5381 --------
5382 ma_device_get_master_volume()
5383 ma_device_set_master_volume_gain_db()
5384 ma_device_get_master_volume_gain_db()
5385 */
5386 MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume);
5387
5388 /*
5389 Retrieves the master volume factor for the device.
5390
5391
5392 Parameters
5393 ----------
5394 pDevice (in)
5395     A pointer to the device whose volume factor is being retrieved.
5396
5397 pVolume (in)
5398     A pointer to the variable that will receive the volume factor. The returned value will be in the range of [0, 1].
5399
5400
5401 Return Value
5402 ------------
5403 MA_SUCCESS if successful.
5404 MA_INVALID_ARGS if pDevice is NULL.
5405 MA_INVALID_ARGS if pVolume is NULL.
5406
5407
5408 Thread Safety
5409 -------------
5410 Safe. This just a simple member retrieval.
5411
5412
5413 Callback Safety
5414 ---------------
5415 Safe.
5416
5417
5418 Remarks
5419 -------
5420 If an error occurs, `*pVolume` will be set to 0.
5421
5422
5423 See Also
5424 --------
5425 ma_device_set_master_volume()
5426 ma_device_set_master_volume_gain_db()
5427 ma_device_get_master_volume_gain_db()
5428 */
5429 MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume);
5430
5431 /*
5432 Sets the master volume for the device as gain in decibels.
5433
5434 A gain of 0 is full volume, whereas a gain of < 0 will decrease the volume.
5435
5436
5437 Parameters
5438 ----------
5439 pDevice (in)
5440     A pointer to the device whose gain is being set.
5441
5442 gainDB (in)
5443     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.
5444
5445
5446 Return Value
5447 ------------
5448 MA_SUCCESS if the volume was set successfully.
5449 MA_INVALID_ARGS if pDevice is NULL.
5450 MA_INVALID_ARGS if the gain is > 0.
5451
5452
5453 Thread Safety
5454 -------------
5455 Safe. This just sets a local member of the device object.
5456
5457
5458 Callback Safety
5459 ---------------
5460 Safe. If you set the volume in the data callback, that data written to the output buffer will have the new volume applied.
5461
5462
5463 Remarks
5464 -------
5465 This applies the gain across all channels.
5466
5467 This does not change the operating system's volume. It only affects the volume for the given `ma_device` object's audio stream.
5468
5469
5470 See Also
5471 --------
5472 ma_device_get_master_volume_gain_db()
5473 ma_device_set_master_volume()
5474 ma_device_get_master_volume()
5475 */
5476 MA_API ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB);
5477
5478 /*
5479 Retrieves the master gain in decibels.
5480
5481
5482 Parameters
5483 ----------
5484 pDevice (in)
5485     A pointer to the device whose gain is being retrieved.
5486
5487 pGainDB (in)
5488     A pointer to the variable that will receive the gain in decibels. The returned value will be <= 0.
5489
5490
5491 Return Value
5492 ------------
5493 MA_SUCCESS if successful.
5494 MA_INVALID_ARGS if pDevice is NULL.
5495 MA_INVALID_ARGS if pGainDB is NULL.
5496
5497
5498 Thread Safety
5499 -------------
5500 Safe. This just a simple member retrieval.
5501
5502
5503 Callback Safety
5504 ---------------
5505 Safe.
5506
5507
5508 Remarks
5509 -------
5510 If an error occurs, `*pGainDB` will be set to 0.
5511
5512
5513 See Also
5514 --------
5515 ma_device_set_master_volume_gain_db()
5516 ma_device_set_master_volume()
5517 ma_device_get_master_volume()
5518 */
5519 MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB);
5520
5521
5522 /*
5523 Called from the data callback of asynchronous backends to allow miniaudio to process the data and fire the miniaudio data callback.
5524
5525
5526 Parameters
5527 ----------
5528 pDevice (in)
5529     A pointer to device whose processing the data callback.
5530
5531 pOutput (out)
5532     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
5533     this can be NULL, in which case pInput must not be NULL.
5534
5535 pInput (in)
5536     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
5537     NULL, in which case `pOutput` must not be NULL.
5538
5539 frameCount (in)
5540     The number of frames being processed.
5541
5542
5543 Return Value
5544 ------------
5545 MA_SUCCESS if successful; any other result code otherwise.
5546
5547
5548 Thread Safety
5549 -------------
5550 This function should only ever be called from the internal data callback of the backend. It is safe to call this simultaneously between a
5551 playback and capture device in duplex setups.
5552
5553
5554 Callback Safety
5555 ---------------
5556 Do not call this from the miniaudio data callback. It should only ever be called from the internal data callback of the backend.
5557
5558
5559 Remarks
5560 -------
5561 If both `pOutput` and `pInput` are NULL, and error will be returned. In duplex scenarios, both `pOutput` and `pInput` can be non-NULL, in
5562 which case `pInput` will be processed first, followed by `pOutput`.
5563
5564 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
5565 callback.
5566 */
5567 MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
5568
5569
5570 /*
5571 Calculates an appropriate buffer size from a descriptor, native sample rate and performance profile.
5572
5573 This function is used by backends for helping determine an appropriately sized buffer to use with
5574 the device depending on the values of `periodSizeInFrames` and `periodSizeInMilliseconds` in the
5575 `pDescriptor` object. Since buffer size calculations based on time depends on the sample rate, a
5576 best guess at the device's native sample rate is also required which is where `nativeSampleRate`
5577 comes in. In addition, the performance profile is also needed for cases where both the period size
5578 in frames and milliseconds are both zero.
5579
5580
5581 Parameters
5582 ----------
5583 pDescriptor (in)
5584     A pointer to device descriptor whose `periodSizeInFrames` and `periodSizeInMilliseconds` members
5585     will be used for the calculation of the buffer size.
5586
5587 nativeSampleRate (in)
5588     The device's native sample rate. This is only ever used when the `periodSizeInFrames` member of
5589     `pDescriptor` is zero. In this case, `periodSizeInMilliseconds` will be used instead, in which
5590     case a sample rate is required to convert to a size in frames.
5591
5592 performanceProfile (in)
5593     When both the `periodSizeInFrames` and `periodSizeInMilliseconds` members of `pDescriptor` are
5594     zero, miniaudio will fall back to a buffer size based on the performance profile. The profile
5595     to use for this calculation is determine by this parameter.
5596
5597
5598 Return Value
5599 ------------
5600 The calculated buffer size in frames.
5601
5602
5603 Thread Safety
5604 -------------
5605 This is safe so long as nothing modifies `pDescriptor` at the same time. However, this function
5606 should only ever be called from within the backend's device initialization routine and therefore
5607 shouldn't have any multithreading concerns.
5608
5609
5610 Callback Safety
5611 ---------------
5612 This is safe to call within the data callback, but there is no reason to ever do this.
5613
5614
5615 Remarks
5616 -------
5617 If `nativeSampleRate` is zero, this function will fall back to `pDescriptor->sampleRate`. If that
5618 is also zero, `MA_DEFAULT_SAMPLE_RATE` will be used instead.
5619 */
5620 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile);
5621
5622
5623
5624 /*
5625 Retrieves a friendly name for a backend.
5626 */
5627 MA_API const char* ma_get_backend_name(ma_backend backend);
5628
5629 /*
5630 Determines whether or not the given backend is available by the compilation environment.
5631 */
5632 MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend);
5633
5634 /*
5635 Retrieves compile-time enabled backends.
5636
5637
5638 Parameters
5639 ----------
5640 pBackends (out, optional)
5641     A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting
5642     the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends.
5643
5644 backendCap (in)
5645     The capacity of the `pBackends` buffer.
5646
5647 pBackendCount (out)
5648     A pointer to the variable that will receive the enabled backend count.
5649
5650
5651 Return Value
5652 ------------
5653 MA_SUCCESS if successful.
5654 MA_INVALID_ARGS if `pBackendCount` is NULL.
5655 MA_NO_SPACE if the capacity of `pBackends` is not large enough.
5656
5657 If `MA_NO_SPACE` is returned, the `pBackends` buffer will be filled with `*pBackendCount` values.
5658
5659
5660 Thread Safety
5661 -------------
5662 Safe.
5663
5664
5665 Callback Safety
5666 ---------------
5667 Safe.
5668
5669
5670 Remarks
5671 -------
5672 If you want to retrieve the number of backends so you can determine the capacity of `pBackends` buffer, you can call
5673 this function with `pBackends` set to NULL.
5674
5675 This will also enumerate the null backend. If you don't want to include this you need to check for `ma_backend_null`
5676 when you enumerate over the returned backends and handle it appropriately. Alternatively, you can disable it at
5677 compile time with `MA_NO_NULL`.
5678
5679 The returned backends are determined based on compile time settings, not the platform it's currently running on. For
5680 example, PulseAudio will be returned if it was enabled at compile time, even when the user doesn't actually have
5681 PulseAudio installed.
5682
5683
5684 Example 1
5685 ---------
5686 The example below retrieves the enabled backend count using a fixed sized buffer allocated on the stack. The buffer is
5687 given a capacity of `MA_BACKEND_COUNT` which will guarantee it'll be large enough to store all available backends.
5688 Since `MA_BACKEND_COUNT` is always a relatively small value, this should be suitable for most scenarios.
5689
5690 ```
5691 ma_backend enabledBackends[MA_BACKEND_COUNT];
5692 size_t enabledBackendCount;
5693
5694 result = ma_get_enabled_backends(enabledBackends, MA_BACKEND_COUNT, &enabledBackendCount);
5695 if (result != MA_SUCCESS) {
5696     // Failed to retrieve enabled backends. Should never happen in this example since all inputs are valid.
5697 }
5698 ```
5699
5700
5701 See Also
5702 --------
5703 ma_is_backend_enabled()
5704 */
5705 MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount);
5706
5707 /*
5708 Determines whether or not loopback mode is support by a backend.
5709 */
5710 MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend);
5711
5712 #endif  /* MA_NO_DEVICE_IO */
5713
5714
5715 #ifndef MA_NO_THREADING
5716
5717 /*
5718 Locks a spinlock.
5719 */
5720 MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock);
5721
5722 /*
5723 Locks a spinlock, but does not yield() when looping.
5724 */
5725 MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock);
5726
5727 /*
5728 Unlocks a spinlock.
5729 */
5730 MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock);
5731
5732
5733 /*
5734 Creates a mutex.
5735
5736 A mutex must be created from a valid context. A mutex is initially unlocked.
5737 */
5738 MA_API ma_result ma_mutex_init(ma_mutex* pMutex);
5739
5740 /*
5741 Deletes a mutex.
5742 */
5743 MA_API void ma_mutex_uninit(ma_mutex* pMutex);
5744
5745 /*
5746 Locks a mutex with an infinite timeout.
5747 */
5748 MA_API void ma_mutex_lock(ma_mutex* pMutex);
5749
5750 /*
5751 Unlocks a mutex.
5752 */
5753 MA_API void ma_mutex_unlock(ma_mutex* pMutex);
5754
5755
5756 /*
5757 Initializes an auto-reset event.
5758 */
5759 MA_API ma_result ma_event_init(ma_event* pEvent);
5760
5761 /*
5762 Uninitializes an auto-reset event.
5763 */
5764 MA_API void ma_event_uninit(ma_event* pEvent);
5765
5766 /*
5767 Waits for the specified auto-reset event to become signalled.
5768 */
5769 MA_API ma_result ma_event_wait(ma_event* pEvent);
5770
5771 /*
5772 Signals the specified auto-reset event.
5773 */
5774 MA_API ma_result ma_event_signal(ma_event* pEvent);
5775 #endif  /* MA_NO_THREADING */
5776
5777
5778 /************************************************************************************************************************************************************
5779
5780 Utiltities
5781
5782 ************************************************************************************************************************************************************/
5783
5784 /*
5785 Adjust buffer size based on a scaling factor.
5786
5787 This just multiplies the base size by the scaling factor, making sure it's a size of at least 1.
5788 */
5789 MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale);
5790
5791 /*
5792 Calculates a buffer size in milliseconds from the specified number of frames and sample rate.
5793 */
5794 MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate);
5795
5796 /*
5797 Calculates a buffer size in frames from the specified number of milliseconds and sample rate.
5798 */
5799 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate);
5800
5801 /*
5802 Copies PCM frames from one buffer to another.
5803 */
5804 MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
5805
5806 /*
5807 Copies silent frames into the given buffer.
5808
5809 Remarks
5810 -------
5811 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
5812 makes more sense for the purpose of mixing to initialize it to the center point.
5813 */
5814 MA_API void ma_silence_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels);
5815 static MA_INLINE void ma_zero_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels) { ma_silence_pcm_frames(p, frameCount, format, channels); }
5816
5817
5818 /*
5819 Offsets a pointer by the specified number of PCM frames.
5820 */
5821 MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels);
5822 MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels);
5823 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); }
5824 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); }
5825
5826
5827 /*
5828 Clips f32 samples.
5829 */
5830 MA_API void ma_clip_samples_f32(float* p, ma_uint64 sampleCount);
5831 static MA_INLINE void ma_clip_pcm_frames_f32(float* p, ma_uint64 frameCount, ma_uint32 channels) { ma_clip_samples_f32(p, frameCount*channels); }
5832
5833 /*
5834 Helper for applying a volume factor to samples.
5835
5836 Note that the source and destination buffers can be the same, in which case it'll perform the operation in-place.
5837 */
5838 MA_API void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint64 sampleCount, float factor);
5839 MA_API void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint64 sampleCount, float factor);
5840 MA_API void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint64 sampleCount, float factor);
5841 MA_API void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint64 sampleCount, float factor);
5842 MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint64 sampleCount, float factor);
5843
5844 MA_API void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint64 sampleCount, float factor);
5845 MA_API void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint64 sampleCount, float factor);
5846 MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, float factor);
5847 MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor);
5848 MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor);
5849
5850 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
5851 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
5852 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
5853 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
5854 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor);
5855 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);
5856
5857 MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
5858 MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
5859 MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
5860 MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
5861 MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pFrames, ma_uint64 frameCount, ma_uint32 channels, float factor);
5862 MA_API void ma_apply_volume_factor_pcm_frames(void* pFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor);
5863
5864
5865 /*
5866 Helper for converting a linear factor to gain in decibels.
5867 */
5868 MA_API float ma_factor_to_gain_db(float factor);
5869
5870 /*
5871 Helper for converting gain in decibels to a linear factor.
5872 */
5873 MA_API float ma_gain_db_to_factor(float gain);
5874
5875
5876 typedef void ma_data_source;
5877
5878 typedef struct
5879 {
5880     ma_result (* onRead)(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
5881     ma_result (* onSeek)(ma_data_source* pDataSource, ma_uint64 frameIndex);
5882     ma_result (* onMap)(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount);   /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
5883     ma_result (* onUnmap)(ma_data_source* pDataSource, ma_uint64 frameCount);
5884     ma_result (* onGetDataFormat)(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate);
5885     ma_result (* onGetCursor)(ma_data_source* pDataSource, ma_uint64* pCursor);
5886     ma_result (* onGetLength)(ma_data_source* pDataSource, ma_uint64* pLength);
5887 } ma_data_source_callbacks;
5888
5889 MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop);   /* Must support pFramesOut = NULL in which case a forward seek should be performed. */
5890 MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */
5891 MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex);
5892 MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount);
5893 MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount);       /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
5894 MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate);
5895 MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor);
5896 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. */
5897
5898
5899
5900
5901 typedef struct
5902 {
5903     ma_data_source_callbacks ds;
5904     ma_format format;
5905     ma_uint32 channels;
5906     ma_uint64 cursor;
5907     ma_uint64 sizeInFrames;
5908     const void* pData;
5909 } ma_audio_buffer_ref;
5910
5911 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);
5912 MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames);
5913 MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop);
5914 MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex);
5915 MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount);
5916 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. */
5917 MA_API ma_result ma_audio_buffer_ref_at_end(ma_audio_buffer_ref* pAudioBufferRef);
5918 MA_API ma_result ma_audio_buffer_ref_get_available_frames(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames);
5919
5920
5921
5922 typedef struct
5923 {
5924     ma_format format;
5925     ma_uint32 channels;
5926     ma_uint64 sizeInFrames;
5927     const void* pData;  /* If set to NULL, will allocate a block of memory for you. */
5928     ma_allocation_callbacks allocationCallbacks;
5929 } ma_audio_buffer_config;
5930
5931 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);
5932
5933 typedef struct
5934 {
5935     ma_audio_buffer_ref ref;
5936     ma_allocation_callbacks allocationCallbacks;
5937     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(). */
5938     ma_uint8 _pExtraData[1];        /* For allocating a buffer with the memory located directly after the other memory of the structure. */
5939 } ma_audio_buffer;
5940
5941 MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer);
5942 MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer);
5943 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. */
5944 MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer);
5945 MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer);
5946 MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop);
5947 MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex);
5948 MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount);
5949 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. */
5950 MA_API ma_result ma_audio_buffer_at_end(ma_audio_buffer* pAudioBuffer);
5951 MA_API ma_result ma_audio_buffer_get_available_frames(ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames);
5952
5953
5954
5955 /************************************************************************************************************************************************************
5956
5957 VFS
5958 ===
5959
5960 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
5961 appropriate for a given situation.
5962
5963 ************************************************************************************************************************************************************/
5964 typedef void      ma_vfs;
5965 typedef ma_handle ma_vfs_file;
5966
5967 #define MA_OPEN_MODE_READ   0x00000001
5968 #define MA_OPEN_MODE_WRITE  0x00000002
5969
5970 typedef enum
5971 {
5972     ma_seek_origin_start,
5973     ma_seek_origin_current,
5974     ma_seek_origin_end  /* Not used by decoders. */
5975 } ma_seek_origin;
5976
5977 typedef struct
5978 {
5979     ma_uint64 sizeInBytes;
5980 } ma_file_info;
5981
5982 typedef struct
5983 {
5984     ma_result (* onOpen) (ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
5985     ma_result (* onOpenW)(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
5986     ma_result (* onClose)(ma_vfs* pVFS, ma_vfs_file file);
5987     ma_result (* onRead) (ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead);
5988     ma_result (* onWrite)(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten);
5989     ma_result (* onSeek) (ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin);
5990     ma_result (* onTell) (ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor);
5991     ma_result (* onInfo) (ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo);
5992 } ma_vfs_callbacks;
5993
5994 MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
5995 MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile);
5996 MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file);
5997 MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead);
5998 MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten);
5999 MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin);
6000 MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor);
6001 MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo);
6002 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);
6003
6004 typedef struct
6005 {
6006     ma_vfs_callbacks cb;
6007     ma_allocation_callbacks allocationCallbacks;    /* Only used for the wchar_t version of open() on non-Windows platforms. */
6008 } ma_default_vfs;
6009
6010 MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks);
6011
6012
6013
6014
6015 #if !defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)
6016 typedef enum
6017 {
6018     ma_resource_format_wav
6019 } ma_resource_format;
6020 #endif
6021
6022 /************************************************************************************************************************************************************
6023
6024 Decoding
6025 ========
6026
6027 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
6028 you do your own synchronization.
6029
6030 ************************************************************************************************************************************************************/
6031 #ifndef MA_NO_DECODING
6032 typedef struct ma_decoder ma_decoder;
6033
6034 typedef size_t    (* ma_decoder_read_proc)                    (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead);     /* Returns the number of bytes read. */
6035 typedef ma_bool32 (* ma_decoder_seek_proc)                    (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin);    /* Origin will never be ma_seek_origin_end. */
6036 typedef ma_uint64 (* ma_decoder_read_pcm_frames_proc)         (ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount);   /* Returns the number of frames read. Output data is in internal format. */
6037 typedef ma_result (* ma_decoder_seek_to_pcm_frame_proc)       (ma_decoder* pDecoder, ma_uint64 frameIndex);
6038 typedef ma_result (* ma_decoder_uninit_proc)                  (ma_decoder* pDecoder);
6039 typedef ma_uint64 (* ma_decoder_get_length_in_pcm_frames_proc)(ma_decoder* pDecoder);
6040
6041 typedef struct
6042 {
6043     ma_format format;      /* Set to 0 or ma_format_unknown to use the stream's internal format. */
6044     ma_uint32 channels;    /* Set to 0 to use the stream's internal channels. */
6045     ma_uint32 sampleRate;  /* Set to 0 to use the stream's internal sample rate. */
6046     ma_channel channelMap[MA_MAX_CHANNELS];
6047     ma_channel_mix_mode channelMixMode;
6048     ma_dither_mode ditherMode;
6049     struct
6050     {
6051         ma_resample_algorithm algorithm;
6052         struct
6053         {
6054             ma_uint32 lpfOrder;
6055         } linear;
6056         struct
6057         {
6058             int quality;
6059         } speex;
6060     } resampling;
6061     ma_allocation_callbacks allocationCallbacks;
6062 } ma_decoder_config;
6063
6064 struct ma_decoder
6065 {
6066     ma_data_source_callbacks ds;
6067     ma_decoder_read_proc onRead;
6068     ma_decoder_seek_proc onSeek;
6069     void* pUserData;
6070     ma_uint64  readPointerInBytes;          /* In internal encoded data. */
6071     ma_uint64  readPointerInPCMFrames;      /* In output sample rate. Used for keeping track of how many frames are available for decoding. */
6072     ma_format  internalFormat;
6073     ma_uint32  internalChannels;
6074     ma_uint32  internalSampleRate;
6075     ma_channel internalChannelMap[MA_MAX_CHANNELS];
6076     ma_format  outputFormat;
6077     ma_uint32  outputChannels;
6078     ma_uint32  outputSampleRate;
6079     ma_channel outputChannelMap[MA_MAX_CHANNELS];
6080     ma_data_converter converter;   /* <-- Data conversion is achieved by running frames through this. */
6081     ma_allocation_callbacks allocationCallbacks;
6082     ma_decoder_read_pcm_frames_proc onReadPCMFrames;
6083     ma_decoder_seek_to_pcm_frame_proc onSeekToPCMFrame;
6084     ma_decoder_uninit_proc onUninit;
6085     ma_decoder_get_length_in_pcm_frames_proc onGetLengthInPCMFrames;
6086     void* pInternalDecoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
6087     union
6088     {
6089         struct
6090         {
6091             ma_vfs* pVFS;
6092             ma_vfs_file file;
6093         } vfs;
6094         struct
6095         {
6096             const ma_uint8* pData;
6097             size_t dataSize;
6098             size_t currentReadPos;
6099         } memory;               /* Only used for decoders that were opened against a block of memory. */
6100     } backend;
6101 };
6102
6103 MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate);
6104
6105 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);
6106 MA_API ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6107 MA_API ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6108 MA_API ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6109 MA_API ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6110 MA_API ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder);
6111
6112 MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6113 MA_API ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6114 MA_API ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6115 MA_API ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6116 MA_API ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6117 MA_API ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder);
6118
6119 MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6120 MA_API ma_result ma_decoder_init_vfs_wav(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6121 MA_API ma_result ma_decoder_init_vfs_flac(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6122 MA_API ma_result ma_decoder_init_vfs_mp3(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6123 MA_API ma_result ma_decoder_init_vfs_vorbis(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6124
6125 MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6126 MA_API ma_result ma_decoder_init_vfs_wav_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6127 MA_API ma_result ma_decoder_init_vfs_flac_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6128 MA_API ma_result ma_decoder_init_vfs_mp3_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6129 MA_API ma_result ma_decoder_init_vfs_vorbis_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6130
6131 MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6132 MA_API ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6133 MA_API ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6134 MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6135 MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6136
6137 MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6138 MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6139 MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6140 MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6141 MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder);
6142
6143 MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder);
6144
6145 /*
6146 Retrieves the current position of the read cursor in PCM frames.
6147 */
6148 MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor);
6149
6150 /*
6151 Retrieves the length of the decoder in PCM frames.
6152
6153 Do not call this on streams of an undefined length, such as internet radio.
6154
6155 If the length is unknown or an error occurs, 0 will be returned.
6156
6157 This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio
6158 uses internally.
6159
6160 For MP3's, this will decode the entire file. Do not call this in time critical scenarios.
6161
6162 This function is not thread safe without your own synchronization.
6163 */
6164 MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder);
6165
6166 /*
6167 Reads PCM frames from the given decoder.
6168
6169 This is not thread safe without your own synchronization.
6170 */
6171 MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount);
6172
6173 /*
6174 Seeks to a PCM frame based on it's absolute index.
6175
6176 This is not thread safe without your own synchronization.
6177 */
6178 MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex);
6179
6180 /*
6181 Retrieves the number of frames that can be read before reaching the end.
6182
6183 This calls `ma_decoder_get_length_in_pcm_frames()` so you need to be aware of the rules for that function, in
6184 particular ensuring you do not call it on streams of an undefined length, such as internet radio.
6185
6186 If the total length of the decoder cannot be retrieved, such as with Vorbis decoders, `MA_NOT_IMPLEMENTED` will be
6187 returned.
6188 */
6189 MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames);
6190
6191 /*
6192 Helper for opening and decoding a file into a heap allocated block of memory. Free the returned pointer with ma_free(). On input,
6193 pConfig should be set to what you want. On output it will be set to what you got.
6194 */
6195 MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
6196 MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
6197 MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut);
6198
6199 #endif  /* MA_NO_DECODING */
6200
6201
6202 /************************************************************************************************************************************************************
6203
6204 Encoding
6205 ========
6206
6207 Encoders do not perform any format conversion for you. If your target format does not support the format, and error will be returned.
6208
6209 ************************************************************************************************************************************************************/
6210 #ifndef MA_NO_ENCODING
6211 typedef struct ma_encoder ma_encoder;
6212
6213 typedef size_t    (* ma_encoder_write_proc)           (ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite);     /* Returns the number of bytes written. */
6214 typedef ma_bool32 (* ma_encoder_seek_proc)            (ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin);
6215 typedef ma_result (* ma_encoder_init_proc)            (ma_encoder* pEncoder);
6216 typedef void      (* ma_encoder_uninit_proc)          (ma_encoder* pEncoder);
6217 typedef ma_uint64 (* ma_encoder_write_pcm_frames_proc)(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount);
6218
6219 typedef struct
6220 {
6221     ma_resource_format resourceFormat;
6222     ma_format format;
6223     ma_uint32 channels;
6224     ma_uint32 sampleRate;
6225     ma_allocation_callbacks allocationCallbacks;
6226 } ma_encoder_config;
6227
6228 MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate);
6229
6230 struct ma_encoder
6231 {
6232     ma_encoder_config config;
6233     ma_encoder_write_proc onWrite;
6234     ma_encoder_seek_proc onSeek;
6235     ma_encoder_init_proc onInit;
6236     ma_encoder_uninit_proc onUninit;
6237     ma_encoder_write_pcm_frames_proc onWritePCMFrames;
6238     void* pUserData;
6239     void* pInternalEncoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
6240     void* pFile;    /* FILE*. Only used when initialized with ma_encoder_init_file(). */
6241 };
6242
6243 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);
6244 MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
6245 MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder);
6246 MA_API void ma_encoder_uninit(ma_encoder* pEncoder);
6247 MA_API ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount);
6248
6249 #endif /* MA_NO_ENCODING */
6250
6251
6252 /************************************************************************************************************************************************************
6253
6254 Generation
6255
6256 ************************************************************************************************************************************************************/
6257 #ifndef MA_NO_GENERATION
6258 typedef enum
6259 {
6260     ma_waveform_type_sine,
6261     ma_waveform_type_square,
6262     ma_waveform_type_triangle,
6263     ma_waveform_type_sawtooth
6264 } ma_waveform_type;
6265
6266 typedef struct
6267 {
6268     ma_format format;
6269     ma_uint32 channels;
6270     ma_uint32 sampleRate;
6271     ma_waveform_type type;
6272     double amplitude;
6273     double frequency;
6274 } ma_waveform_config;
6275
6276 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);
6277
6278 typedef struct
6279 {
6280     ma_data_source_callbacks ds;
6281     ma_waveform_config config;
6282     double advance;
6283     double time;
6284 } ma_waveform;
6285
6286 MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform);
6287 MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount);
6288 MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex);
6289 MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude);
6290 MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency);
6291 MA_API ma_result ma_waveform_set_type(ma_waveform* pWaveform, ma_waveform_type type);
6292 MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate);
6293
6294 typedef enum
6295 {
6296     ma_noise_type_white,
6297     ma_noise_type_pink,
6298     ma_noise_type_brownian
6299 } ma_noise_type;
6300
6301 typedef struct
6302 {
6303     ma_format format;
6304     ma_uint32 channels;
6305     ma_noise_type type;
6306     ma_int32 seed;
6307     double amplitude;
6308     ma_bool32 duplicateChannels;
6309 } ma_noise_config;
6310
6311 MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude);
6312
6313 typedef struct
6314 {
6315     ma_data_source_callbacks ds;
6316     ma_noise_config config;
6317     ma_lcg lcg;
6318     union
6319     {
6320         struct
6321         {
6322             double bin[MA_MAX_CHANNELS][16];
6323             double accumulation[MA_MAX_CHANNELS];
6324             ma_uint32 counter[MA_MAX_CHANNELS];
6325         } pink;
6326         struct
6327         {
6328             double accumulation[MA_MAX_CHANNELS];
6329         } brownian;
6330     } state;
6331 } ma_noise;
6332
6333 MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise);
6334 MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount);
6335 MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude);
6336 MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed);
6337 MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type);
6338
6339 #endif  /* MA_NO_GENERATION */
6340
6341 #ifdef __cplusplus
6342 }
6343 #endif
6344 #endif  /* miniaudio_h */
6345
6346
6347
6348 /************************************************************************************************************************************************************
6349 *************************************************************************************************************************************************************
6350
6351 IMPLEMENTATION
6352
6353 *************************************************************************************************************************************************************
6354 ************************************************************************************************************************************************************/
6355 #if defined(MINIAUDIO_IMPLEMENTATION) || defined(MA_IMPLEMENTATION)
6356 #ifndef miniaudio_c
6357 #define miniaudio_c
6358
6359 #include <assert.h>
6360 #include <limits.h> /* For INT_MAX */
6361 #include <math.h>   /* sin(), etc. */
6362
6363 #include <stdarg.h>
6364 #include <stdio.h>
6365 #if !defined(_MSC_VER) && !defined(__DMC__)
6366     #include <strings.h>    /* For strcasecmp(). */
6367     #include <wchar.h>      /* For wcslen(), wcsrtombs() */
6368 #endif
6369
6370 #ifdef MA_WIN32
6371 #include <windows.h>
6372 #else
6373 #include <stdlib.h>     /* For malloc(), free(), wcstombs(). */
6374 #include <string.h>     /* For memset() */
6375 #include <sched.h>
6376 #include <sys/time.h>   /* select() (used for ma_sleep()). */
6377 #endif
6378
6379 #include <sys/stat.h>   /* For fstat(), etc. */
6380
6381 #ifdef MA_EMSCRIPTEN
6382 #include <emscripten/emscripten.h>
6383 #endif
6384
6385 #if !defined(MA_64BIT) && !defined(MA_32BIT)
6386 #ifdef _WIN32
6387 #ifdef _WIN64
6388 #define MA_64BIT
6389 #else
6390 #define MA_32BIT
6391 #endif
6392 #endif
6393 #endif
6394
6395 #if !defined(MA_64BIT) && !defined(MA_32BIT)
6396 #ifdef __GNUC__
6397 #ifdef __LP64__
6398 #define MA_64BIT
6399 #else
6400 #define MA_32BIT
6401 #endif
6402 #endif
6403 #endif
6404
6405 #if !defined(MA_64BIT) && !defined(MA_32BIT)
6406 #include <stdint.h>
6407 #if INTPTR_MAX == INT64_MAX
6408 #define MA_64BIT
6409 #else
6410 #define MA_32BIT
6411 #endif
6412 #endif
6413
6414 /* Architecture Detection */
6415 #if defined(__x86_64__) || defined(_M_X64)
6416 #define MA_X64
6417 #elif defined(__i386) || defined(_M_IX86)
6418 #define MA_X86
6419 #elif defined(__arm__) || defined(_M_ARM)
6420 #define MA_ARM
6421 #endif
6422
6423 /* Cannot currently support AVX-512 if AVX is disabled. */
6424 #if !defined(MA_NO_AVX512) && defined(MA_NO_AVX2)
6425 #define MA_NO_AVX512
6426 #endif
6427
6428 /* Intrinsics Support */
6429 #if defined(MA_X64) || defined(MA_X86)
6430     #if defined(_MSC_VER) && !defined(__clang__)
6431         /* MSVC. */
6432         #if _MSC_VER >= 1400 && !defined(MA_NO_SSE2)   /* 2005 */
6433             #define MA_SUPPORT_SSE2
6434         #endif
6435         /*#if _MSC_VER >= 1600 && !defined(MA_NO_AVX)*/    /* 2010 */
6436         /*    #define MA_SUPPORT_AVX*/
6437         /*#endif*/
6438         #if _MSC_VER >= 1700 && !defined(MA_NO_AVX2)   /* 2012 */
6439             #define MA_SUPPORT_AVX2
6440         #endif
6441         #if _MSC_VER >= 1910 && !defined(MA_NO_AVX512) /* 2017 */
6442             #define MA_SUPPORT_AVX512
6443         #endif
6444     #else
6445         /* Assume GNUC-style. */
6446         #if defined(__SSE2__) && !defined(MA_NO_SSE2)
6447             #define MA_SUPPORT_SSE2
6448         #endif
6449         /*#if defined(__AVX__) && !defined(MA_NO_AVX)*/
6450         /*    #define MA_SUPPORT_AVX*/
6451         /*#endif*/
6452         #if defined(__AVX2__) && !defined(MA_NO_AVX2)
6453             #define MA_SUPPORT_AVX2
6454         #endif
6455         #if defined(__AVX512F__) && !defined(MA_NO_AVX512)
6456             #define MA_SUPPORT_AVX512
6457         #endif
6458     #endif
6459
6460     /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */
6461     #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
6462         #if !defined(MA_SUPPORT_SSE2)   && !defined(MA_NO_SSE2)   && __has_include(<emmintrin.h>)
6463             #define MA_SUPPORT_SSE2
6464         #endif
6465         /*#if !defined(MA_SUPPORT_AVX)    && !defined(MA_NO_AVX)    && __has_include(<immintrin.h>)*/
6466         /*    #define MA_SUPPORT_AVX*/
6467         /*#endif*/
6468         #if !defined(MA_SUPPORT_AVX2)   && !defined(MA_NO_AVX2)   && __has_include(<immintrin.h>)
6469             #define MA_SUPPORT_AVX2
6470         #endif
6471         #if !defined(MA_SUPPORT_AVX512) && !defined(MA_NO_AVX512) && __has_include(<zmmintrin.h>)
6472             #define MA_SUPPORT_AVX512
6473         #endif
6474     #endif
6475
6476     #if defined(MA_SUPPORT_AVX512)
6477         #include <immintrin.h>  /* Not a mistake. Intentionally including <immintrin.h> instead of <zmmintrin.h> because otherwise the compiler will complain. */
6478     #elif defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX)
6479         #include <immintrin.h>
6480     #elif defined(MA_SUPPORT_SSE2)
6481         #include <emmintrin.h>
6482     #endif
6483 #endif
6484
6485 #if defined(MA_ARM)
6486     #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
6487         #define MA_SUPPORT_NEON
6488     #endif
6489
6490     /* Fall back to looking for the #include file. */
6491     #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
6492         #if !defined(MA_SUPPORT_NEON) && !defined(MA_NO_NEON) && __has_include(<arm_neon.h>)
6493             #define MA_SUPPORT_NEON
6494         #endif
6495     #endif
6496
6497     #if defined(MA_SUPPORT_NEON)
6498         #include <arm_neon.h>
6499     #endif
6500 #endif
6501
6502 /* Begin globally disabled warnings. */
6503 #if defined(_MSC_VER)
6504     #pragma warning(push)
6505     #pragma warning(disable:4752)   /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */
6506 #endif
6507
6508 #if defined(MA_X64) || defined(MA_X86)
6509     #if defined(_MSC_VER) && !defined(__clang__)
6510         #if _MSC_VER >= 1400
6511             #include <intrin.h>
6512             static MA_INLINE void ma_cpuid(int info[4], int fid)
6513             {
6514                 __cpuid(info, fid);
6515             }
6516         #else
6517             #define MA_NO_CPUID
6518         #endif
6519
6520         #if _MSC_VER >= 1600 && (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219)
6521             static MA_INLINE unsigned __int64 ma_xgetbv(int reg)
6522             {
6523                 return _xgetbv(reg);
6524             }
6525         #else
6526             #define MA_NO_XGETBV
6527         #endif
6528     #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID)
6529         static MA_INLINE void ma_cpuid(int info[4], int fid)
6530         {
6531             /*
6532             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
6533             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
6534             supporting different assembly dialects.
6535
6536             What's basically happening is that we're saving and restoring the ebx register manually.
6537             */
6538             #if defined(DRFLAC_X86) && defined(__PIC__)
6539                 __asm__ __volatile__ (
6540                     "xchg{l} {%%}ebx, %k1;"
6541                     "cpuid;"
6542                     "xchg{l} {%%}ebx, %k1;"
6543                     : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
6544                 );
6545             #else
6546                 __asm__ __volatile__ (
6547                     "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
6548                 );
6549             #endif
6550         }
6551
6552         static MA_INLINE ma_uint64 ma_xgetbv(int reg)
6553         {
6554             unsigned int hi;
6555             unsigned int lo;
6556
6557             __asm__ __volatile__ (
6558                 "xgetbv" : "=a"(lo), "=d"(hi) : "c"(reg)
6559             );
6560
6561             return ((ma_uint64)hi << 32) | (ma_uint64)lo;
6562         }
6563     #else
6564         #define MA_NO_CPUID
6565         #define MA_NO_XGETBV
6566     #endif
6567 #else
6568     #define MA_NO_CPUID
6569     #define MA_NO_XGETBV
6570 #endif
6571
6572 static MA_INLINE ma_bool32 ma_has_sse2(void)
6573 {
6574 #if defined(MA_SUPPORT_SSE2)
6575     #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_SSE2)
6576         #if defined(MA_X64)
6577             return MA_TRUE;    /* 64-bit targets always support SSE2. */
6578         #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
6579             return MA_TRUE;    /* If the compiler is allowed to freely generate SSE2 code we can assume support. */
6580         #else
6581             #if defined(MA_NO_CPUID)
6582                 return MA_FALSE;
6583             #else
6584                 int info[4];
6585                 ma_cpuid(info, 1);
6586                 return (info[3] & (1 << 26)) != 0;
6587             #endif
6588         #endif
6589     #else
6590         return MA_FALSE;       /* SSE2 is only supported on x86 and x64 architectures. */
6591     #endif
6592 #else
6593     return MA_FALSE;           /* No compiler support. */
6594 #endif
6595 }
6596
6597 #if 0
6598 static MA_INLINE ma_bool32 ma_has_avx()
6599 {
6600 #if defined(MA_SUPPORT_AVX)
6601     #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX)
6602         #if defined(_AVX_) || defined(__AVX__)
6603             return MA_TRUE;    /* If the compiler is allowed to freely generate AVX code we can assume support. */
6604         #else
6605             /* AVX requires both CPU and OS support. */
6606             #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
6607                 return MA_FALSE;
6608             #else
6609                 int info[4];
6610                 ma_cpuid(info, 1);
6611                 if (((info[2] & (1 << 27)) != 0) && ((info[2] & (1 << 28)) != 0)) {
6612                     ma_uint64 xrc = ma_xgetbv(0);
6613                     if ((xrc & 0x06) == 0x06) {
6614                         return MA_TRUE;
6615                     } else {
6616                         return MA_FALSE;
6617                     }
6618                 } else {
6619                     return MA_FALSE;
6620                 }
6621             #endif
6622         #endif
6623     #else
6624         return MA_FALSE;       /* AVX is only supported on x86 and x64 architectures. */
6625     #endif
6626 #else
6627     return MA_FALSE;           /* No compiler support. */
6628 #endif
6629 }
6630 #endif
6631
6632 static MA_INLINE ma_bool32 ma_has_avx2(void)
6633 {
6634 #if defined(MA_SUPPORT_AVX2)
6635     #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX2)
6636         #if defined(_AVX2_) || defined(__AVX2__)
6637             return MA_TRUE;    /* If the compiler is allowed to freely generate AVX2 code we can assume support. */
6638         #else
6639             /* AVX2 requires both CPU and OS support. */
6640             #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
6641                 return MA_FALSE;
6642             #else
6643                 int info1[4];
6644                 int info7[4];
6645                 ma_cpuid(info1, 1);
6646                 ma_cpuid(info7, 7);
6647                 if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 5)) != 0)) {
6648                     ma_uint64 xrc = ma_xgetbv(0);
6649                     if ((xrc & 0x06) == 0x06) {
6650                         return MA_TRUE;
6651                     } else {
6652                         return MA_FALSE;
6653                     }
6654                 } else {
6655                     return MA_FALSE;
6656                 }
6657             #endif
6658         #endif
6659     #else
6660         return MA_FALSE;       /* AVX2 is only supported on x86 and x64 architectures. */
6661     #endif
6662 #else
6663     return MA_FALSE;           /* No compiler support. */
6664 #endif
6665 }
6666
6667 static MA_INLINE ma_bool32 ma_has_avx512f(void)
6668 {
6669 #if defined(MA_SUPPORT_AVX512)
6670     #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_AVX512)
6671         #if defined(__AVX512F__)
6672             return MA_TRUE;    /* If the compiler is allowed to freely generate AVX-512F code we can assume support. */
6673         #else
6674             /* AVX-512 requires both CPU and OS support. */
6675             #if defined(MA_NO_CPUID) || defined(MA_NO_XGETBV)
6676                 return MA_FALSE;
6677             #else
6678                 int info1[4];
6679                 int info7[4];
6680                 ma_cpuid(info1, 1);
6681                 ma_cpuid(info7, 7);
6682                 if (((info1[2] & (1 << 27)) != 0) && ((info7[1] & (1 << 16)) != 0)) {
6683                     ma_uint64 xrc = ma_xgetbv(0);
6684                     if ((xrc & 0xE6) == 0xE6) {
6685                         return MA_TRUE;
6686                     } else {
6687                         return MA_FALSE;
6688                     }
6689                 } else {
6690                     return MA_FALSE;
6691                 }
6692             #endif
6693         #endif
6694     #else
6695         return MA_FALSE;       /* AVX-512F is only supported on x86 and x64 architectures. */
6696     #endif
6697 #else
6698     return MA_FALSE;           /* No compiler support. */
6699 #endif
6700 }
6701
6702 static MA_INLINE ma_bool32 ma_has_neon(void)
6703 {
6704 #if defined(MA_SUPPORT_NEON)
6705     #if defined(MA_ARM) && !defined(MA_NO_NEON)
6706         #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
6707             return MA_TRUE;    /* If the compiler is allowed to freely generate NEON code we can assume support. */
6708         #else
6709             /* TODO: Runtime check. */
6710             return MA_FALSE;
6711         #endif
6712     #else
6713         return MA_FALSE;       /* NEON is only supported on ARM architectures. */
6714     #endif
6715 #else
6716     return MA_FALSE;           /* No compiler support. */
6717 #endif
6718 }
6719
6720 #define MA_SIMD_NONE    0
6721 #define MA_SIMD_SSE2    1
6722 #define MA_SIMD_AVX2    2
6723 #define MA_SIMD_NEON    3
6724
6725 #ifndef MA_PREFERRED_SIMD
6726     #  if defined(MA_SUPPORT_SSE2) && defined(MA_PREFER_SSE2)
6727         #define MA_PREFERRED_SIMD MA_SIMD_SSE2
6728     #elif defined(MA_SUPPORT_AVX2) && defined(MA_PREFER_AVX2)
6729         #define MA_PREFERRED_SIMD MA_SIMD_AVX2
6730     #elif defined(MA_SUPPORT_NEON) && defined(MA_PREFER_NEON)
6731         #define MA_PREFERRED_SIMD MA_SIMD_NEON
6732     #else
6733         #define MA_PREFERRED_SIMD MA_SIMD_NONE
6734     #endif
6735 #endif
6736
6737 #if defined(__has_builtin)
6738     #define MA_COMPILER_HAS_BUILTIN(x) __has_builtin(x)
6739 #else
6740     #define MA_COMPILER_HAS_BUILTIN(x) 0
6741 #endif
6742
6743 #ifndef MA_ASSUME
6744     #if MA_COMPILER_HAS_BUILTIN(__builtin_assume)
6745         #define MA_ASSUME(x) __builtin_assume(x)
6746     #elif MA_COMPILER_HAS_BUILTIN(__builtin_unreachable)
6747         #define MA_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
6748     #elif defined(_MSC_VER)
6749         #define MA_ASSUME(x) __assume(x)
6750     #else
6751         #define MA_ASSUME(x) while(0)
6752     #endif
6753 #endif
6754
6755 #ifndef MA_RESTRICT
6756     #if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
6757         #define MA_RESTRICT __restrict
6758     #else
6759         #define MA_RESTRICT
6760     #endif
6761 #endif
6762
6763 #if defined(_MSC_VER) && _MSC_VER >= 1400
6764     #define MA_HAS_BYTESWAP16_INTRINSIC
6765     #define MA_HAS_BYTESWAP32_INTRINSIC
6766     #define MA_HAS_BYTESWAP64_INTRINSIC
6767 #elif defined(__clang__)
6768     #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap16)
6769         #define MA_HAS_BYTESWAP16_INTRINSIC
6770     #endif
6771     #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap32)
6772         #define MA_HAS_BYTESWAP32_INTRINSIC
6773     #endif
6774     #if MA_COMPILER_HAS_BUILTIN(__builtin_bswap64)
6775         #define MA_HAS_BYTESWAP64_INTRINSIC
6776     #endif
6777 #elif defined(__GNUC__)
6778     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
6779         #define MA_HAS_BYTESWAP32_INTRINSIC
6780         #define MA_HAS_BYTESWAP64_INTRINSIC
6781     #endif
6782     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
6783         #define MA_HAS_BYTESWAP16_INTRINSIC
6784     #endif
6785 #endif
6786
6787
6788 static MA_INLINE ma_bool32 ma_is_little_endian(void)
6789 {
6790 #if defined(MA_X86) || defined(MA_X64)
6791     return MA_TRUE;
6792 #else
6793     int n = 1;
6794     return (*(char*)&n) == 1;
6795 #endif
6796 }
6797
6798 static MA_INLINE ma_bool32 ma_is_big_endian(void)
6799 {
6800     return !ma_is_little_endian();
6801 }
6802
6803
6804 static MA_INLINE ma_uint32 ma_swap_endian_uint32(ma_uint32 n)
6805 {
6806 #ifdef MA_HAS_BYTESWAP32_INTRINSIC
6807     #if defined(_MSC_VER)
6808         return _byteswap_ulong(n);
6809     #elif defined(__GNUC__) || defined(__clang__)
6810         #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. */
6811             /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
6812             ma_uint32 r;
6813             __asm__ __volatile__ (
6814             #if defined(MA_64BIT)
6815                 "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! */
6816             #else
6817                 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
6818             #endif
6819             );
6820             return r;
6821         #else
6822             return __builtin_bswap32(n);
6823         #endif
6824     #else
6825         #error "This compiler does not support the byte swap intrinsic."
6826     #endif
6827 #else
6828     return ((n & 0xFF000000) >> 24) |
6829            ((n & 0x00FF0000) >>  8) |
6830            ((n & 0x0000FF00) <<  8) |
6831            ((n & 0x000000FF) << 24);
6832 #endif
6833 }
6834
6835
6836 #if !defined(MA_EMSCRIPTEN)
6837 #ifdef MA_WIN32
6838 static void ma_sleep__win32(ma_uint32 milliseconds)
6839 {
6840     Sleep((DWORD)milliseconds);
6841 }
6842 #endif
6843 #ifdef MA_POSIX
6844 static void ma_sleep__posix(ma_uint32 milliseconds)
6845 {
6846 #ifdef MA_EMSCRIPTEN
6847     (void)milliseconds;
6848     MA_ASSERT(MA_FALSE);  /* The Emscripten build should never sleep. */
6849 #else
6850     #if _POSIX_C_SOURCE >= 199309L
6851         struct timespec ts;
6852         ts.tv_sec  = milliseconds / 1000;
6853         ts.tv_nsec = milliseconds % 1000 * 1000000;
6854         nanosleep(&ts, NULL);
6855     #else
6856         struct timeval tv;
6857         tv.tv_sec  = milliseconds / 1000;
6858         tv.tv_usec = milliseconds % 1000 * 1000;
6859         select(0, NULL, NULL, NULL, &tv);
6860     #endif
6861 #endif
6862 }
6863 #endif
6864
6865 static void ma_sleep(ma_uint32 milliseconds)
6866 {
6867 #ifdef MA_WIN32
6868     ma_sleep__win32(milliseconds);
6869 #endif
6870 #ifdef MA_POSIX
6871     ma_sleep__posix(milliseconds);
6872 #endif
6873 }
6874 #endif
6875
6876 static MA_INLINE void ma_yield()
6877 {
6878 #if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
6879     /* x86/x64 */
6880     #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(__clang__)
6881         #if _MSC_VER >= 1400
6882             _mm_pause();
6883         #else
6884             #if defined(__DMC__)
6885                 /* Digital Mars does not recognize the PAUSE opcode. Fall back to NOP. */
6886                 __asm nop;  
6887             #else
6888                 __asm pause;
6889             #endif
6890         #endif
6891     #else
6892         __asm__ __volatile__ ("pause");
6893     #endif
6894 #elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
6895     /* ARM */
6896     #if defined(_MSC_VER)
6897         /* 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. */
6898         __yield();
6899     #else
6900         __asm__ __volatile__ ("yield"); /* ARMv6K/ARMv6T2 and above. */
6901     #endif
6902 #else
6903     /* Unknown or unsupported architecture. No-op. */
6904 #endif
6905 }
6906
6907
6908
6909 #ifndef MA_COINIT_VALUE
6910 #define MA_COINIT_VALUE    0   /* 0 = COINIT_MULTITHREADED */
6911 #endif
6912
6913
6914 #ifndef MA_FLT_MAX
6915     #ifdef FLT_MAX
6916         #define MA_FLT_MAX FLT_MAX
6917     #else
6918         #define MA_FLT_MAX 3.402823466e+38F
6919     #endif
6920 #endif
6921
6922
6923 #ifndef MA_PI
6924 #define MA_PI      3.14159265358979323846264f
6925 #endif
6926 #ifndef MA_PI_D
6927 #define MA_PI_D    3.14159265358979323846264
6928 #endif
6929 #ifndef MA_TAU
6930 #define MA_TAU     6.28318530717958647693f
6931 #endif
6932 #ifndef MA_TAU_D
6933 #define MA_TAU_D   6.28318530717958647693
6934 #endif
6935
6936
6937 /* The default format when ma_format_unknown (0) is requested when initializing a device. */
6938 #ifndef MA_DEFAULT_FORMAT
6939 #define MA_DEFAULT_FORMAT                                   ma_format_f32
6940 #endif
6941
6942 /* The default channel count to use when 0 is used when initializing a device. */
6943 #ifndef MA_DEFAULT_CHANNELS
6944 #define MA_DEFAULT_CHANNELS                                 2
6945 #endif
6946
6947 /* The default sample rate to use when 0 is used when initializing a device. */
6948 #ifndef MA_DEFAULT_SAMPLE_RATE
6949 #define MA_DEFAULT_SAMPLE_RATE                              48000
6950 #endif
6951
6952 /* Default periods when none is specified in ma_device_init(). More periods means more work on the CPU. */
6953 #ifndef MA_DEFAULT_PERIODS
6954 #define MA_DEFAULT_PERIODS                                  3
6955 #endif
6956
6957 /* The default period size in milliseconds for low latency mode. */
6958 #ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY
6959 #define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY  10
6960 #endif
6961
6962 /* The default buffer size in milliseconds for conservative mode. */
6963 #ifndef MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE
6964 #define MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE 100
6965 #endif
6966
6967 /* The default LPF filter order for linear resampling. Note that this is clamped to MA_MAX_FILTER_ORDER. */
6968 #ifndef MA_DEFAULT_RESAMPLER_LPF_ORDER
6969     #if MA_MAX_FILTER_ORDER >= 4
6970         #define MA_DEFAULT_RESAMPLER_LPF_ORDER  4
6971     #else
6972         #define MA_DEFAULT_RESAMPLER_LPF_ORDER  MA_MAX_FILTER_ORDER
6973     #endif
6974 #endif
6975
6976
6977 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
6978     #pragma GCC diagnostic push
6979     #pragma GCC diagnostic ignored "-Wunused-variable"
6980 #endif
6981
6982 /* Standard sample rates, in order of priority. */
6983 static ma_uint32 g_maStandardSampleRatePriorities[] = {
6984     (ma_uint32)ma_standard_sample_rate_48000,
6985     (ma_uint32)ma_standard_sample_rate_44100,
6986
6987     (ma_uint32)ma_standard_sample_rate_32000,
6988     (ma_uint32)ma_standard_sample_rate_24000,
6989     (ma_uint32)ma_standard_sample_rate_22050,
6990
6991     (ma_uint32)ma_standard_sample_rate_88200,
6992     (ma_uint32)ma_standard_sample_rate_96000,
6993     (ma_uint32)ma_standard_sample_rate_176400,
6994     (ma_uint32)ma_standard_sample_rate_192000,
6995
6996     (ma_uint32)ma_standard_sample_rate_16000,
6997     (ma_uint32)ma_standard_sample_rate_11025,
6998     (ma_uint32)ma_standard_sample_rate_8000,
6999
7000     (ma_uint32)ma_standard_sample_rate_352800,
7001     (ma_uint32)ma_standard_sample_rate_384000
7002 };
7003
7004 static MA_INLINE ma_bool32 ma_is_standard_sample_rate(ma_uint32 sampleRate)
7005 {
7006     ma_uint32 iSampleRate;
7007
7008     for (iSampleRate = 0; iSampleRate < sizeof(g_maStandardSampleRatePriorities) / sizeof(g_maStandardSampleRatePriorities[0]); iSampleRate += 1) {
7009         if (g_maStandardSampleRatePriorities[iSampleRate] == sampleRate) {
7010             return MA_TRUE;
7011         }
7012     }
7013
7014     /* Getting here means the sample rate is not supported. */
7015     return MA_FALSE;
7016 }
7017
7018
7019 static ma_format g_maFormatPriorities[] = {
7020     ma_format_s16,         /* Most common */
7021     ma_format_f32,
7022
7023     /*ma_format_s24_32,*/    /* Clean alignment */
7024     ma_format_s32,
7025
7026     ma_format_s24,         /* Unclean alignment */
7027
7028     ma_format_u8           /* Low quality */
7029 };
7030 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
7031     #pragma GCC diagnostic pop
7032 #endif
7033
7034
7035 MA_API void ma_version(ma_uint32* pMajor, ma_uint32* pMinor, ma_uint32* pRevision)
7036 {
7037     if (pMajor) {
7038         *pMajor = MA_VERSION_MAJOR;
7039     }
7040
7041     if (pMinor) {
7042         *pMinor = MA_VERSION_MINOR;
7043     }
7044
7045     if (pRevision) {
7046         *pRevision = MA_VERSION_REVISION;
7047     }
7048 }
7049
7050 MA_API const char* ma_version_string(void)
7051 {
7052     return MA_VERSION_STRING;
7053 }
7054
7055
7056 /******************************************************************************
7057
7058 Standard Library Stuff
7059
7060 ******************************************************************************/
7061 #ifndef MA_MALLOC
7062 #ifdef MA_WIN32
7063 #define MA_MALLOC(sz) HeapAlloc(GetProcessHeap(), 0, (sz))
7064 #else
7065 #define MA_MALLOC(sz) malloc((sz))
7066 #endif
7067 #endif
7068
7069 #ifndef MA_REALLOC
7070 #ifdef MA_WIN32
7071 #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)))
7072 #else
7073 #define MA_REALLOC(p, sz) realloc((p), (sz))
7074 #endif
7075 #endif
7076
7077 #ifndef MA_FREE
7078 #ifdef MA_WIN32
7079 #define MA_FREE(p) HeapFree(GetProcessHeap(), 0, (p))
7080 #else
7081 #define MA_FREE(p) free((p))
7082 #endif
7083 #endif
7084
7085 #ifndef MA_ZERO_MEMORY
7086 #ifdef MA_WIN32
7087 #define MA_ZERO_MEMORY(p, sz) ZeroMemory((p), (sz))
7088 #else
7089 #define MA_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
7090 #endif
7091 #endif
7092
7093 #ifndef MA_COPY_MEMORY
7094 #ifdef MA_WIN32
7095 #define MA_COPY_MEMORY(dst, src, sz) CopyMemory((dst), (src), (sz))
7096 #else
7097 #define MA_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
7098 #endif
7099 #endif
7100
7101 #ifndef MA_ASSERT
7102 #ifdef MA_WIN32
7103 #define MA_ASSERT(condition) assert(condition)
7104 #else
7105 #define MA_ASSERT(condition) assert(condition)
7106 #endif
7107 #endif
7108
7109 #define MA_ZERO_OBJECT(p) MA_ZERO_MEMORY((p), sizeof(*(p)))
7110
7111 #define ma_countof(x)               (sizeof(x) / sizeof(x[0]))
7112 #define ma_max(x, y)                (((x) > (y)) ? (x) : (y))
7113 #define ma_min(x, y)                (((x) < (y)) ? (x) : (y))
7114 #define ma_abs(x)                   (((x) > 0) ? (x) : -(x))
7115 #define ma_clamp(x, lo, hi)         (ma_max(lo, ma_min(x, hi)))
7116 #define ma_offset_ptr(p, offset)    (((ma_uint8*)(p)) + (offset))
7117
7118 #define ma_buffer_frame_capacity(buffer, channels, format) (sizeof(buffer) / ma_get_bytes_per_sample(format) / (channels))
7119
7120 static MA_INLINE double ma_sin(double x)
7121 {
7122     /* TODO: Implement custom sin(x). */
7123     return sin(x);
7124 }
7125
7126 static MA_INLINE double ma_exp(double x)
7127 {
7128     /* TODO: Implement custom exp(x). */
7129     return exp(x);
7130 }
7131
7132 static MA_INLINE double ma_log(double x)
7133 {
7134     /* TODO: Implement custom log(x). */
7135     return log(x);
7136 }
7137
7138 static MA_INLINE double ma_pow(double x, double y)
7139 {
7140     /* TODO: Implement custom pow(x, y). */
7141     return pow(x, y);
7142 }
7143
7144 static MA_INLINE double ma_sqrt(double x)
7145 {
7146     /* TODO: Implement custom sqrt(x). */
7147     return sqrt(x);
7148 }
7149
7150
7151 static MA_INLINE double ma_cos(double x)
7152 {
7153     return ma_sin((MA_PI_D*0.5) - x);
7154 }
7155
7156 static MA_INLINE double ma_log10(double x)
7157 {
7158     return ma_log(x) * 0.43429448190325182765;
7159 }
7160
7161 static MA_INLINE float ma_powf(float x, float y)
7162 {
7163     return (float)ma_pow((double)x, (double)y);
7164 }
7165
7166 static MA_INLINE float ma_log10f(float x)
7167 {
7168     return (float)ma_log10((double)x);
7169 }
7170
7171
7172 static MA_INLINE double ma_degrees_to_radians(double degrees)
7173 {
7174     return degrees * 0.01745329252;
7175 }
7176
7177 static MA_INLINE double ma_radians_to_degrees(double radians)
7178 {
7179     return radians * 57.295779512896;
7180 }
7181
7182 static MA_INLINE float ma_degrees_to_radians_f(float degrees)
7183 {
7184     return degrees * 0.01745329252f;
7185 }
7186
7187 static MA_INLINE float ma_radians_to_degrees_f(float radians)
7188 {
7189     return radians * 57.295779512896f;
7190 }
7191
7192
7193 /*
7194 Return Values:
7195   0:  Success
7196   22: EINVAL
7197   34: ERANGE
7198
7199 Not using symbolic constants for errors because I want to avoid #including errno.h
7200 */
7201 MA_API int ma_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src)
7202 {
7203     size_t i;
7204
7205     if (dst == 0) {
7206         return 22;
7207     }
7208     if (dstSizeInBytes == 0) {
7209         return 34;
7210     }
7211     if (src == 0) {
7212         dst[0] = '\0';
7213         return 22;
7214     }
7215
7216     for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) {
7217         dst[i] = src[i];
7218     }
7219
7220     if (i < dstSizeInBytes) {
7221         dst[i] = '\0';
7222         return 0;
7223     }
7224
7225     dst[0] = '\0';
7226     return 34;
7227 }
7228
7229 MA_API int ma_wcscpy_s(wchar_t* dst, size_t dstCap, const wchar_t* src)
7230 {
7231     size_t i;
7232
7233     if (dst == 0) {
7234         return 22;
7235     }
7236     if (dstCap == 0) {
7237         return 34;
7238     }
7239     if (src == 0) {
7240         dst[0] = '\0';
7241         return 22;
7242     }
7243
7244     for (i = 0; i < dstCap && src[i] != '\0'; ++i) {
7245         dst[i] = src[i];
7246     }
7247
7248     if (i < dstCap) {
7249         dst[i] = '\0';
7250         return 0;
7251     }
7252
7253     dst[0] = '\0';
7254     return 34;
7255 }
7256
7257
7258 MA_API int ma_strncpy_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count)
7259 {
7260     size_t maxcount;
7261     size_t i;
7262
7263     if (dst == 0) {
7264         return 22;
7265     }
7266     if (dstSizeInBytes == 0) {
7267         return 34;
7268     }
7269     if (src == 0) {
7270         dst[0] = '\0';
7271         return 22;
7272     }
7273
7274     maxcount = count;
7275     if (count == ((size_t)-1) || count >= dstSizeInBytes) {        /* -1 = _TRUNCATE */
7276         maxcount = dstSizeInBytes - 1;
7277     }
7278
7279     for (i = 0; i < maxcount && src[i] != '\0'; ++i) {
7280         dst[i] = src[i];
7281     }
7282
7283     if (src[i] == '\0' || i == count || count == ((size_t)-1)) {
7284         dst[i] = '\0';
7285         return 0;
7286     }
7287
7288     dst[0] = '\0';
7289     return 34;
7290 }
7291
7292 MA_API int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src)
7293 {
7294     char* dstorig;
7295
7296     if (dst == 0) {
7297         return 22;
7298     }
7299     if (dstSizeInBytes == 0) {
7300         return 34;
7301     }
7302     if (src == 0) {
7303         dst[0] = '\0';
7304         return 22;
7305     }
7306
7307     dstorig = dst;
7308
7309     while (dstSizeInBytes > 0 && dst[0] != '\0') {
7310         dst += 1;
7311         dstSizeInBytes -= 1;
7312     }
7313
7314     if (dstSizeInBytes == 0) {
7315         return 22;  /* Unterminated. */
7316     }
7317
7318
7319     while (dstSizeInBytes > 0 && src[0] != '\0') {
7320         *dst++ = *src++;
7321         dstSizeInBytes -= 1;
7322     }
7323
7324     if (dstSizeInBytes > 0) {
7325         dst[0] = '\0';
7326     } else {
7327         dstorig[0] = '\0';
7328         return 34;
7329     }
7330
7331     return 0;
7332 }
7333
7334 MA_API int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count)
7335 {
7336     char* dstorig;
7337
7338     if (dst == 0) {
7339         return 22;
7340     }
7341     if (dstSizeInBytes == 0) {
7342         return 34;
7343     }
7344     if (src == 0) {
7345         return 22;
7346     }
7347
7348     dstorig = dst;
7349
7350     while (dstSizeInBytes > 0 && dst[0] != '\0') {
7351         dst += 1;
7352         dstSizeInBytes -= 1;
7353     }
7354
7355     if (dstSizeInBytes == 0) {
7356         return 22;  /* Unterminated. */
7357     }
7358
7359
7360     if (count == ((size_t)-1)) {        /* _TRUNCATE */
7361         count = dstSizeInBytes - 1;
7362     }
7363
7364     while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) {
7365         *dst++ = *src++;
7366         dstSizeInBytes -= 1;
7367         count -= 1;
7368     }
7369
7370     if (dstSizeInBytes > 0) {
7371         dst[0] = '\0';
7372     } else {
7373         dstorig[0] = '\0';
7374         return 34;
7375     }
7376
7377     return 0;
7378 }
7379
7380 MA_API int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix)
7381 {
7382     int sign;
7383     unsigned int valueU;
7384     char* dstEnd;
7385
7386     if (dst == NULL || dstSizeInBytes == 0) {
7387         return 22;
7388     }
7389     if (radix < 2 || radix > 36) {
7390         dst[0] = '\0';
7391         return 22;
7392     }
7393
7394     sign = (value < 0 && radix == 10) ? -1 : 1;     /* The negative sign is only used when the base is 10. */
7395
7396     if (value < 0) {
7397         valueU = -value;
7398     } else {
7399         valueU = value;
7400     }
7401
7402     dstEnd = dst;
7403     do
7404     {
7405         int remainder = valueU % radix;
7406         if (remainder > 9) {
7407             *dstEnd = (char)((remainder - 10) + 'a');
7408         } else {
7409             *dstEnd = (char)(remainder + '0');
7410         }
7411
7412         dstEnd += 1;
7413         dstSizeInBytes -= 1;
7414         valueU /= radix;
7415     } while (dstSizeInBytes > 0 && valueU > 0);
7416
7417     if (dstSizeInBytes == 0) {
7418         dst[0] = '\0';
7419         return 22;  /* Ran out of room in the output buffer. */
7420     }
7421
7422     if (sign < 0) {
7423         *dstEnd++ = '-';
7424         dstSizeInBytes -= 1;
7425     }
7426
7427     if (dstSizeInBytes == 0) {
7428         dst[0] = '\0';
7429         return 22;  /* Ran out of room in the output buffer. */
7430     }
7431
7432     *dstEnd = '\0';
7433
7434
7435     /* At this point the string will be reversed. */
7436     dstEnd -= 1;
7437     while (dst < dstEnd) {
7438         char temp = *dst;
7439         *dst = *dstEnd;
7440         *dstEnd = temp;
7441
7442         dst += 1;
7443         dstEnd -= 1;
7444     }
7445
7446     return 0;
7447 }
7448
7449 MA_API int ma_strcmp(const char* str1, const char* str2)
7450 {
7451     if (str1 == str2) return  0;
7452
7453     /* These checks differ from the standard implementation. It's not important, but I prefer it just for sanity. */
7454     if (str1 == NULL) return -1;
7455     if (str2 == NULL) return  1;
7456
7457     for (;;) {
7458         if (str1[0] == '\0') {
7459             break;
7460         }
7461         if (str1[0] != str2[0]) {
7462             break;
7463         }
7464
7465         str1 += 1;
7466         str2 += 1;
7467     }
7468
7469     return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0];
7470 }
7471
7472 MA_API int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB)
7473 {
7474     int result;
7475
7476     result = ma_strncpy_s(dst, dstSize, srcA, (size_t)-1);
7477     if (result != 0) {
7478         return result;
7479     }
7480
7481     result = ma_strncat_s(dst, dstSize, srcB, (size_t)-1);
7482     if (result != 0) {
7483         return result;
7484     }
7485
7486     return result;
7487 }
7488
7489 MA_API char* ma_copy_string(const char* src, const ma_allocation_callbacks* pAllocationCallbacks)
7490 {
7491     size_t sz = strlen(src)+1;
7492     char* dst = (char*)ma_malloc(sz, pAllocationCallbacks);
7493     if (dst == NULL) {
7494         return NULL;
7495     }
7496
7497     ma_strcpy_s(dst, sz, src);
7498
7499     return dst;
7500 }
7501
7502 MA_API wchar_t* ma_copy_string_w(const wchar_t* src, const ma_allocation_callbacks* pAllocationCallbacks)
7503 {
7504     size_t sz = wcslen(src)+1;
7505     wchar_t* dst = (wchar_t*)ma_malloc(sz * sizeof(*dst), pAllocationCallbacks);
7506     if (dst == NULL) {
7507         return NULL;
7508     }
7509
7510     ma_wcscpy_s(dst, sz, src);
7511
7512     return dst;
7513 }
7514
7515
7516 #include <errno.h>
7517 static ma_result ma_result_from_errno(int e)
7518 {
7519     switch (e)
7520     {
7521         case 0: return MA_SUCCESS;
7522     #ifdef EPERM
7523         case EPERM: return MA_INVALID_OPERATION;
7524     #endif
7525     #ifdef ENOENT
7526         case ENOENT: return MA_DOES_NOT_EXIST;
7527     #endif
7528     #ifdef ESRCH
7529         case ESRCH: return MA_DOES_NOT_EXIST;
7530     #endif
7531     #ifdef EINTR
7532         case EINTR: return MA_INTERRUPT;
7533     #endif
7534     #ifdef EIO
7535         case EIO: return MA_IO_ERROR;
7536     #endif
7537     #ifdef ENXIO
7538         case ENXIO: return MA_DOES_NOT_EXIST;
7539     #endif
7540     #ifdef E2BIG
7541         case E2BIG: return MA_INVALID_ARGS;
7542     #endif
7543     #ifdef ENOEXEC
7544         case ENOEXEC: return MA_INVALID_FILE;
7545     #endif
7546     #ifdef EBADF
7547         case EBADF: return MA_INVALID_FILE;
7548     #endif
7549     #ifdef ECHILD
7550         case ECHILD: return MA_ERROR;
7551     #endif
7552     #ifdef EAGAIN
7553         case EAGAIN: return MA_UNAVAILABLE;
7554     #endif
7555     #ifdef ENOMEM
7556         case ENOMEM: return MA_OUT_OF_MEMORY;
7557     #endif
7558     #ifdef EACCES
7559         case EACCES: return MA_ACCESS_DENIED;
7560     #endif
7561     #ifdef EFAULT
7562         case EFAULT: return MA_BAD_ADDRESS;
7563     #endif
7564     #ifdef ENOTBLK
7565         case ENOTBLK: return MA_ERROR;
7566     #endif
7567     #ifdef EBUSY
7568         case EBUSY: return MA_BUSY;
7569     #endif
7570     #ifdef EEXIST
7571         case EEXIST: return MA_ALREADY_EXISTS;
7572     #endif
7573     #ifdef EXDEV
7574         case EXDEV: return MA_ERROR;
7575     #endif
7576     #ifdef ENODEV
7577         case ENODEV: return MA_DOES_NOT_EXIST;
7578     #endif
7579     #ifdef ENOTDIR
7580         case ENOTDIR: return MA_NOT_DIRECTORY;
7581     #endif
7582     #ifdef EISDIR
7583         case EISDIR: return MA_IS_DIRECTORY;
7584     #endif
7585     #ifdef EINVAL
7586         case EINVAL: return MA_INVALID_ARGS;
7587     #endif
7588     #ifdef ENFILE
7589         case ENFILE: return MA_TOO_MANY_OPEN_FILES;
7590     #endif
7591     #ifdef EMFILE
7592         case EMFILE: return MA_TOO_MANY_OPEN_FILES;
7593     #endif
7594     #ifdef ENOTTY
7595         case ENOTTY: return MA_INVALID_OPERATION;
7596     #endif
7597     #ifdef ETXTBSY
7598         case ETXTBSY: return MA_BUSY;
7599     #endif
7600     #ifdef EFBIG
7601         case EFBIG: return MA_TOO_BIG;
7602     #endif
7603     #ifdef ENOSPC
7604         case ENOSPC: return MA_NO_SPACE;
7605     #endif
7606     #ifdef ESPIPE
7607         case ESPIPE: return MA_BAD_SEEK;
7608     #endif
7609     #ifdef EROFS
7610         case EROFS: return MA_ACCESS_DENIED;
7611     #endif
7612     #ifdef EMLINK
7613         case EMLINK: return MA_TOO_MANY_LINKS;
7614     #endif
7615     #ifdef EPIPE
7616         case EPIPE: return MA_BAD_PIPE;
7617     #endif
7618     #ifdef EDOM
7619         case EDOM: return MA_OUT_OF_RANGE;
7620     #endif
7621     #ifdef ERANGE
7622         case ERANGE: return MA_OUT_OF_RANGE;
7623     #endif
7624     #ifdef EDEADLK
7625         case EDEADLK: return MA_DEADLOCK;
7626     #endif
7627     #ifdef ENAMETOOLONG
7628         case ENAMETOOLONG: return MA_PATH_TOO_LONG;
7629     #endif
7630     #ifdef ENOLCK
7631         case ENOLCK: return MA_ERROR;
7632     #endif
7633     #ifdef ENOSYS
7634         case ENOSYS: return MA_NOT_IMPLEMENTED;
7635     #endif
7636     #ifdef ENOTEMPTY
7637         case ENOTEMPTY: return MA_DIRECTORY_NOT_EMPTY;
7638     #endif
7639     #ifdef ELOOP
7640         case ELOOP: return MA_TOO_MANY_LINKS;
7641     #endif
7642     #ifdef ENOMSG
7643         case ENOMSG: return MA_NO_MESSAGE;
7644     #endif
7645     #ifdef EIDRM
7646         case EIDRM: return MA_ERROR;
7647     #endif
7648     #ifdef ECHRNG
7649         case ECHRNG: return MA_ERROR;
7650     #endif
7651     #ifdef EL2NSYNC
7652         case EL2NSYNC: return MA_ERROR;
7653     #endif
7654     #ifdef EL3HLT
7655         case EL3HLT: return MA_ERROR;
7656     #endif
7657     #ifdef EL3RST
7658         case EL3RST: return MA_ERROR;
7659     #endif
7660     #ifdef ELNRNG
7661         case ELNRNG: return MA_OUT_OF_RANGE;
7662     #endif
7663     #ifdef EUNATCH
7664         case EUNATCH: return MA_ERROR;
7665     #endif
7666     #ifdef ENOCSI
7667         case ENOCSI: return MA_ERROR;
7668     #endif
7669     #ifdef EL2HLT
7670         case EL2HLT: return MA_ERROR;
7671     #endif
7672     #ifdef EBADE
7673         case EBADE: return MA_ERROR;
7674     #endif
7675     #ifdef EBADR
7676         case EBADR: return MA_ERROR;
7677     #endif
7678     #ifdef EXFULL
7679         case EXFULL: return MA_ERROR;
7680     #endif
7681     #ifdef ENOANO
7682         case ENOANO: return MA_ERROR;
7683     #endif
7684     #ifdef EBADRQC
7685         case EBADRQC: return MA_ERROR;
7686     #endif
7687     #ifdef EBADSLT
7688         case EBADSLT: return MA_ERROR;
7689     #endif
7690     #ifdef EBFONT
7691         case EBFONT: return MA_INVALID_FILE;
7692     #endif
7693     #ifdef ENOSTR
7694         case ENOSTR: return MA_ERROR;
7695     #endif
7696     #ifdef ENODATA
7697         case ENODATA: return MA_NO_DATA_AVAILABLE;
7698     #endif
7699     #ifdef ETIME
7700         case ETIME: return MA_TIMEOUT;
7701     #endif
7702     #ifdef ENOSR
7703         case ENOSR: return MA_NO_DATA_AVAILABLE;
7704     #endif
7705     #ifdef ENONET
7706         case ENONET: return MA_NO_NETWORK;
7707     #endif
7708     #ifdef ENOPKG
7709         case ENOPKG: return MA_ERROR;
7710     #endif
7711     #ifdef EREMOTE
7712         case EREMOTE: return MA_ERROR;
7713     #endif
7714     #ifdef ENOLINK
7715         case ENOLINK: return MA_ERROR;
7716     #endif
7717     #ifdef EADV
7718         case EADV: return MA_ERROR;
7719     #endif
7720     #ifdef ESRMNT
7721         case ESRMNT: return MA_ERROR;
7722     #endif
7723     #ifdef ECOMM
7724         case ECOMM: return MA_ERROR;
7725     #endif
7726     #ifdef EPROTO
7727         case EPROTO: return MA_ERROR;
7728     #endif
7729     #ifdef EMULTIHOP
7730         case EMULTIHOP: return MA_ERROR;
7731     #endif
7732     #ifdef EDOTDOT
7733         case EDOTDOT: return MA_ERROR;
7734     #endif
7735     #ifdef EBADMSG
7736         case EBADMSG: return MA_BAD_MESSAGE;
7737     #endif
7738     #ifdef EOVERFLOW
7739         case EOVERFLOW: return MA_TOO_BIG;
7740     #endif
7741     #ifdef ENOTUNIQ
7742         case ENOTUNIQ: return MA_NOT_UNIQUE;
7743     #endif
7744     #ifdef EBADFD
7745         case EBADFD: return MA_ERROR;
7746     #endif
7747     #ifdef EREMCHG
7748         case EREMCHG: return MA_ERROR;
7749     #endif
7750     #ifdef ELIBACC
7751         case ELIBACC: return MA_ACCESS_DENIED;
7752     #endif
7753     #ifdef ELIBBAD
7754         case ELIBBAD: return MA_INVALID_FILE;
7755     #endif
7756     #ifdef ELIBSCN
7757         case ELIBSCN: return MA_INVALID_FILE;
7758     #endif
7759     #ifdef ELIBMAX
7760         case ELIBMAX: return MA_ERROR;
7761     #endif
7762     #ifdef ELIBEXEC
7763         case ELIBEXEC: return MA_ERROR;
7764     #endif
7765     #ifdef EILSEQ
7766         case EILSEQ: return MA_INVALID_DATA;
7767     #endif
7768     #ifdef ERESTART
7769         case ERESTART: return MA_ERROR;
7770     #endif
7771     #ifdef ESTRPIPE
7772         case ESTRPIPE: return MA_ERROR;
7773     #endif
7774     #ifdef EUSERS
7775         case EUSERS: return MA_ERROR;
7776     #endif
7777     #ifdef ENOTSOCK
7778         case ENOTSOCK: return MA_NOT_SOCKET;
7779     #endif
7780     #ifdef EDESTADDRREQ
7781         case EDESTADDRREQ: return MA_NO_ADDRESS;
7782     #endif
7783     #ifdef EMSGSIZE
7784         case EMSGSIZE: return MA_TOO_BIG;
7785     #endif
7786     #ifdef EPROTOTYPE
7787         case EPROTOTYPE: return MA_BAD_PROTOCOL;
7788     #endif
7789     #ifdef ENOPROTOOPT
7790         case ENOPROTOOPT: return MA_PROTOCOL_UNAVAILABLE;
7791     #endif
7792     #ifdef EPROTONOSUPPORT
7793         case EPROTONOSUPPORT: return MA_PROTOCOL_NOT_SUPPORTED;
7794     #endif
7795     #ifdef ESOCKTNOSUPPORT
7796         case ESOCKTNOSUPPORT: return MA_SOCKET_NOT_SUPPORTED;
7797     #endif
7798     #ifdef EOPNOTSUPP
7799         case EOPNOTSUPP: return MA_INVALID_OPERATION;
7800     #endif
7801     #ifdef EPFNOSUPPORT
7802         case EPFNOSUPPORT: return MA_PROTOCOL_FAMILY_NOT_SUPPORTED;
7803     #endif
7804     #ifdef EAFNOSUPPORT
7805         case EAFNOSUPPORT: return MA_ADDRESS_FAMILY_NOT_SUPPORTED;
7806     #endif
7807     #ifdef EADDRINUSE
7808         case EADDRINUSE: return MA_ALREADY_IN_USE;
7809     #endif
7810     #ifdef EADDRNOTAVAIL
7811         case EADDRNOTAVAIL: return MA_ERROR;
7812     #endif
7813     #ifdef ENETDOWN
7814         case ENETDOWN: return MA_NO_NETWORK;
7815     #endif
7816     #ifdef ENETUNREACH
7817         case ENETUNREACH: return MA_NO_NETWORK;
7818     #endif
7819     #ifdef ENETRESET
7820         case ENETRESET: return MA_NO_NETWORK;
7821     #endif
7822     #ifdef ECONNABORTED
7823         case ECONNABORTED: return MA_NO_NETWORK;
7824     #endif
7825     #ifdef ECONNRESET
7826         case ECONNRESET: return MA_CONNECTION_RESET;
7827     #endif
7828     #ifdef ENOBUFS
7829         case ENOBUFS: return MA_NO_SPACE;
7830     #endif
7831     #ifdef EISCONN
7832         case EISCONN: return MA_ALREADY_CONNECTED;
7833     #endif
7834     #ifdef ENOTCONN
7835         case ENOTCONN: return MA_NOT_CONNECTED;
7836     #endif
7837     #ifdef ESHUTDOWN
7838         case ESHUTDOWN: return MA_ERROR;
7839     #endif
7840     #ifdef ETOOMANYREFS
7841         case ETOOMANYREFS: return MA_ERROR;
7842     #endif
7843     #ifdef ETIMEDOUT
7844         case ETIMEDOUT: return MA_TIMEOUT;
7845     #endif
7846     #ifdef ECONNREFUSED
7847         case ECONNREFUSED: return MA_CONNECTION_REFUSED;
7848     #endif
7849     #ifdef EHOSTDOWN
7850         case EHOSTDOWN: return MA_NO_HOST;
7851     #endif
7852     #ifdef EHOSTUNREACH
7853         case EHOSTUNREACH: return MA_NO_HOST;
7854     #endif
7855     #ifdef EALREADY
7856         case EALREADY: return MA_IN_PROGRESS;
7857     #endif
7858     #ifdef EINPROGRESS
7859         case EINPROGRESS: return MA_IN_PROGRESS;
7860     #endif
7861     #ifdef ESTALE
7862         case ESTALE: return MA_INVALID_FILE;
7863     #endif
7864     #ifdef EUCLEAN
7865         case EUCLEAN: return MA_ERROR;
7866     #endif
7867     #ifdef ENOTNAM
7868         case ENOTNAM: return MA_ERROR;
7869     #endif
7870     #ifdef ENAVAIL
7871         case ENAVAIL: return MA_ERROR;
7872     #endif
7873     #ifdef EISNAM
7874         case EISNAM: return MA_ERROR;
7875     #endif
7876     #ifdef EREMOTEIO
7877         case EREMOTEIO: return MA_IO_ERROR;
7878     #endif
7879     #ifdef EDQUOT
7880         case EDQUOT: return MA_NO_SPACE;
7881     #endif
7882     #ifdef ENOMEDIUM
7883         case ENOMEDIUM: return MA_DOES_NOT_EXIST;
7884     #endif
7885     #ifdef EMEDIUMTYPE
7886         case EMEDIUMTYPE: return MA_ERROR;
7887     #endif
7888     #ifdef ECANCELED
7889         case ECANCELED: return MA_CANCELLED;
7890     #endif
7891     #ifdef ENOKEY
7892         case ENOKEY: return MA_ERROR;
7893     #endif
7894     #ifdef EKEYEXPIRED
7895         case EKEYEXPIRED: return MA_ERROR;
7896     #endif
7897     #ifdef EKEYREVOKED
7898         case EKEYREVOKED: return MA_ERROR;
7899     #endif
7900     #ifdef EKEYREJECTED
7901         case EKEYREJECTED: return MA_ERROR;
7902     #endif
7903     #ifdef EOWNERDEAD
7904         case EOWNERDEAD: return MA_ERROR;
7905     #endif
7906     #ifdef ENOTRECOVERABLE
7907         case ENOTRECOVERABLE: return MA_ERROR;
7908     #endif
7909     #ifdef ERFKILL
7910         case ERFKILL: return MA_ERROR;
7911     #endif
7912     #ifdef EHWPOISON
7913         case EHWPOISON: return MA_ERROR;
7914     #endif
7915         default: return MA_ERROR;
7916     }
7917 }
7918
7919 MA_API ma_result ma_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
7920 {
7921 #if defined(_MSC_VER) && _MSC_VER >= 1400
7922     errno_t err;
7923 #endif
7924
7925     if (ppFile != NULL) {
7926         *ppFile = NULL;  /* Safety. */
7927     }
7928
7929     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
7930         return MA_INVALID_ARGS;
7931     }
7932
7933 #if defined(_MSC_VER) && _MSC_VER >= 1400
7934     err = fopen_s(ppFile, pFilePath, pOpenMode);
7935     if (err != 0) {
7936         return ma_result_from_errno(err);
7937     }
7938 #else
7939 #if defined(_WIN32) || defined(__APPLE__)
7940     *ppFile = fopen(pFilePath, pOpenMode);
7941 #else
7942     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
7943         *ppFile = fopen64(pFilePath, pOpenMode);
7944     #else
7945         *ppFile = fopen(pFilePath, pOpenMode);
7946     #endif
7947 #endif
7948     if (*ppFile == NULL) {
7949         ma_result result = ma_result_from_errno(errno);
7950         if (result == MA_SUCCESS) {
7951             result = MA_ERROR;   /* Just a safety check to make sure we never ever return success when pFile == NULL. */
7952         }
7953
7954         return result;
7955     }
7956 #endif
7957
7958     return MA_SUCCESS;
7959 }
7960
7961
7962
7963 /*
7964 _wfopen() isn't always available in all compilation environments.
7965
7966     * Windows only.
7967     * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
7968     * MinGW-64 (both 32- and 64-bit) seems to support it.
7969     * MinGW wraps it in !defined(__STRICT_ANSI__).
7970     * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
7971
7972 This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
7973 fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
7974 */
7975 #if defined(_WIN32)
7976     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
7977         #define MA_HAS_WFOPEN
7978     #endif
7979 #endif
7980
7981 MA_API ma_result ma_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const ma_allocation_callbacks* pAllocationCallbacks)
7982 {
7983     if (ppFile != NULL) {
7984         *ppFile = NULL;  /* Safety. */
7985     }
7986
7987     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
7988         return MA_INVALID_ARGS;
7989     }
7990
7991 #if defined(MA_HAS_WFOPEN)
7992     {
7993         /* Use _wfopen() on Windows. */
7994     #if defined(_MSC_VER) && _MSC_VER >= 1400
7995         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
7996         if (err != 0) {
7997             return ma_result_from_errno(err);
7998         }
7999     #else
8000         *ppFile = _wfopen(pFilePath, pOpenMode);
8001         if (*ppFile == NULL) {
8002             return ma_result_from_errno(errno);
8003         }
8004     #endif
8005         (void)pAllocationCallbacks;
8006     }
8007 #else
8008     /*
8009     Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
8010     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
8011     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.
8012     */
8013     {
8014         mbstate_t mbs;
8015         size_t lenMB;
8016         const wchar_t* pFilePathTemp = pFilePath;
8017         char* pFilePathMB = NULL;
8018         char pOpenModeMB[32] = {0};
8019
8020         /* Get the length first. */
8021         MA_ZERO_OBJECT(&mbs);
8022         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
8023         if (lenMB == (size_t)-1) {
8024             return ma_result_from_errno(errno);
8025         }
8026
8027         pFilePathMB = (char*)ma_malloc(lenMB + 1, pAllocationCallbacks);
8028         if (pFilePathMB == NULL) {
8029             return MA_OUT_OF_MEMORY;
8030         }
8031
8032         pFilePathTemp = pFilePath;
8033         MA_ZERO_OBJECT(&mbs);
8034         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
8035
8036         /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
8037         {
8038             size_t i = 0;
8039             for (;;) {
8040                 if (pOpenMode[i] == 0) {
8041                     pOpenModeMB[i] = '\0';
8042                     break;
8043                 }
8044
8045                 pOpenModeMB[i] = (char)pOpenMode[i];
8046                 i += 1;
8047             }
8048         }
8049
8050         *ppFile = fopen(pFilePathMB, pOpenModeMB);
8051
8052         ma_free(pFilePathMB, pAllocationCallbacks);
8053     }
8054
8055     if (*ppFile == NULL) {
8056         return MA_ERROR;
8057     }
8058 #endif
8059
8060     return MA_SUCCESS;
8061 }
8062
8063
8064
8065 static MA_INLINE void ma_copy_memory_64(void* dst, const void* src, ma_uint64 sizeInBytes)
8066 {
8067 #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX
8068     MA_COPY_MEMORY(dst, src, (size_t)sizeInBytes);
8069 #else
8070     while (sizeInBytes > 0) {
8071         ma_uint64 bytesToCopyNow = sizeInBytes;
8072         if (bytesToCopyNow > MA_SIZE_MAX) {
8073             bytesToCopyNow = MA_SIZE_MAX;
8074         }
8075
8076         MA_COPY_MEMORY(dst, src, (size_t)bytesToCopyNow);  /* Safe cast to size_t. */
8077
8078         sizeInBytes -= bytesToCopyNow;
8079         dst = (      void*)((      ma_uint8*)dst + bytesToCopyNow);
8080         src = (const void*)((const ma_uint8*)src + bytesToCopyNow);
8081     }
8082 #endif
8083 }
8084
8085 static MA_INLINE void ma_zero_memory_64(void* dst, ma_uint64 sizeInBytes)
8086 {
8087 #if 0xFFFFFFFFFFFFFFFF <= MA_SIZE_MAX
8088     MA_ZERO_MEMORY(dst, (size_t)sizeInBytes);
8089 #else
8090     while (sizeInBytes > 0) {
8091         ma_uint64 bytesToZeroNow = sizeInBytes;
8092         if (bytesToZeroNow > MA_SIZE_MAX) {
8093             bytesToZeroNow = MA_SIZE_MAX;
8094         }
8095
8096         MA_ZERO_MEMORY(dst, (size_t)bytesToZeroNow);  /* Safe cast to size_t. */
8097
8098         sizeInBytes -= bytesToZeroNow;
8099         dst = (void*)((ma_uint8*)dst + bytesToZeroNow);
8100     }
8101 #endif
8102 }
8103
8104
8105 /* Thanks to good old Bit Twiddling Hacks for this one: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */
8106 static MA_INLINE unsigned int ma_next_power_of_2(unsigned int x)
8107 {
8108     x--;
8109     x |= x >> 1;
8110     x |= x >> 2;
8111     x |= x >> 4;
8112     x |= x >> 8;
8113     x |= x >> 16;
8114     x++;
8115
8116     return x;
8117 }
8118
8119 static MA_INLINE unsigned int ma_prev_power_of_2(unsigned int x)
8120 {
8121     return ma_next_power_of_2(x) >> 1;
8122 }
8123
8124 static MA_INLINE unsigned int ma_round_to_power_of_2(unsigned int x)
8125 {
8126     unsigned int prev = ma_prev_power_of_2(x);
8127     unsigned int next = ma_next_power_of_2(x);
8128     if ((next - x) > (x - prev)) {
8129         return prev;
8130     } else {
8131         return next;
8132     }
8133 }
8134
8135 static MA_INLINE unsigned int ma_count_set_bits(unsigned int x)
8136 {
8137     unsigned int count = 0;
8138     while (x != 0) {
8139         if (x & 1) {
8140             count += 1;
8141         }
8142
8143         x = x >> 1;
8144     }
8145
8146     return count;
8147 }
8148
8149
8150
8151 /* Clamps an f32 sample to -1..1 */
8152 static MA_INLINE float ma_clip_f32(float x)
8153 {
8154     if (x < -1) return -1;
8155     if (x > +1) return +1;
8156     return x;
8157 }
8158
8159 static MA_INLINE float ma_mix_f32(float x, float y, float a)
8160 {
8161     return x*(1-a) + y*a;
8162 }
8163 static MA_INLINE float ma_mix_f32_fast(float x, float y, float a)
8164 {
8165     float r0 = (y - x);
8166     float r1 = r0*a;
8167     return x + r1;
8168     /*return x + (y - x)*a;*/
8169 }
8170
8171 #if defined(MA_SUPPORT_SSE2)
8172 static MA_INLINE __m128 ma_mix_f32_fast__sse2(__m128 x, __m128 y, __m128 a)
8173 {
8174     return _mm_add_ps(x, _mm_mul_ps(_mm_sub_ps(y, x), a));
8175 }
8176 #endif
8177 #if defined(MA_SUPPORT_AVX2)
8178 static MA_INLINE __m256 ma_mix_f32_fast__avx2(__m256 x, __m256 y, __m256 a)
8179 {
8180     return _mm256_add_ps(x, _mm256_mul_ps(_mm256_sub_ps(y, x), a));
8181 }
8182 #endif
8183 #if defined(MA_SUPPORT_AVX512)
8184 static MA_INLINE __m512 ma_mix_f32_fast__avx512(__m512 x, __m512 y, __m512 a)
8185 {
8186     return _mm512_add_ps(x, _mm512_mul_ps(_mm512_sub_ps(y, x), a));
8187 }
8188 #endif
8189 #if defined(MA_SUPPORT_NEON)
8190 static MA_INLINE float32x4_t ma_mix_f32_fast__neon(float32x4_t x, float32x4_t y, float32x4_t a)
8191 {
8192     return vaddq_f32(x, vmulq_f32(vsubq_f32(y, x), a));
8193 }
8194 #endif
8195
8196
8197 static MA_INLINE double ma_mix_f64(double x, double y, double a)
8198 {
8199     return x*(1-a) + y*a;
8200 }
8201 static MA_INLINE double ma_mix_f64_fast(double x, double y, double a)
8202 {
8203     return x + (y - x)*a;
8204 }
8205
8206 static MA_INLINE float ma_scale_to_range_f32(float x, float lo, float hi)
8207 {
8208     return lo + x*(hi-lo);
8209 }
8210
8211
8212 /*
8213 Greatest common factor using Euclid's algorithm iteratively.
8214 */
8215 static MA_INLINE ma_uint32 ma_gcf_u32(ma_uint32 a, ma_uint32 b)
8216 {
8217     for (;;) {
8218         if (b == 0) {
8219             break;
8220         } else {
8221             ma_uint32 t = a;
8222             a = b;
8223             b = t % a;
8224         }
8225     }
8226
8227     return a;
8228 }
8229
8230
8231 /*
8232 Random Number Generation
8233
8234 miniaudio uses the LCG random number generation algorithm. This is good enough for audio.
8235
8236 Note that miniaudio's global LCG implementation uses global state which is _not_ thread-local. When this is called across
8237 multiple threads, results will be unpredictable. However, it won't crash and results will still be random enough for
8238 miniaudio's purposes.
8239 */
8240 #ifndef MA_DEFAULT_LCG_SEED
8241 #define MA_DEFAULT_LCG_SEED 4321
8242 #endif
8243
8244 #define MA_LCG_M   2147483647
8245 #define MA_LCG_A   48271
8246 #define MA_LCG_C   0
8247
8248 static ma_lcg g_maLCG = {MA_DEFAULT_LCG_SEED}; /* Non-zero initial seed. Use ma_seed() to use an explicit seed. */
8249
8250 static MA_INLINE void ma_lcg_seed(ma_lcg* pLCG, ma_int32 seed)
8251 {
8252     MA_ASSERT(pLCG != NULL);
8253     pLCG->state = seed;
8254 }
8255
8256 static MA_INLINE ma_int32 ma_lcg_rand_s32(ma_lcg* pLCG)
8257 {
8258     pLCG->state = (MA_LCG_A * pLCG->state + MA_LCG_C) % MA_LCG_M;
8259     return pLCG->state;
8260 }
8261
8262 static MA_INLINE ma_uint32 ma_lcg_rand_u32(ma_lcg* pLCG)
8263 {
8264     return (ma_uint32)ma_lcg_rand_s32(pLCG);
8265 }
8266
8267 static MA_INLINE ma_int16 ma_lcg_rand_s16(ma_lcg* pLCG)
8268 {
8269     return (ma_int16)(ma_lcg_rand_s32(pLCG) & 0xFFFF);
8270 }
8271
8272 static MA_INLINE double ma_lcg_rand_f64(ma_lcg* pLCG)
8273 {
8274     return ma_lcg_rand_s32(pLCG) / (double)0x7FFFFFFF;
8275 }
8276
8277 static MA_INLINE float ma_lcg_rand_f32(ma_lcg* pLCG)
8278 {
8279     return (float)ma_lcg_rand_f64(pLCG);
8280 }
8281
8282 static MA_INLINE float ma_lcg_rand_range_f32(ma_lcg* pLCG, float lo, float hi)
8283 {
8284     return ma_scale_to_range_f32(ma_lcg_rand_f32(pLCG), lo, hi);
8285 }
8286
8287 static MA_INLINE ma_int32 ma_lcg_rand_range_s32(ma_lcg* pLCG, ma_int32 lo, ma_int32 hi)
8288 {
8289     if (lo == hi) {
8290         return lo;
8291     }
8292
8293     return lo + ma_lcg_rand_u32(pLCG) / (0xFFFFFFFF / (hi - lo + 1) + 1);
8294 }
8295
8296
8297
8298 static MA_INLINE void ma_seed(ma_int32 seed)
8299 {
8300     ma_lcg_seed(&g_maLCG, seed);
8301 }
8302
8303 static MA_INLINE ma_int32 ma_rand_s32(void)
8304 {
8305     return ma_lcg_rand_s32(&g_maLCG);
8306 }
8307
8308 static MA_INLINE ma_uint32 ma_rand_u32(void)
8309 {
8310     return ma_lcg_rand_u32(&g_maLCG);
8311 }
8312
8313 static MA_INLINE double ma_rand_f64(void)
8314 {
8315     return ma_lcg_rand_f64(&g_maLCG);
8316 }
8317
8318 static MA_INLINE float ma_rand_f32(void)
8319 {
8320     return ma_lcg_rand_f32(&g_maLCG);
8321 }
8322
8323 static MA_INLINE float ma_rand_range_f32(float lo, float hi)
8324 {
8325     return ma_lcg_rand_range_f32(&g_maLCG, lo, hi);
8326 }
8327
8328 static MA_INLINE ma_int32 ma_rand_range_s32(ma_int32 lo, ma_int32 hi)
8329 {
8330     return ma_lcg_rand_range_s32(&g_maLCG, lo, hi);
8331 }
8332
8333
8334 static MA_INLINE float ma_dither_f32_rectangle(float ditherMin, float ditherMax)
8335 {
8336     return ma_rand_range_f32(ditherMin, ditherMax);
8337 }
8338
8339 static MA_INLINE float ma_dither_f32_triangle(float ditherMin, float ditherMax)
8340 {
8341     float a = ma_rand_range_f32(ditherMin, 0);
8342     float b = ma_rand_range_f32(0, ditherMax);
8343     return a + b;
8344 }
8345
8346 static MA_INLINE float ma_dither_f32(ma_dither_mode ditherMode, float ditherMin, float ditherMax)
8347 {
8348     if (ditherMode == ma_dither_mode_rectangle) {
8349         return ma_dither_f32_rectangle(ditherMin, ditherMax);
8350     }
8351     if (ditherMode == ma_dither_mode_triangle) {
8352         return ma_dither_f32_triangle(ditherMin, ditherMax);
8353     }
8354
8355     return 0;
8356 }
8357
8358 static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode, ma_int32 ditherMin, ma_int32 ditherMax)
8359 {
8360     if (ditherMode == ma_dither_mode_rectangle) {
8361         ma_int32 a = ma_rand_range_s32(ditherMin, ditherMax);
8362         return a;
8363     }
8364     if (ditherMode == ma_dither_mode_triangle) {
8365         ma_int32 a = ma_rand_range_s32(ditherMin, 0);
8366         ma_int32 b = ma_rand_range_s32(0, ditherMax);
8367         return a + b;
8368     }
8369
8370     return 0;
8371 }
8372
8373
8374 /**************************************************************************************************************************************************************
8375
8376 Atomics
8377
8378 **************************************************************************************************************************************************************/
8379 /* c89atomic.h begin */
8380 #ifndef c89atomic_h
8381 #define c89atomic_h
8382 #if defined(__cplusplus)
8383 extern "C" {
8384 #endif
8385 typedef   signed char           c89atomic_int8;
8386 typedef unsigned char           c89atomic_uint8;
8387 typedef   signed short          c89atomic_int16;
8388 typedef unsigned short          c89atomic_uint16;
8389 typedef   signed int            c89atomic_int32;
8390 typedef unsigned int            c89atomic_uint32;
8391 #if defined(_MSC_VER)
8392     typedef   signed __int64    c89atomic_int64;
8393     typedef unsigned __int64    c89atomic_uint64;
8394 #else
8395     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
8396         #pragma GCC diagnostic push
8397         #pragma GCC diagnostic ignored "-Wlong-long"
8398         #if defined(__clang__)
8399             #pragma GCC diagnostic ignored "-Wc++11-long-long"
8400         #endif
8401     #endif
8402     typedef   signed long long  c89atomic_int64;
8403     typedef unsigned long long  c89atomic_uint64;
8404     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
8405         #pragma GCC diagnostic pop
8406     #endif
8407 #endif
8408 typedef int                     c89atomic_memory_order;
8409 typedef unsigned char           c89atomic_bool;
8410 #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
8411 #ifdef _WIN32
8412 #ifdef _WIN64
8413 #define C89ATOMIC_64BIT
8414 #else
8415 #define C89ATOMIC_32BIT
8416 #endif
8417 #endif
8418 #endif
8419 #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
8420 #ifdef __GNUC__
8421 #ifdef __LP64__
8422 #define C89ATOMIC_64BIT
8423 #else
8424 #define C89ATOMIC_32BIT
8425 #endif
8426 #endif
8427 #endif
8428 #if !defined(C89ATOMIC_64BIT) && !defined(C89ATOMIC_32BIT)
8429 #include <stdint.h>
8430 #if INTPTR_MAX == INT64_MAX
8431 #define C89ATOMIC_64BIT
8432 #else
8433 #define C89ATOMIC_32BIT
8434 #endif
8435 #endif
8436 #if defined(__x86_64__) || defined(_M_X64)
8437 #define C89ATOMIC_X64
8438 #elif defined(__i386) || defined(_M_IX86)
8439 #define C89ATOMIC_X86
8440 #elif defined(__arm__) || defined(_M_ARM)
8441 #define C89ATOMIC_ARM
8442 #endif
8443 #if defined(_MSC_VER)
8444     #define C89ATOMIC_INLINE __forceinline
8445 #elif defined(__GNUC__)
8446     #if defined(__STRICT_ANSI__)
8447         #define C89ATOMIC_INLINE __inline__ __attribute__((always_inline))
8448     #else
8449         #define C89ATOMIC_INLINE inline __attribute__((always_inline))
8450     #endif
8451 #elif defined(__WATCOMC__) || defined(__DMC__)
8452     #define C89ATOMIC_INLINE __inline
8453 #else
8454     #define C89ATOMIC_INLINE
8455 #endif
8456 #define C89ATOMIC_HAS_8
8457 #define C89ATOMIC_HAS_16
8458 #define C89ATOMIC_HAS_32
8459 #define C89ATOMIC_HAS_64
8460 #if (defined(_MSC_VER) ) || defined(__WATCOMC__) || defined(__DMC__)
8461     #define c89atomic_memory_order_relaxed  0
8462     #define c89atomic_memory_order_consume  1
8463     #define c89atomic_memory_order_acquire  2
8464     #define c89atomic_memory_order_release  3
8465     #define c89atomic_memory_order_acq_rel  4
8466     #define c89atomic_memory_order_seq_cst  5
8467     #if _MSC_VER < 1600 && defined(C89ATOMIC_32BIT)
8468         #define C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY
8469     #endif
8470     #if _MSC_VER < 1600
8471         #undef C89ATOMIC_HAS_8
8472         #undef C89ATOMIC_HAS_16
8473     #endif
8474     #if !defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
8475         #include <intrin.h>
8476     #endif
8477     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
8478         #if defined(C89ATOMIC_HAS_8)
8479             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired)
8480             {
8481                 c89atomic_uint8 result = 0;
8482                 __asm {
8483                     mov ecx, dst
8484                     mov al,  expected
8485                     mov dl,  desired
8486                     lock cmpxchg [ecx], dl
8487                     mov result, al
8488                 }
8489                 return result;
8490             }
8491         #endif
8492         #if defined(C89ATOMIC_HAS_16)
8493             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired)
8494             {
8495                 c89atomic_uint16 result = 0;
8496                 __asm {
8497                     mov ecx, dst
8498                     mov ax,  expected
8499                     mov dx,  desired
8500                     lock cmpxchg [ecx], dx
8501                     mov result, ax
8502                 }
8503                 return result;
8504             }
8505         #endif
8506         #if defined(C89ATOMIC_HAS_32)
8507             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired)
8508             {
8509                 c89atomic_uint32 result = 0;
8510                 __asm {
8511                     mov ecx, dst
8512                     mov eax, expected
8513                     mov edx, desired
8514                     lock cmpxchg [ecx], edx
8515                     mov result, eax
8516                 }
8517                 return result;
8518             }
8519         #endif
8520         #if defined(C89ATOMIC_HAS_64)
8521             static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired)
8522             {
8523                 c89atomic_uint32 resultEAX = 0;
8524                 c89atomic_uint32 resultEDX = 0;
8525                 __asm {
8526                     mov esi, dst
8527                     mov eax, dword ptr expected
8528                     mov edx, dword ptr expected + 4
8529                     mov ebx, dword ptr desired
8530                     mov ecx, dword ptr desired + 4
8531                     lock cmpxchg8b qword ptr [esi]
8532                     mov resultEAX, eax
8533                     mov resultEDX, edx
8534                 }
8535                 return ((c89atomic_uint64)resultEDX << 32) | resultEAX;
8536             }
8537         #endif
8538     #else
8539         #if defined(C89ATOMIC_HAS_8)
8540             #define c89atomic_compare_and_swap_8( dst, expected, desired) (c89atomic_uint8 )_InterlockedCompareExchange8((volatile char*)dst, (char)desired, (char)expected)
8541         #endif
8542         #if defined(C89ATOMIC_HAS_16)
8543             #define c89atomic_compare_and_swap_16(dst, expected, desired) (c89atomic_uint16)_InterlockedCompareExchange16((volatile short*)dst, (short)desired, (short)expected)
8544         #endif
8545         #if defined(C89ATOMIC_HAS_32)
8546             #define c89atomic_compare_and_swap_32(dst, expected, desired) (c89atomic_uint32)_InterlockedCompareExchange((volatile long*)dst, (long)desired, (long)expected)
8547         #endif
8548         #if defined(C89ATOMIC_HAS_64)
8549             #define c89atomic_compare_and_swap_64(dst, expected, desired) (c89atomic_uint64)_InterlockedCompareExchange64((volatile long long*)dst, (long long)desired, (long long)expected)
8550         #endif
8551     #endif
8552     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
8553         #if defined(C89ATOMIC_HAS_8)
8554             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8555             {
8556                 c89atomic_uint8 result = 0;
8557                 (void)order;
8558                 __asm {
8559                     mov ecx, dst
8560                     mov al,  src
8561                     lock xchg [ecx], al
8562                     mov result, al
8563                 }
8564                 return result;
8565             }
8566         #endif
8567         #if defined(C89ATOMIC_HAS_16)
8568             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8569             {
8570                 c89atomic_uint16 result = 0;
8571                 (void)order;
8572                 __asm {
8573                     mov ecx, dst
8574                     mov ax,  src
8575                     lock xchg [ecx], ax
8576                     mov result, ax
8577                 }
8578                 return result;
8579             }
8580         #endif
8581         #if defined(C89ATOMIC_HAS_32)
8582             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8583             {
8584                 c89atomic_uint32 result = 0;
8585                 (void)order;
8586                 __asm {
8587                     mov ecx, dst
8588                     mov eax, src
8589                     lock xchg [ecx], eax
8590                     mov result, eax
8591                 }
8592                 return result;
8593             }
8594         #endif
8595     #else
8596         #if defined(C89ATOMIC_HAS_8)
8597             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8598             {
8599                 (void)order;
8600                 return (c89atomic_uint8)_InterlockedExchange8((volatile char*)dst, (char)src);
8601             }
8602         #endif
8603         #if defined(C89ATOMIC_HAS_16)
8604             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8605             {
8606                 (void)order;
8607                 return (c89atomic_uint16)_InterlockedExchange16((volatile short*)dst, (short)src);
8608             }
8609         #endif
8610         #if defined(C89ATOMIC_HAS_32)
8611             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8612             {
8613                 (void)order;
8614                 return (c89atomic_uint32)_InterlockedExchange((volatile long*)dst, (long)src);
8615             }
8616         #endif
8617         #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT)
8618             static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8619             {
8620                 (void)order;
8621                 return (c89atomic_uint64)_InterlockedExchange64((volatile long long*)dst, (long long)src);
8622             }
8623         #else
8624         #endif
8625     #endif
8626     #if defined(C89ATOMIC_HAS_64) && !defined(C89ATOMIC_64BIT)
8627         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8628         {
8629             c89atomic_uint64 oldValue;
8630             do {
8631                 oldValue = *dst;
8632             } while (c89atomic_compare_and_swap_64(dst, oldValue, src) != oldValue);
8633             (void)order;
8634             return oldValue;
8635         }
8636     #endif
8637     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
8638         #if defined(C89ATOMIC_HAS_8)
8639             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8640             {
8641                 c89atomic_uint8 result = 0;
8642                 (void)order;
8643                 __asm {
8644                     mov ecx, dst
8645                     mov al,  src
8646                     lock xadd [ecx], al
8647                     mov result, al
8648                 }
8649                 return result;
8650             }
8651         #endif
8652         #if defined(C89ATOMIC_HAS_16)
8653             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8654             {
8655                 c89atomic_uint16 result = 0;
8656                 (void)order;
8657                 __asm {
8658                     mov ecx, dst
8659                     mov ax,  src
8660                     lock xadd [ecx], ax
8661                     mov result, ax
8662                 }
8663                 return result;
8664             }
8665         #endif
8666         #if defined(C89ATOMIC_HAS_32)
8667             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8668             {
8669                 c89atomic_uint32 result = 0;
8670                 (void)order;
8671                 __asm {
8672                     mov ecx, dst
8673                     mov eax, src
8674                     lock xadd [ecx], eax
8675                     mov result, eax
8676                 }
8677                 return result;
8678             }
8679         #endif
8680     #else
8681         #if defined(C89ATOMIC_HAS_8)
8682             static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8683             {
8684                 (void)order;
8685                 return (c89atomic_uint8)_InterlockedExchangeAdd8((volatile char*)dst, (char)src);
8686             }
8687         #endif
8688         #if defined(C89ATOMIC_HAS_16)
8689             static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8690             {
8691                 (void)order;
8692                 return (c89atomic_uint16)_InterlockedExchangeAdd16((volatile short*)dst, (short)src);
8693             }
8694         #endif
8695         #if defined(C89ATOMIC_HAS_32)
8696             static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8697             {
8698                 (void)order;
8699                 return (c89atomic_uint32)_InterlockedExchangeAdd((volatile long*)dst, (long)src);
8700             }
8701         #endif
8702         #if defined(C89ATOMIC_HAS_64) && defined(C89ATOMIC_64BIT)
8703             static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8704             {
8705                 (void)order;
8706                 return (c89atomic_uint64)_InterlockedExchangeAdd64((volatile long long*)dst, (long long)src);
8707             }
8708         #else
8709         #endif
8710     #endif
8711     #if defined(C89ATOMIC_HAS_64) && !defined(C89ATOMIC_64BIT)
8712         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8713         {
8714             c89atomic_uint64 oldValue;
8715             c89atomic_uint64 newValue;
8716             do {
8717                 oldValue = *dst;
8718                 newValue = oldValue + src;
8719             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
8720             (void)order;
8721             return oldValue;
8722         }
8723     #endif
8724     #if defined(C89ATOMIC_MSVC_USE_INLINED_ASSEMBLY)
8725         static C89ATOMIC_INLINE void __stdcall c89atomic_thread_fence(c89atomic_memory_order order)
8726         {
8727             (void)order;
8728             __asm {
8729                 lock add [esp], 0
8730             }
8731         }
8732     #else
8733         #if defined(C89ATOMIC_X64)
8734             #define c89atomic_thread_fence(order)   __faststorefence(), (void)order
8735         #else
8736             static C89ATOMIC_INLINE void c89atomic_thread_fence(c89atomic_memory_order order)
8737             {
8738                 volatile c89atomic_uint32 barrier = 0;
8739                 c89atomic_fetch_add_explicit_32(&barrier, 0, order);
8740             }
8741         #endif
8742     #endif
8743     #define c89atomic_compiler_fence()      c89atomic_thread_fence(c89atomic_memory_order_seq_cst)
8744     #define c89atomic_signal_fence(order)   c89atomic_thread_fence(order)
8745     #if defined(C89ATOMIC_HAS_8)
8746         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
8747         {
8748             (void)order;
8749             return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0);
8750         }
8751     #endif
8752     #if defined(C89ATOMIC_HAS_16)
8753         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
8754         {
8755             (void)order;
8756             return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0);
8757         }
8758     #endif
8759     #if defined(C89ATOMIC_HAS_32)
8760         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order)
8761         {
8762             (void)order;
8763             return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0);
8764         }
8765     #endif
8766     #if defined(C89ATOMIC_HAS_64)
8767         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order)
8768         {
8769             (void)order;
8770             return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0);
8771         }
8772     #endif
8773     #if defined(C89ATOMIC_HAS_8)
8774         #define c89atomic_store_explicit_8( dst, src, order) (void)c89atomic_exchange_explicit_8 (dst, src, order)
8775     #endif
8776     #if defined(C89ATOMIC_HAS_16)
8777         #define c89atomic_store_explicit_16(dst, src, order) (void)c89atomic_exchange_explicit_16(dst, src, order)
8778     #endif
8779     #if defined(C89ATOMIC_HAS_32)
8780         #define c89atomic_store_explicit_32(dst, src, order) (void)c89atomic_exchange_explicit_32(dst, src, order)
8781     #endif
8782     #if defined(C89ATOMIC_HAS_64)
8783         #define c89atomic_store_explicit_64(dst, src, order) (void)c89atomic_exchange_explicit_64(dst, src, order)
8784     #endif
8785     #if defined(C89ATOMIC_HAS_8)
8786         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8787         {
8788             c89atomic_uint8 oldValue;
8789             c89atomic_uint8 newValue;
8790             do {
8791                 oldValue = *dst;
8792                 newValue = (c89atomic_uint8)(oldValue - src);
8793             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
8794             (void)order;
8795             return oldValue;
8796         }
8797     #endif
8798     #if defined(C89ATOMIC_HAS_16)
8799         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8800         {
8801             c89atomic_uint16 oldValue;
8802             c89atomic_uint16 newValue;
8803             do {
8804                 oldValue = *dst;
8805                 newValue = (c89atomic_uint16)(oldValue - src);
8806             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
8807             (void)order;
8808             return oldValue;
8809         }
8810     #endif
8811     #if defined(C89ATOMIC_HAS_32)
8812         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8813         {
8814             c89atomic_uint32 oldValue;
8815             c89atomic_uint32 newValue;
8816             do {
8817                 oldValue = *dst;
8818                 newValue = oldValue - src;
8819             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
8820             (void)order;
8821             return oldValue;
8822         }
8823     #endif
8824     #if defined(C89ATOMIC_HAS_64)
8825         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8826         {
8827             c89atomic_uint64 oldValue;
8828             c89atomic_uint64 newValue;
8829             do {
8830                 oldValue = *dst;
8831                 newValue = oldValue - src;
8832             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
8833             (void)order;
8834             return oldValue;
8835         }
8836     #endif
8837     #if defined(C89ATOMIC_HAS_8)
8838         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8839         {
8840             c89atomic_uint8 oldValue;
8841             c89atomic_uint8 newValue;
8842             do {
8843                 oldValue = *dst;
8844                 newValue = (c89atomic_uint8)(oldValue & src);
8845             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
8846             (void)order;
8847             return oldValue;
8848         }
8849     #endif
8850     #if defined(C89ATOMIC_HAS_16)
8851         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8852         {
8853             c89atomic_uint16 oldValue;
8854             c89atomic_uint16 newValue;
8855             do {
8856                 oldValue = *dst;
8857                 newValue = (c89atomic_uint16)(oldValue & src);
8858             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
8859             (void)order;
8860             return oldValue;
8861         }
8862     #endif
8863     #if defined(C89ATOMIC_HAS_32)
8864         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8865         {
8866             c89atomic_uint32 oldValue;
8867             c89atomic_uint32 newValue;
8868             do {
8869                 oldValue = *dst;
8870                 newValue = oldValue & src;
8871             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
8872             (void)order;
8873             return oldValue;
8874         }
8875     #endif
8876     #if defined(C89ATOMIC_HAS_64)
8877         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8878         {
8879             c89atomic_uint64 oldValue;
8880             c89atomic_uint64 newValue;
8881             do {
8882                 oldValue = *dst;
8883                 newValue = oldValue & src;
8884             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
8885             (void)order;
8886             return oldValue;
8887         }
8888     #endif
8889     #if defined(C89ATOMIC_HAS_8)
8890         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8891         {
8892             c89atomic_uint8 oldValue;
8893             c89atomic_uint8 newValue;
8894             do {
8895                 oldValue = *dst;
8896                 newValue = (c89atomic_uint8)(oldValue ^ src);
8897             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
8898             (void)order;
8899             return oldValue;
8900         }
8901     #endif
8902     #if defined(C89ATOMIC_HAS_16)
8903         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8904         {
8905             c89atomic_uint16 oldValue;
8906             c89atomic_uint16 newValue;
8907             do {
8908                 oldValue = *dst;
8909                 newValue = (c89atomic_uint16)(oldValue ^ src);
8910             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
8911             (void)order;
8912             return oldValue;
8913         }
8914     #endif
8915     #if defined(C89ATOMIC_HAS_32)
8916         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8917         {
8918             c89atomic_uint32 oldValue;
8919             c89atomic_uint32 newValue;
8920             do {
8921                 oldValue = *dst;
8922                 newValue = oldValue ^ src;
8923             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
8924             (void)order;
8925             return oldValue;
8926         }
8927     #endif
8928     #if defined(C89ATOMIC_HAS_64)
8929         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8930         {
8931             c89atomic_uint64 oldValue;
8932             c89atomic_uint64 newValue;
8933             do {
8934                 oldValue = *dst;
8935                 newValue = oldValue ^ src;
8936             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
8937             (void)order;
8938             return oldValue;
8939         }
8940     #endif
8941     #if defined(C89ATOMIC_HAS_8)
8942         static C89ATOMIC_INLINE c89atomic_uint8 __stdcall c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
8943         {
8944             c89atomic_uint8 oldValue;
8945             c89atomic_uint8 newValue;
8946             do {
8947                 oldValue = *dst;
8948                 newValue = (c89atomic_uint8)(oldValue | src);
8949             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
8950             (void)order;
8951             return oldValue;
8952         }
8953     #endif
8954     #if defined(C89ATOMIC_HAS_16)
8955         static C89ATOMIC_INLINE c89atomic_uint16 __stdcall c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
8956         {
8957             c89atomic_uint16 oldValue;
8958             c89atomic_uint16 newValue;
8959             do {
8960                 oldValue = *dst;
8961                 newValue = (c89atomic_uint16)(oldValue | src);
8962             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
8963             (void)order;
8964             return oldValue;
8965         }
8966     #endif
8967     #if defined(C89ATOMIC_HAS_32)
8968         static C89ATOMIC_INLINE c89atomic_uint32 __stdcall c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
8969         {
8970             c89atomic_uint32 oldValue;
8971             c89atomic_uint32 newValue;
8972             do {
8973                 oldValue = *dst;
8974                 newValue = oldValue | src;
8975             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
8976             (void)order;
8977             return oldValue;
8978         }
8979     #endif
8980     #if defined(C89ATOMIC_HAS_64)
8981         static C89ATOMIC_INLINE c89atomic_uint64 __stdcall c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
8982         {
8983             c89atomic_uint64 oldValue;
8984             c89atomic_uint64 newValue;
8985             do {
8986                 oldValue = *dst;
8987                 newValue = oldValue | src;
8988             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
8989             (void)order;
8990             return oldValue;
8991         }
8992     #endif
8993     #if defined(C89ATOMIC_HAS_8)
8994         #define c89atomic_test_and_set_explicit_8( dst, order) c89atomic_exchange_explicit_8 (dst, 1, order)
8995     #endif
8996     #if defined(C89ATOMIC_HAS_16)
8997         #define c89atomic_test_and_set_explicit_16(dst, order) c89atomic_exchange_explicit_16(dst, 1, order)
8998     #endif
8999     #if defined(C89ATOMIC_HAS_32)
9000         #define c89atomic_test_and_set_explicit_32(dst, order) c89atomic_exchange_explicit_32(dst, 1, order)
9001     #endif
9002     #if defined(C89ATOMIC_HAS_64)
9003         #define c89atomic_test_and_set_explicit_64(dst, order) c89atomic_exchange_explicit_64(dst, 1, order)
9004     #endif
9005     #if defined(C89ATOMIC_HAS_8)
9006         #define c89atomic_clear_explicit_8( dst, order) c89atomic_store_explicit_8 (dst, 0, order)
9007     #endif
9008     #if defined(C89ATOMIC_HAS_16)
9009         #define c89atomic_clear_explicit_16(dst, order) c89atomic_store_explicit_16(dst, 0, order)
9010     #endif
9011     #if defined(C89ATOMIC_HAS_32)
9012         #define c89atomic_clear_explicit_32(dst, order) c89atomic_store_explicit_32(dst, 0, order)
9013     #endif
9014     #if defined(C89ATOMIC_HAS_64)
9015         #define c89atomic_clear_explicit_64(dst, order) c89atomic_store_explicit_64(dst, 0, order)
9016     #endif
9017     #if defined(C89ATOMIC_HAS_8)
9018         typedef c89atomic_uint8 c89atomic_flag;
9019         #define c89atomic_flag_test_and_set_explicit(ptr, order)    (c89atomic_bool)c89atomic_test_and_set_explicit_8(ptr, order)
9020         #define c89atomic_flag_clear_explicit(ptr, order)           c89atomic_clear_explicit_8(ptr, order)
9021         #define c89atoimc_flag_load_explicit(ptr, order)            c89atomic_load_explicit_8(ptr, order)
9022     #else
9023         typedef c89atomic_uint32 c89atomic_flag;
9024         #define c89atomic_flag_test_and_set_explicit(ptr, order)    (c89atomic_bool)c89atomic_test_and_set_explicit_32(ptr, order)
9025         #define c89atomic_flag_clear_explicit(ptr, order)           c89atomic_clear_explicit_32(ptr, order)
9026         #define c89atoimc_flag_load_explicit(ptr, order)            c89atomic_load_explicit_32(ptr, order)
9027     #endif
9028 #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
9029     #define C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE
9030     #define C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE
9031     #define c89atomic_memory_order_relaxed                          __ATOMIC_RELAXED
9032     #define c89atomic_memory_order_consume                          __ATOMIC_CONSUME
9033     #define c89atomic_memory_order_acquire                          __ATOMIC_ACQUIRE
9034     #define c89atomic_memory_order_release                          __ATOMIC_RELEASE
9035     #define c89atomic_memory_order_acq_rel                          __ATOMIC_ACQ_REL
9036     #define c89atomic_memory_order_seq_cst                          __ATOMIC_SEQ_CST
9037     #define c89atomic_compiler_fence()                              __asm__ __volatile__("":::"memory")
9038     #define c89atomic_thread_fence(order)                           __atomic_thread_fence(order)
9039     #define c89atomic_signal_fence(order)                           __atomic_signal_fence(order)
9040     #define c89atomic_is_lock_free_8(ptr)                           __atomic_is_lock_free(1, ptr)
9041     #define c89atomic_is_lock_free_16(ptr)                          __atomic_is_lock_free(2, ptr)
9042     #define c89atomic_is_lock_free_32(ptr)                          __atomic_is_lock_free(4, ptr)
9043     #define c89atomic_is_lock_free_64(ptr)                          __atomic_is_lock_free(8, ptr)
9044     #define c89atomic_test_and_set_explicit_8( dst, order)          __atomic_exchange_n(dst, 1, order)
9045     #define c89atomic_test_and_set_explicit_16(dst, order)          __atomic_exchange_n(dst, 1, order)
9046     #define c89atomic_test_and_set_explicit_32(dst, order)          __atomic_exchange_n(dst, 1, order)
9047     #define c89atomic_test_and_set_explicit_64(dst, order)          __atomic_exchange_n(dst, 1, order)
9048     #define c89atomic_clear_explicit_8( dst, order)                 __atomic_store_n(dst, 0, order)
9049     #define c89atomic_clear_explicit_16(dst, order)                 __atomic_store_n(dst, 0, order)
9050     #define c89atomic_clear_explicit_32(dst, order)                 __atomic_store_n(dst, 0, order)
9051     #define c89atomic_clear_explicit_64(dst, order)                 __atomic_store_n(dst, 0, order)
9052     #define c89atomic_store_explicit_8( dst, src, order)            __atomic_store_n(dst, src, order)
9053     #define c89atomic_store_explicit_16(dst, src, order)            __atomic_store_n(dst, src, order)
9054     #define c89atomic_store_explicit_32(dst, src, order)            __atomic_store_n(dst, src, order)
9055     #define c89atomic_store_explicit_64(dst, src, order)            __atomic_store_n(dst, src, order)
9056     #define c89atomic_load_explicit_8( dst, order)                  __atomic_load_n(dst, order)
9057     #define c89atomic_load_explicit_16(dst, order)                  __atomic_load_n(dst, order)
9058     #define c89atomic_load_explicit_32(dst, order)                  __atomic_load_n(dst, order)
9059     #define c89atomic_load_explicit_64(dst, order)                  __atomic_load_n(dst, order)
9060     #define c89atomic_exchange_explicit_8( dst, src, order)         __atomic_exchange_n(dst, src, order)
9061     #define c89atomic_exchange_explicit_16(dst, src, order)         __atomic_exchange_n(dst, src, order)
9062     #define c89atomic_exchange_explicit_32(dst, src, order)         __atomic_exchange_n(dst, src, order)
9063     #define c89atomic_exchange_explicit_64(dst, src, order)         __atomic_exchange_n(dst, src, order)
9064     #define c89atomic_compare_exchange_strong_explicit_8( dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
9065     #define c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
9066     #define c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
9067     #define c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder)   __atomic_compare_exchange_n(dst, expected, desired, 0, successOrder, failureOrder)
9068     #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
9069     #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
9070     #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
9071     #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder)     __atomic_compare_exchange_n(dst, expected, desired, 1, successOrder, failureOrder)
9072     #define c89atomic_fetch_add_explicit_8( dst, src, order)        __atomic_fetch_add(dst, src, order)
9073     #define c89atomic_fetch_add_explicit_16(dst, src, order)        __atomic_fetch_add(dst, src, order)
9074     #define c89atomic_fetch_add_explicit_32(dst, src, order)        __atomic_fetch_add(dst, src, order)
9075     #define c89atomic_fetch_add_explicit_64(dst, src, order)        __atomic_fetch_add(dst, src, order)
9076     #define c89atomic_fetch_sub_explicit_8( dst, src, order)        __atomic_fetch_sub(dst, src, order)
9077     #define c89atomic_fetch_sub_explicit_16(dst, src, order)        __atomic_fetch_sub(dst, src, order)
9078     #define c89atomic_fetch_sub_explicit_32(dst, src, order)        __atomic_fetch_sub(dst, src, order)
9079     #define c89atomic_fetch_sub_explicit_64(dst, src, order)        __atomic_fetch_sub(dst, src, order)
9080     #define c89atomic_fetch_or_explicit_8( dst, src, order)         __atomic_fetch_or(dst, src, order)
9081     #define c89atomic_fetch_or_explicit_16(dst, src, order)         __atomic_fetch_or(dst, src, order)
9082     #define c89atomic_fetch_or_explicit_32(dst, src, order)         __atomic_fetch_or(dst, src, order)
9083     #define c89atomic_fetch_or_explicit_64(dst, src, order)         __atomic_fetch_or(dst, src, order)
9084     #define c89atomic_fetch_xor_explicit_8( dst, src, order)        __atomic_fetch_xor(dst, src, order)
9085     #define c89atomic_fetch_xor_explicit_16(dst, src, order)        __atomic_fetch_xor(dst, src, order)
9086     #define c89atomic_fetch_xor_explicit_32(dst, src, order)        __atomic_fetch_xor(dst, src, order)
9087     #define c89atomic_fetch_xor_explicit_64(dst, src, order)        __atomic_fetch_xor(dst, src, order)
9088     #define c89atomic_fetch_and_explicit_8( dst, src, order)        __atomic_fetch_and(dst, src, order)
9089     #define c89atomic_fetch_and_explicit_16(dst, src, order)        __atomic_fetch_and(dst, src, order)
9090     #define c89atomic_fetch_and_explicit_32(dst, src, order)        __atomic_fetch_and(dst, src, order)
9091     #define c89atomic_fetch_and_explicit_64(dst, src, order)        __atomic_fetch_and(dst, src, order)
9092     #define c89atomic_compare_and_swap_8 (dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9093     #define c89atomic_compare_and_swap_16(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9094     #define c89atomic_compare_and_swap_32(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9095     #define c89atomic_compare_and_swap_64(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9096     typedef c89atomic_uint8 c89atomic_flag;
9097     #define c89atomic_flag_test_and_set_explicit(dst, order)        (c89atomic_bool)__atomic_test_and_set(dst, order)
9098     #define c89atomic_flag_clear_explicit(dst, order)               __atomic_clear(dst, order)
9099     #define c89atoimc_flag_load_explicit(ptr, order)                c89atomic_load_explicit_8(ptr, order)
9100 #else
9101     #define c89atomic_memory_order_relaxed  1
9102     #define c89atomic_memory_order_consume  2
9103     #define c89atomic_memory_order_acquire  3
9104     #define c89atomic_memory_order_release  4
9105     #define c89atomic_memory_order_acq_rel  5
9106     #define c89atomic_memory_order_seq_cst  6
9107     #define c89atomic_compiler_fence() __asm__ __volatile__("":::"memory")
9108     #if defined(__GNUC__)
9109         #define c89atomic_thread_fence(order) __sync_synchronize(), (void)order
9110         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9111         {
9112             if (order > c89atomic_memory_order_acquire) {
9113                 __sync_synchronize();
9114             }
9115             return __sync_lock_test_and_set(dst, src);
9116         }
9117         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9118         {
9119             c89atomic_uint16 oldValue;
9120             do {
9121                 oldValue = *dst;
9122             } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
9123             (void)order;
9124             return oldValue;
9125         }
9126         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9127         {
9128             c89atomic_uint32 oldValue;
9129             do {
9130                 oldValue = *dst;
9131             } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
9132             (void)order;
9133             return oldValue;
9134         }
9135         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9136         {
9137             c89atomic_uint64 oldValue;
9138             do {
9139                 oldValue = *dst;
9140             } while (__sync_val_compare_and_swap(dst, oldValue, src) != oldValue);
9141             (void)order;
9142             return oldValue;
9143         }
9144         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9145         {
9146             (void)order;
9147             return __sync_fetch_and_add(dst, src);
9148         }
9149         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9150         {
9151             (void)order;
9152             return __sync_fetch_and_add(dst, src);
9153         }
9154         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9155         {
9156             (void)order;
9157             return __sync_fetch_and_add(dst, src);
9158         }
9159         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9160         {
9161             (void)order;
9162             return __sync_fetch_and_add(dst, src);
9163         }
9164         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9165         {
9166             (void)order;
9167             return __sync_fetch_and_sub(dst, src);
9168         }
9169         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9170         {
9171             (void)order;
9172             return __sync_fetch_and_sub(dst, src);
9173         }
9174         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9175         {
9176             (void)order;
9177             return __sync_fetch_and_sub(dst, src);
9178         }
9179         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9180         {
9181             (void)order;
9182             return __sync_fetch_and_sub(dst, src);
9183         }
9184         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9185         {
9186             (void)order;
9187             return __sync_fetch_and_or(dst, src);
9188         }
9189         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9190         {
9191             (void)order;
9192             return __sync_fetch_and_or(dst, src);
9193         }
9194         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9195         {
9196             (void)order;
9197             return __sync_fetch_and_or(dst, src);
9198         }
9199         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9200         {
9201             (void)order;
9202             return __sync_fetch_and_or(dst, src);
9203         }
9204         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9205         {
9206             (void)order;
9207             return __sync_fetch_and_xor(dst, src);
9208         }
9209         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9210         {
9211             (void)order;
9212             return __sync_fetch_and_xor(dst, src);
9213         }
9214         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9215         {
9216             (void)order;
9217             return __sync_fetch_and_xor(dst, src);
9218         }
9219         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9220         {
9221             (void)order;
9222             return __sync_fetch_and_xor(dst, src);
9223         }
9224         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9225         {
9226             (void)order;
9227             return __sync_fetch_and_and(dst, src);
9228         }
9229         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9230         {
9231             (void)order;
9232             return __sync_fetch_and_and(dst, src);
9233         }
9234         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9235         {
9236             (void)order;
9237             return __sync_fetch_and_and(dst, src);
9238         }
9239         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9240         {
9241             (void)order;
9242             return __sync_fetch_and_and(dst, src);
9243         }
9244         #define c89atomic_compare_and_swap_8( dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9245         #define c89atomic_compare_and_swap_16(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9246         #define c89atomic_compare_and_swap_32(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9247         #define c89atomic_compare_and_swap_64(dst, expected, desired)   __sync_val_compare_and_swap(dst, expected, desired)
9248     #else
9249         #if defined(C89ATOMIC_X86)
9250             #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addl $0, (%%esp)" ::: "memory", "cc")
9251         #elif defined(C89ATOMIC_X64)
9252             #define c89atomic_thread_fence(order) __asm__ __volatile__("lock; addq $0, (%%rsp)" ::: "memory", "cc")
9253         #else
9254             #error Unsupported architecture. Please submit a feature request.
9255         #endif
9256         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_compare_and_swap_8(volatile c89atomic_uint8* dst, c89atomic_uint8 expected, c89atomic_uint8 desired)
9257         {
9258             c89atomic_uint8 result;
9259         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9260             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
9261         #else
9262             #error Unsupported architecture. Please submit a feature request.
9263         #endif
9264             return result;
9265         }
9266         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_compare_and_swap_16(volatile c89atomic_uint16* dst, c89atomic_uint16 expected, c89atomic_uint16 desired)
9267         {
9268             c89atomic_uint16 result;
9269         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9270             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
9271         #else
9272             #error Unsupported architecture. Please submit a feature request.
9273         #endif
9274             return result;
9275         }
9276         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_compare_and_swap_32(volatile c89atomic_uint32* dst, c89atomic_uint32 expected, c89atomic_uint32 desired)
9277         {
9278             c89atomic_uint32 result;
9279         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9280             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
9281         #else
9282             #error Unsupported architecture. Please submit a feature request.
9283         #endif
9284             return result;
9285         }
9286         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_compare_and_swap_64(volatile c89atomic_uint64* dst, c89atomic_uint64 expected, c89atomic_uint64 desired)
9287         {
9288             volatile c89atomic_uint64 result;
9289         #if defined(C89ATOMIC_X86)
9290             c89atomic_uint32 resultEAX;
9291             c89atomic_uint32 resultEDX;
9292             __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");
9293             result = ((c89atomic_uint64)resultEDX << 32) | resultEAX;
9294         #elif defined(C89ATOMIC_X64)
9295             __asm__ __volatile__("lock; cmpxchg %3, %0" : "+m"(*dst), "=a"(result) : "a"(expected), "d"(desired) : "cc");
9296         #else
9297             #error Unsupported architecture. Please submit a feature request.
9298         #endif
9299             return result;
9300         }
9301         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_exchange_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9302         {
9303             c89atomic_uint8 result = 0;
9304             (void)order;
9305         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9306             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
9307         #else
9308             #error Unsupported architecture. Please submit a feature request.
9309         #endif
9310             return result;
9311         }
9312         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_exchange_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9313         {
9314             c89atomic_uint16 result = 0;
9315             (void)order;
9316         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9317             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
9318         #else
9319             #error Unsupported architecture. Please submit a feature request.
9320         #endif
9321             return result;
9322         }
9323         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_exchange_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9324         {
9325             c89atomic_uint32 result;
9326             (void)order;
9327         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9328             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
9329         #else
9330             #error Unsupported architecture. Please submit a feature request.
9331         #endif
9332             return result;
9333         }
9334         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_exchange_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9335         {
9336             c89atomic_uint64 result;
9337             (void)order;
9338         #if defined(C89ATOMIC_X86)
9339             do {
9340                 result = *dst;
9341             } while (c89atomic_compare_and_swap_64(dst, result, src) != result);
9342         #elif defined(C89ATOMIC_X64)
9343             __asm__ __volatile__("lock; xchg %1, %0" : "+m"(*dst), "=a"(result) : "a"(src));
9344         #else
9345             #error Unsupported architecture. Please submit a feature request.
9346         #endif
9347             return result;
9348         }
9349         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_add_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9350         {
9351             c89atomic_uint8 result;
9352             (void)order;
9353         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9354             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
9355         #else
9356             #error Unsupported architecture. Please submit a feature request.
9357         #endif
9358             return result;
9359         }
9360         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_add_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9361         {
9362             c89atomic_uint16 result;
9363             (void)order;
9364         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9365             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
9366         #else
9367             #error Unsupported architecture. Please submit a feature request.
9368         #endif
9369             return result;
9370         }
9371         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_add_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9372         {
9373             c89atomic_uint32 result;
9374             (void)order;
9375         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9376             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
9377         #else
9378             #error Unsupported architecture. Please submit a feature request.
9379         #endif
9380             return result;
9381         }
9382         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_add_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9383         {
9384         #if defined(C89ATOMIC_X86)
9385             c89atomic_uint64 oldValue;
9386             c89atomic_uint64 newValue;
9387             (void)order;
9388             do {
9389                 oldValue = *dst;
9390                 newValue = oldValue + src;
9391             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
9392             return oldValue;
9393         #elif defined(C89ATOMIC_X64)
9394             c89atomic_uint64 result;
9395             (void)order;
9396             __asm__ __volatile__("lock; xadd %1, %0" : "+m"(*dst), "=a"(result) : "a"(src) : "cc");
9397             return result;
9398         #endif
9399         }
9400         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_sub_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9401         {
9402             c89atomic_uint8 oldValue;
9403             c89atomic_uint8 newValue;
9404             do {
9405                 oldValue = *dst;
9406                 newValue = (c89atomic_uint8)(oldValue - src);
9407             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
9408             (void)order;
9409             return oldValue;
9410         }
9411         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_sub_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9412         {
9413             c89atomic_uint16 oldValue;
9414             c89atomic_uint16 newValue;
9415             do {
9416                 oldValue = *dst;
9417                 newValue = (c89atomic_uint16)(oldValue - src);
9418             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
9419             (void)order;
9420             return oldValue;
9421         }
9422         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_sub_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9423         {
9424             c89atomic_uint32 oldValue;
9425             c89atomic_uint32 newValue;
9426             do {
9427                 oldValue = *dst;
9428                 newValue = oldValue - src;
9429             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
9430             (void)order;
9431             return oldValue;
9432         }
9433         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_sub_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9434         {
9435             c89atomic_uint64 oldValue;
9436             c89atomic_uint64 newValue;
9437             do {
9438                 oldValue = *dst;
9439                 newValue = oldValue - src;
9440             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
9441             (void)order;
9442             return oldValue;
9443         }
9444         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_and_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9445         {
9446             c89atomic_uint8 oldValue;
9447             c89atomic_uint8 newValue;
9448             do {
9449                 oldValue = *dst;
9450                 newValue = (c89atomic_uint8)(oldValue & src);
9451             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
9452             (void)order;
9453             return oldValue;
9454         }
9455         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_and_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9456         {
9457             c89atomic_uint16 oldValue;
9458             c89atomic_uint16 newValue;
9459             do {
9460                 oldValue = *dst;
9461                 newValue = (c89atomic_uint16)(oldValue & src);
9462             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
9463             (void)order;
9464             return oldValue;
9465         }
9466         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_and_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9467         {
9468             c89atomic_uint32 oldValue;
9469             c89atomic_uint32 newValue;
9470             do {
9471                 oldValue = *dst;
9472                 newValue = oldValue & src;
9473             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
9474             (void)order;
9475             return oldValue;
9476         }
9477         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_and_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9478         {
9479             c89atomic_uint64 oldValue;
9480             c89atomic_uint64 newValue;
9481             do {
9482                 oldValue = *dst;
9483                 newValue = oldValue & src;
9484             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
9485             (void)order;
9486             return oldValue;
9487         }
9488         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_xor_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9489         {
9490             c89atomic_uint8 oldValue;
9491             c89atomic_uint8 newValue;
9492             do {
9493                 oldValue = *dst;
9494                 newValue = (c89atomic_uint8)(oldValue ^ src);
9495             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
9496             (void)order;
9497             return oldValue;
9498         }
9499         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_xor_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9500         {
9501             c89atomic_uint16 oldValue;
9502             c89atomic_uint16 newValue;
9503             do {
9504                 oldValue = *dst;
9505                 newValue = (c89atomic_uint16)(oldValue ^ src);
9506             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
9507             (void)order;
9508             return oldValue;
9509         }
9510         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_xor_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9511         {
9512             c89atomic_uint32 oldValue;
9513             c89atomic_uint32 newValue;
9514             do {
9515                 oldValue = *dst;
9516                 newValue = oldValue ^ src;
9517             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
9518             (void)order;
9519             return oldValue;
9520         }
9521         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_xor_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9522         {
9523             c89atomic_uint64 oldValue;
9524             c89atomic_uint64 newValue;
9525             do {
9526                 oldValue = *dst;
9527                 newValue = oldValue ^ src;
9528             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
9529             (void)order;
9530             return oldValue;
9531         }
9532         static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_fetch_or_explicit_8(volatile c89atomic_uint8* dst, c89atomic_uint8 src, c89atomic_memory_order order)
9533         {
9534             c89atomic_uint8 oldValue;
9535             c89atomic_uint8 newValue;
9536             do {
9537                 oldValue = *dst;
9538                 newValue = (c89atomic_uint8)(oldValue | src);
9539             } while (c89atomic_compare_and_swap_8(dst, oldValue, newValue) != oldValue);
9540             (void)order;
9541             return oldValue;
9542         }
9543         static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_fetch_or_explicit_16(volatile c89atomic_uint16* dst, c89atomic_uint16 src, c89atomic_memory_order order)
9544         {
9545             c89atomic_uint16 oldValue;
9546             c89atomic_uint16 newValue;
9547             do {
9548                 oldValue = *dst;
9549                 newValue = (c89atomic_uint16)(oldValue | src);
9550             } while (c89atomic_compare_and_swap_16(dst, oldValue, newValue) != oldValue);
9551             (void)order;
9552             return oldValue;
9553         }
9554         static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_fetch_or_explicit_32(volatile c89atomic_uint32* dst, c89atomic_uint32 src, c89atomic_memory_order order)
9555         {
9556             c89atomic_uint32 oldValue;
9557             c89atomic_uint32 newValue;
9558             do {
9559                 oldValue = *dst;
9560                 newValue = oldValue | src;
9561             } while (c89atomic_compare_and_swap_32(dst, oldValue, newValue) != oldValue);
9562             (void)order;
9563             return oldValue;
9564         }
9565         static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_fetch_or_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64 src, c89atomic_memory_order order)
9566         {
9567             c89atomic_uint64 oldValue;
9568             c89atomic_uint64 newValue;
9569             do {
9570                 oldValue = *dst;
9571                 newValue = oldValue | src;
9572             } while (c89atomic_compare_and_swap_64(dst, oldValue, newValue) != oldValue);
9573             (void)order;
9574             return oldValue;
9575         }
9576     #endif
9577     #define c89atomic_signal_fence(order)                           c89atomic_thread_fence(order)
9578     static C89ATOMIC_INLINE c89atomic_uint8 c89atomic_load_explicit_8(volatile const c89atomic_uint8* ptr, c89atomic_memory_order order)
9579     {
9580         (void)order;
9581         return c89atomic_compare_and_swap_8((c89atomic_uint8*)ptr, 0, 0);
9582     }
9583     static C89ATOMIC_INLINE c89atomic_uint16 c89atomic_load_explicit_16(volatile const c89atomic_uint16* ptr, c89atomic_memory_order order)
9584     {
9585         (void)order;
9586         return c89atomic_compare_and_swap_16((c89atomic_uint16*)ptr, 0, 0);
9587     }
9588     static C89ATOMIC_INLINE c89atomic_uint32 c89atomic_load_explicit_32(volatile const c89atomic_uint32* ptr, c89atomic_memory_order order)
9589     {
9590         (void)order;
9591         return c89atomic_compare_and_swap_32((c89atomic_uint32*)ptr, 0, 0);
9592     }
9593     static C89ATOMIC_INLINE c89atomic_uint64 c89atomic_load_explicit_64(volatile const c89atomic_uint64* ptr, c89atomic_memory_order order)
9594     {
9595         (void)order;
9596         return c89atomic_compare_and_swap_64((c89atomic_uint64*)ptr, 0, 0);
9597     }
9598     #define c89atomic_store_explicit_8( dst, src, order)            (void)c89atomic_exchange_explicit_8 (dst, src, order)
9599     #define c89atomic_store_explicit_16(dst, src, order)            (void)c89atomic_exchange_explicit_16(dst, src, order)
9600     #define c89atomic_store_explicit_32(dst, src, order)            (void)c89atomic_exchange_explicit_32(dst, src, order)
9601     #define c89atomic_store_explicit_64(dst, src, order)            (void)c89atomic_exchange_explicit_64(dst, src, order)
9602     #define c89atomic_test_and_set_explicit_8( dst, order)          c89atomic_exchange_explicit_8 (dst, 1, order)
9603     #define c89atomic_test_and_set_explicit_16(dst, order)          c89atomic_exchange_explicit_16(dst, 1, order)
9604     #define c89atomic_test_and_set_explicit_32(dst, order)          c89atomic_exchange_explicit_32(dst, 1, order)
9605     #define c89atomic_test_and_set_explicit_64(dst, order)          c89atomic_exchange_explicit_64(dst, 1, order)
9606     #define c89atomic_clear_explicit_8( dst, order)                 c89atomic_store_explicit_8 (dst, 0, order)
9607     #define c89atomic_clear_explicit_16(dst, order)                 c89atomic_store_explicit_16(dst, 0, order)
9608     #define c89atomic_clear_explicit_32(dst, order)                 c89atomic_store_explicit_32(dst, 0, order)
9609     #define c89atomic_clear_explicit_64(dst, order)                 c89atomic_store_explicit_64(dst, 0, order)
9610     typedef c89atomic_uint8 c89atomic_flag;
9611     #define c89atomic_flag_test_and_set_explicit(ptr, order)        (c89atomic_bool)c89atomic_test_and_set_explicit_8(ptr, order)
9612     #define c89atomic_flag_clear_explicit(ptr, order)               c89atomic_clear_explicit_8(ptr, order)
9613     #define c89atoimc_flag_load_explicit(ptr, order)                c89atomic_load_explicit_8(ptr, order)
9614 #endif
9615 #if !defined(C89ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE)
9616     #if defined(C89ATOMIC_HAS_8)
9617         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)
9618         {
9619             c89atomic_uint8 expectedValue;
9620             c89atomic_uint8 result;
9621             (void)successOrder;
9622             (void)failureOrder;
9623             expectedValue = c89atomic_load_explicit_8(expected, c89atomic_memory_order_seq_cst);
9624             result = c89atomic_compare_and_swap_8(dst, expectedValue, desired);
9625             if (result == expectedValue) {
9626                 return 1;
9627             } else {
9628                 c89atomic_store_explicit_8(expected, result, failureOrder);
9629                 return 0;
9630             }
9631         }
9632     #endif
9633     #if defined(C89ATOMIC_HAS_16)
9634         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)
9635         {
9636             c89atomic_uint16 expectedValue;
9637             c89atomic_uint16 result;
9638             (void)successOrder;
9639             (void)failureOrder;
9640             expectedValue = c89atomic_load_explicit_16(expected, c89atomic_memory_order_seq_cst);
9641             result = c89atomic_compare_and_swap_16(dst, expectedValue, desired);
9642             if (result == expectedValue) {
9643                 return 1;
9644             } else {
9645                 c89atomic_store_explicit_16(expected, result, failureOrder);
9646                 return 0;
9647             }
9648         }
9649     #endif
9650     #if defined(C89ATOMIC_HAS_32)
9651         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)
9652         {
9653             c89atomic_uint32 expectedValue;
9654             c89atomic_uint32 result;
9655             (void)successOrder;
9656             (void)failureOrder;
9657             expectedValue = c89atomic_load_explicit_32(expected, c89atomic_memory_order_seq_cst);
9658             result = c89atomic_compare_and_swap_32(dst, expectedValue, desired);
9659             if (result == expectedValue) {
9660                 return 1;
9661             } else {
9662                 c89atomic_store_explicit_32(expected, result, failureOrder);
9663                 return 0;
9664             }
9665         }
9666     #endif
9667     #if defined(C89ATOMIC_HAS_64)
9668         c89atomic_bool c89atomic_compare_exchange_strong_explicit_64(volatile c89atomic_uint64* dst, c89atomic_uint64* expected, c89atomic_uint64 desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
9669         {
9670             c89atomic_uint64 expectedValue;
9671             c89atomic_uint64 result;
9672             (void)successOrder;
9673             (void)failureOrder;
9674             expectedValue = c89atomic_load_explicit_64(expected, c89atomic_memory_order_seq_cst);
9675             result = c89atomic_compare_and_swap_64(dst, expectedValue, desired);
9676             if (result == expectedValue) {
9677                 return 1;
9678             } else {
9679                 c89atomic_store_explicit_64(expected, result, failureOrder);
9680                 return 0;
9681             }
9682         }
9683     #endif
9684     #define c89atomic_compare_exchange_weak_explicit_8( dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_8 (dst, expected, desired, successOrder, failureOrder)
9685     #define c89atomic_compare_exchange_weak_explicit_16(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_16(dst, expected, desired, successOrder, failureOrder)
9686     #define c89atomic_compare_exchange_weak_explicit_32(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_32(dst, expected, desired, successOrder, failureOrder)
9687     #define c89atomic_compare_exchange_weak_explicit_64(dst, expected, desired, successOrder, failureOrder) c89atomic_compare_exchange_strong_explicit_64(dst, expected, desired, successOrder, failureOrder)
9688 #endif
9689 #if !defined(C89ATOMIC_HAS_NATIVE_IS_LOCK_FREE)
9690     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_8(volatile void* ptr)
9691     {
9692         (void)ptr;
9693         return 1;
9694     }
9695     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_16(volatile void* ptr)
9696     {
9697         (void)ptr;
9698         return 1;
9699     }
9700     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_32(volatile void* ptr)
9701     {
9702         (void)ptr;
9703         return 1;
9704     }
9705     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_64(volatile void* ptr)
9706     {
9707         (void)ptr;
9708     #if defined(C89ATOMIC_64BIT)
9709         return 1;
9710     #else
9711         #if defined(C89ATOMIC_X86) || defined(C89ATOMIC_X64)
9712             return 1;
9713         #else
9714             return 0;
9715         #endif
9716     #endif
9717     }
9718 #endif
9719 #if defined(C89ATOMIC_64BIT)
9720     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr)
9721     {
9722         return c89atomic_is_lock_free_64((volatile c89atomic_uint64*)ptr);
9723     }
9724     static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order)
9725     {
9726         return (void*)c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order);
9727     }
9728     static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
9729     {
9730         c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order);
9731     }
9732     static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
9733     {
9734         return (void*)c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)src, order);
9735     }
9736     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)
9737     {
9738         return c89atomic_compare_exchange_strong_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder);
9739     }
9740     static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
9741     {
9742         return c89atomic_compare_exchange_weak_explicit_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64*)expected, (c89atomic_uint64)desired, successOrder, failureOrder);
9743     }
9744     static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired)
9745     {
9746         return (void*)c89atomic_compare_and_swap_64((volatile c89atomic_uint64*)dst, (c89atomic_uint64)expected, (c89atomic_uint64)desired);
9747     }
9748 #elif defined(C89ATOMIC_32BIT)
9749     static C89ATOMIC_INLINE c89atomic_bool c89atomic_is_lock_free_ptr(volatile void** ptr)
9750     {
9751         return c89atomic_is_lock_free_32((volatile c89atomic_uint32*)ptr);
9752     }
9753     static C89ATOMIC_INLINE void* c89atomic_load_explicit_ptr(volatile void** ptr, c89atomic_memory_order order)
9754     {
9755         return (void*)c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order);
9756     }
9757     static C89ATOMIC_INLINE void c89atomic_store_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
9758     {
9759         c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order);
9760     }
9761     static C89ATOMIC_INLINE void* c89atomic_exchange_explicit_ptr(volatile void** dst, void* src, c89atomic_memory_order order)
9762     {
9763         return (void*)c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)src, order);
9764     }
9765     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)
9766     {
9767         return c89atomic_compare_exchange_strong_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder);
9768     }
9769     static C89ATOMIC_INLINE c89atomic_bool c89atomic_compare_exchange_weak_explicit_ptr(volatile void** dst, volatile void** expected, void* desired, c89atomic_memory_order successOrder, c89atomic_memory_order failureOrder)
9770     {
9771         return c89atomic_compare_exchange_weak_explicit_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32*)expected, (c89atomic_uint32)desired, successOrder, failureOrder);
9772     }
9773     static C89ATOMIC_INLINE void* c89atomic_compare_and_swap_ptr(volatile void** dst, void* expected, void* desired)
9774     {
9775         return (void*)c89atomic_compare_and_swap_32((volatile c89atomic_uint32*)dst, (c89atomic_uint32)expected, (c89atomic_uint32)desired);
9776     }
9777 #else
9778     #error Unsupported architecture.
9779 #endif
9780 #define c89atomic_flag_test_and_set(ptr)                                c89atomic_flag_test_and_set_explicit(ptr, c89atomic_memory_order_seq_cst)
9781 #define c89atomic_flag_clear(ptr)                                       c89atomic_flag_clear_explicit(ptr, c89atomic_memory_order_seq_cst)
9782 #define c89atomic_store_ptr(dst, src)                                   c89atomic_store_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst)
9783 #define c89atomic_load_ptr(ptr)                                         c89atomic_load_explicit_ptr((volatile void**)ptr, c89atomic_memory_order_seq_cst)
9784 #define c89atomic_exchange_ptr(dst, src)                                c89atomic_exchange_explicit_ptr((volatile void**)dst, (void*)src, c89atomic_memory_order_seq_cst)
9785 #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)
9786 #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)
9787 #define c89atomic_test_and_set_8( ptr)                                  c89atomic_test_and_set_explicit_8( ptr, c89atomic_memory_order_seq_cst)
9788 #define c89atomic_test_and_set_16(ptr)                                  c89atomic_test_and_set_explicit_16(ptr, c89atomic_memory_order_seq_cst)
9789 #define c89atomic_test_and_set_32(ptr)                                  c89atomic_test_and_set_explicit_32(ptr, c89atomic_memory_order_seq_cst)
9790 #define c89atomic_test_and_set_64(ptr)                                  c89atomic_test_and_set_explicit_64(ptr, c89atomic_memory_order_seq_cst)
9791 #define c89atomic_clear_8( ptr)                                         c89atomic_clear_explicit_8( ptr, c89atomic_memory_order_seq_cst)
9792 #define c89atomic_clear_16(ptr)                                         c89atomic_clear_explicit_16(ptr, c89atomic_memory_order_seq_cst)
9793 #define c89atomic_clear_32(ptr)                                         c89atomic_clear_explicit_32(ptr, c89atomic_memory_order_seq_cst)
9794 #define c89atomic_clear_64(ptr)                                         c89atomic_clear_explicit_64(ptr, c89atomic_memory_order_seq_cst)
9795 #define c89atomic_store_8( dst, src)                                    c89atomic_store_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
9796 #define c89atomic_store_16(dst, src)                                    c89atomic_store_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
9797 #define c89atomic_store_32(dst, src)                                    c89atomic_store_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
9798 #define c89atomic_store_64(dst, src)                                    c89atomic_store_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
9799 #define c89atomic_load_8( ptr)                                          c89atomic_load_explicit_8( ptr, c89atomic_memory_order_seq_cst)
9800 #define c89atomic_load_16(ptr)                                          c89atomic_load_explicit_16(ptr, c89atomic_memory_order_seq_cst)
9801 #define c89atomic_load_32(ptr)                                          c89atomic_load_explicit_32(ptr, c89atomic_memory_order_seq_cst)
9802 #define c89atomic_load_64(ptr)                                          c89atomic_load_explicit_64(ptr, c89atomic_memory_order_seq_cst)
9803 #define c89atomic_exchange_8( dst, src)                                 c89atomic_exchange_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
9804 #define c89atomic_exchange_16(dst, src)                                 c89atomic_exchange_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
9805 #define c89atomic_exchange_32(dst, src)                                 c89atomic_exchange_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
9806 #define c89atomic_exchange_64(dst, src)                                 c89atomic_exchange_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
9807 #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)
9808 #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)
9809 #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)
9810 #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)
9811 #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)
9812 #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)
9813 #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)
9814 #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)
9815 #define c89atomic_fetch_add_8( dst, src)                                c89atomic_fetch_add_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
9816 #define c89atomic_fetch_add_16(dst, src)                                c89atomic_fetch_add_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
9817 #define c89atomic_fetch_add_32(dst, src)                                c89atomic_fetch_add_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
9818 #define c89atomic_fetch_add_64(dst, src)                                c89atomic_fetch_add_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
9819 #define c89atomic_fetch_sub_8( dst, src)                                c89atomic_fetch_sub_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
9820 #define c89atomic_fetch_sub_16(dst, src)                                c89atomic_fetch_sub_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
9821 #define c89atomic_fetch_sub_32(dst, src)                                c89atomic_fetch_sub_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
9822 #define c89atomic_fetch_sub_64(dst, src)                                c89atomic_fetch_sub_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
9823 #define c89atomic_fetch_or_8( dst, src)                                 c89atomic_fetch_or_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
9824 #define c89atomic_fetch_or_16(dst, src)                                 c89atomic_fetch_or_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
9825 #define c89atomic_fetch_or_32(dst, src)                                 c89atomic_fetch_or_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
9826 #define c89atomic_fetch_or_64(dst, src)                                 c89atomic_fetch_or_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
9827 #define c89atomic_fetch_xor_8( dst, src)                                c89atomic_fetch_xor_explicit_8( dst, src, c89atomic_memory_order_seq_cst)
9828 #define c89atomic_fetch_xor_16(dst, src)                                c89atomic_fetch_xor_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
9829 #define c89atomic_fetch_xor_32(dst, src)                                c89atomic_fetch_xor_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
9830 #define c89atomic_fetch_xor_64(dst, src)                                c89atomic_fetch_xor_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
9831 #define c89atomic_fetch_and_8( dst, src)                                c89atomic_fetch_and_explicit_8 (dst, src, c89atomic_memory_order_seq_cst)
9832 #define c89atomic_fetch_and_16(dst, src)                                c89atomic_fetch_and_explicit_16(dst, src, c89atomic_memory_order_seq_cst)
9833 #define c89atomic_fetch_and_32(dst, src)                                c89atomic_fetch_and_explicit_32(dst, src, c89atomic_memory_order_seq_cst)
9834 #define c89atomic_fetch_and_64(dst, src)                                c89atomic_fetch_and_explicit_64(dst, src, c89atomic_memory_order_seq_cst)
9835 #define c89atomic_test_and_set_explicit_i8( ptr, order)                 (c89atomic_int8 )c89atomic_test_and_set_explicit_8( (c89atomic_uint8* )ptr, order)
9836 #define c89atomic_test_and_set_explicit_i16(ptr, order)                 (c89atomic_int16)c89atomic_test_and_set_explicit_16((c89atomic_uint16*)ptr, order)
9837 #define c89atomic_test_and_set_explicit_i32(ptr, order)                 (c89atomic_int32)c89atomic_test_and_set_explicit_32((c89atomic_uint32*)ptr, order)
9838 #define c89atomic_test_and_set_explicit_i64(ptr, order)                 (c89atomic_int64)c89atomic_test_and_set_explicit_64((c89atomic_uint64*)ptr, order)
9839 #define c89atomic_clear_explicit_i8( ptr, order)                        c89atomic_clear_explicit_8( (c89atomic_uint8* )ptr, order)
9840 #define c89atomic_clear_explicit_i16(ptr, order)                        c89atomic_clear_explicit_16((c89atomic_uint16*)ptr, order)
9841 #define c89atomic_clear_explicit_i32(ptr, order)                        c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order)
9842 #define c89atomic_clear_explicit_i64(ptr, order)                        c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order)
9843 #define c89atomic_store_explicit_i8( dst, src, order)                   (c89atomic_int8 )c89atomic_store_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
9844 #define c89atomic_store_explicit_i16(dst, src, order)                   (c89atomic_int16)c89atomic_store_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
9845 #define c89atomic_store_explicit_i32(dst, src, order)                   (c89atomic_int32)c89atomic_store_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
9846 #define c89atomic_store_explicit_i64(dst, src, order)                   (c89atomic_int64)c89atomic_store_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
9847 #define c89atomic_load_explicit_i8( ptr, order)                         (c89atomic_int8 )c89atomic_load_explicit_8( (c89atomic_uint8* )ptr, order)
9848 #define c89atomic_load_explicit_i16(ptr, order)                         (c89atomic_int16)c89atomic_load_explicit_16((c89atomic_uint16*)ptr, order)
9849 #define c89atomic_load_explicit_i32(ptr, order)                         (c89atomic_int32)c89atomic_load_explicit_32((c89atomic_uint32*)ptr, order)
9850 #define c89atomic_load_explicit_i64(ptr, order)                         (c89atomic_int64)c89atomic_load_explicit_64((c89atomic_uint64*)ptr, order)
9851 #define c89atomic_exchange_explicit_i8( dst, src, order)                (c89atomic_int8 )c89atomic_exchange_explicit_8 ((c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
9852 #define c89atomic_exchange_explicit_i16(dst, src, order)                (c89atomic_int16)c89atomic_exchange_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
9853 #define c89atomic_exchange_explicit_i32(dst, src, order)                (c89atomic_int32)c89atomic_exchange_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
9854 #define c89atomic_exchange_explicit_i64(dst, src, order)                (c89atomic_int64)c89atomic_exchange_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
9855 #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)
9856 #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)
9857 #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)
9858 #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)
9859 #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)
9860 #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)
9861 #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)
9862 #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)
9863 #define c89atomic_fetch_add_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_add_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
9864 #define c89atomic_fetch_add_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_add_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
9865 #define c89atomic_fetch_add_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_add_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
9866 #define c89atomic_fetch_add_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_add_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
9867 #define c89atomic_fetch_sub_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_sub_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
9868 #define c89atomic_fetch_sub_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_sub_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
9869 #define c89atomic_fetch_sub_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_sub_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
9870 #define c89atomic_fetch_sub_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_sub_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
9871 #define c89atomic_fetch_or_explicit_i8( dst, src, order)                (c89atomic_int8 )c89atomic_fetch_or_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
9872 #define c89atomic_fetch_or_explicit_i16(dst, src, order)                (c89atomic_int16)c89atomic_fetch_or_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
9873 #define c89atomic_fetch_or_explicit_i32(dst, src, order)                (c89atomic_int32)c89atomic_fetch_or_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
9874 #define c89atomic_fetch_or_explicit_i64(dst, src, order)                (c89atomic_int64)c89atomic_fetch_or_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
9875 #define c89atomic_fetch_xor_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_xor_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
9876 #define c89atomic_fetch_xor_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_xor_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
9877 #define c89atomic_fetch_xor_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_xor_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
9878 #define c89atomic_fetch_xor_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_xor_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
9879 #define c89atomic_fetch_and_explicit_i8( dst, src, order)               (c89atomic_int8 )c89atomic_fetch_and_explicit_8( (c89atomic_uint8* )dst, (c89atomic_uint8 )src, order)
9880 #define c89atomic_fetch_and_explicit_i16(dst, src, order)               (c89atomic_int16)c89atomic_fetch_and_explicit_16((c89atomic_uint16*)dst, (c89atomic_uint16)src, order)
9881 #define c89atomic_fetch_and_explicit_i32(dst, src, order)               (c89atomic_int32)c89atomic_fetch_and_explicit_32((c89atomic_uint32*)dst, (c89atomic_uint32)src, order)
9882 #define c89atomic_fetch_and_explicit_i64(dst, src, order)               (c89atomic_int64)c89atomic_fetch_and_explicit_64((c89atomic_uint64*)dst, (c89atomic_uint64)src, order)
9883 #define c89atomic_test_and_set_i8( ptr)                                 c89atomic_test_and_set_explicit_i8( ptr, c89atomic_memory_order_seq_cst)
9884 #define c89atomic_test_and_set_i16(ptr)                                 c89atomic_test_and_set_explicit_i16(ptr, c89atomic_memory_order_seq_cst)
9885 #define c89atomic_test_and_set_i32(ptr)                                 c89atomic_test_and_set_explicit_i32(ptr, c89atomic_memory_order_seq_cst)
9886 #define c89atomic_test_and_set_i64(ptr)                                 c89atomic_test_and_set_explicit_i64(ptr, c89atomic_memory_order_seq_cst)
9887 #define c89atomic_clear_i8( ptr)                                        c89atomic_clear_explicit_i8( ptr, c89atomic_memory_order_seq_cst)
9888 #define c89atomic_clear_i16(ptr)                                        c89atomic_clear_explicit_i16(ptr, c89atomic_memory_order_seq_cst)
9889 #define c89atomic_clear_i32(ptr)                                        c89atomic_clear_explicit_i32(ptr, c89atomic_memory_order_seq_cst)
9890 #define c89atomic_clear_i64(ptr)                                        c89atomic_clear_explicit_i64(ptr, c89atomic_memory_order_seq_cst)
9891 #define c89atomic_store_i8( dst, src)                                   c89atomic_store_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
9892 #define c89atomic_store_i16(dst, src)                                   c89atomic_store_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
9893 #define c89atomic_store_i32(dst, src)                                   c89atomic_store_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
9894 #define c89atomic_store_i64(dst, src)                                   c89atomic_store_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
9895 #define c89atomic_load_i8( ptr)                                         c89atomic_load_explicit_i8( ptr, c89atomic_memory_order_seq_cst)
9896 #define c89atomic_load_i16(ptr)                                         c89atomic_load_explicit_i16(ptr, c89atomic_memory_order_seq_cst)
9897 #define c89atomic_load_i32(ptr)                                         c89atomic_load_explicit_i32(ptr, c89atomic_memory_order_seq_cst)
9898 #define c89atomic_load_i64(ptr)                                         c89atomic_load_explicit_i64(ptr, c89atomic_memory_order_seq_cst)
9899 #define c89atomic_exchange_i8( dst, src)                                c89atomic_exchange_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
9900 #define c89atomic_exchange_i16(dst, src)                                c89atomic_exchange_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
9901 #define c89atomic_exchange_i32(dst, src)                                c89atomic_exchange_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
9902 #define c89atomic_exchange_i64(dst, src)                                c89atomic_exchange_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
9903 #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)
9904 #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)
9905 #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)
9906 #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)
9907 #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)
9908 #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)
9909 #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)
9910 #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)
9911 #define c89atomic_fetch_add_i8( dst, src)                               c89atomic_fetch_add_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
9912 #define c89atomic_fetch_add_i16(dst, src)                               c89atomic_fetch_add_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
9913 #define c89atomic_fetch_add_i32(dst, src)                               c89atomic_fetch_add_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
9914 #define c89atomic_fetch_add_i64(dst, src)                               c89atomic_fetch_add_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
9915 #define c89atomic_fetch_sub_i8( dst, src)                               c89atomic_fetch_sub_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
9916 #define c89atomic_fetch_sub_i16(dst, src)                               c89atomic_fetch_sub_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
9917 #define c89atomic_fetch_sub_i32(dst, src)                               c89atomic_fetch_sub_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
9918 #define c89atomic_fetch_sub_i64(dst, src)                               c89atomic_fetch_sub_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
9919 #define c89atomic_fetch_or_i8( dst, src)                                c89atomic_fetch_or_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
9920 #define c89atomic_fetch_or_i16(dst, src)                                c89atomic_fetch_or_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
9921 #define c89atomic_fetch_or_i32(dst, src)                                c89atomic_fetch_or_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
9922 #define c89atomic_fetch_or_i64(dst, src)                                c89atomic_fetch_or_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
9923 #define c89atomic_fetch_xor_i8( dst, src)                               c89atomic_fetch_xor_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
9924 #define c89atomic_fetch_xor_i16(dst, src)                               c89atomic_fetch_xor_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
9925 #define c89atomic_fetch_xor_i32(dst, src)                               c89atomic_fetch_xor_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
9926 #define c89atomic_fetch_xor_i64(dst, src)                               c89atomic_fetch_xor_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
9927 #define c89atomic_fetch_and_i8( dst, src)                               c89atomic_fetch_and_explicit_i8( dst, src, c89atomic_memory_order_seq_cst)
9928 #define c89atomic_fetch_and_i16(dst, src)                               c89atomic_fetch_and_explicit_i16(dst, src, c89atomic_memory_order_seq_cst)
9929 #define c89atomic_fetch_and_i32(dst, src)                               c89atomic_fetch_and_explicit_i32(dst, src, c89atomic_memory_order_seq_cst)
9930 #define c89atomic_fetch_and_i64(dst, src)                               c89atomic_fetch_and_explicit_i64(dst, src, c89atomic_memory_order_seq_cst)
9931 typedef union
9932 {
9933     c89atomic_uint32 i;
9934     float f;
9935 } c89atomic_if32;
9936 typedef union
9937 {
9938     c89atomic_uint64 i;
9939     double f;
9940 } c89atomic_if64;
9941 #define c89atomic_clear_explicit_f32(ptr, order)                        c89atomic_clear_explicit_32((c89atomic_uint32*)ptr, order)
9942 #define c89atomic_clear_explicit_f64(ptr, order)                        c89atomic_clear_explicit_64((c89atomic_uint64*)ptr, order)
9943 static C89ATOMIC_INLINE void c89atomic_store_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
9944 {
9945     c89atomic_if32 x;
9946     x.f = src;
9947     c89atomic_store_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
9948 }
9949 static C89ATOMIC_INLINE void c89atomic_store_explicit_f64(volatile float* dst, float src, c89atomic_memory_order order)
9950 {
9951     c89atomic_if64 x;
9952     x.f = src;
9953     c89atomic_store_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
9954 }
9955 static C89ATOMIC_INLINE float c89atomic_load_explicit_f32(volatile float* ptr, c89atomic_memory_order order)
9956 {
9957     c89atomic_if32 r;
9958     r.i = c89atomic_load_explicit_32((volatile c89atomic_uint32*)ptr, order);
9959     return r.f;
9960 }
9961 static C89ATOMIC_INLINE double c89atomic_load_explicit_f64(volatile double* ptr, c89atomic_memory_order order)
9962 {
9963     c89atomic_if64 r;
9964     r.i = c89atomic_load_explicit_64((volatile c89atomic_uint64*)ptr, order);
9965     return r.f;
9966 }
9967 static C89ATOMIC_INLINE float c89atomic_exchange_explicit_f32(volatile float* dst, float src, c89atomic_memory_order order)
9968 {
9969     c89atomic_if32 r;
9970     c89atomic_if32 x;
9971     x.f = src;
9972     r.i = c89atomic_exchange_explicit_32((volatile c89atomic_uint32*)dst, x.i, order);
9973     return r.f;
9974 }
9975 static C89ATOMIC_INLINE double c89atomic_exchange_explicit_f64(volatile double* dst, double src, c89atomic_memory_order order)
9976 {
9977     c89atomic_if64 r;
9978     c89atomic_if64 x;
9979     x.f = src;
9980     r.i = c89atomic_exchange_explicit_64((volatile c89atomic_uint64*)dst, x.i, order);
9981     return r.f;
9982 }
9983 #define c89atomic_clear_f32(ptr)                                        (float )c89atomic_clear_explicit_f32(ptr, c89atomic_memory_order_seq_cst)
9984 #define c89atomic_clear_f64(ptr)                                        (double)c89atomic_clear_explicit_f64(ptr, c89atomic_memory_order_seq_cst)
9985 #define c89atomic_store_f32(dst, src)                                   c89atomic_store_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
9986 #define c89atomic_store_f64(dst, src)                                   c89atomic_store_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
9987 #define c89atomic_load_f32(ptr)                                         (float )c89atomic_load_explicit_f32(ptr, c89atomic_memory_order_seq_cst)
9988 #define c89atomic_load_f64(ptr)                                         (double)c89atomic_load_explicit_f64(ptr, c89atomic_memory_order_seq_cst)
9989 #define c89atomic_exchange_f32(dst, src)                                (float )c89atomic_exchange_explicit_f32(dst, src, c89atomic_memory_order_seq_cst)
9990 #define c89atomic_exchange_f64(dst, src)                                (double)c89atomic_exchange_explicit_f64(dst, src, c89atomic_memory_order_seq_cst)
9991 typedef c89atomic_flag c89atomic_spinlock;
9992 static C89ATOMIC_INLINE void c89atomic_spinlock_lock(volatile c89atomic_spinlock* pSpinlock)
9993 {
9994     for (;;) {
9995         if (c89atomic_flag_test_and_set_explicit(pSpinlock, c89atomic_memory_order_acquire) == 0) {
9996             break;
9997         }
9998         while (c89atoimc_flag_load_explicit(pSpinlock, c89atomic_memory_order_relaxed) == 1) {
9999         }
10000     }
10001 }
10002 static C89ATOMIC_INLINE void c89atomic_spinlock_unlock(volatile c89atomic_spinlock* pSpinlock)
10003 {
10004     c89atomic_flag_clear_explicit(pSpinlock, c89atomic_memory_order_release);
10005 }
10006 #if defined(__cplusplus)
10007 }
10008 #endif
10009 #endif
10010 /* c89atomic.h end */
10011
10012
10013
10014 static void* ma__malloc_default(size_t sz, void* pUserData)
10015 {
10016     (void)pUserData;
10017     return MA_MALLOC(sz);
10018 }
10019
10020 static void* ma__realloc_default(void* p, size_t sz, void* pUserData)
10021 {
10022     (void)pUserData;
10023     return MA_REALLOC(p, sz);
10024 }
10025
10026 static void ma__free_default(void* p, void* pUserData)
10027 {
10028     (void)pUserData;
10029     MA_FREE(p);
10030 }
10031
10032
10033 static void* ma__malloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
10034 {
10035     if (pAllocationCallbacks == NULL) {
10036         return NULL;
10037     }
10038
10039     if (pAllocationCallbacks->onMalloc != NULL) {
10040         return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
10041     }
10042
10043     /* Try using realloc(). */
10044     if (pAllocationCallbacks->onRealloc != NULL) {
10045         return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
10046     }
10047
10048     return NULL;
10049 }
10050
10051 static void* ma__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const ma_allocation_callbacks* pAllocationCallbacks)
10052 {
10053     if (pAllocationCallbacks == NULL) {
10054         return NULL;
10055     }
10056
10057     if (pAllocationCallbacks->onRealloc != NULL) {
10058         return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
10059     }
10060
10061     /* Try emulating realloc() in terms of malloc()/free(). */
10062     if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
10063         void* p2;
10064
10065         p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
10066         if (p2 == NULL) {
10067             return NULL;
10068         }
10069
10070         if (p != NULL) {
10071             MA_COPY_MEMORY(p2, p, szOld);
10072             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
10073         }
10074
10075         return p2;
10076     }
10077
10078     return NULL;
10079 }
10080
10081 static MA_INLINE void* ma__calloc_from_callbacks(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
10082 {
10083     void* p = ma__malloc_from_callbacks(sz, pAllocationCallbacks);
10084     if (p != NULL) {
10085         MA_ZERO_MEMORY(p, sz);
10086     }
10087
10088     return p;
10089 }
10090
10091 static void ma__free_from_callbacks(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
10092 {
10093     if (p == NULL || pAllocationCallbacks == NULL) {
10094         return;
10095     }
10096
10097     if (pAllocationCallbacks->onFree != NULL) {
10098         pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
10099     }
10100 }
10101
10102 static ma_allocation_callbacks ma_allocation_callbacks_init_default(void)
10103 {
10104     ma_allocation_callbacks callbacks;
10105     callbacks.pUserData = NULL;
10106     callbacks.onMalloc  = ma__malloc_default;
10107     callbacks.onRealloc = ma__realloc_default;
10108     callbacks.onFree    = ma__free_default;
10109
10110     return callbacks;
10111 }
10112
10113 static ma_result ma_allocation_callbacks_init_copy(ma_allocation_callbacks* pDst, const ma_allocation_callbacks* pSrc)
10114 {
10115     if (pDst == NULL) {
10116         return MA_INVALID_ARGS;
10117     }
10118
10119     if (pSrc == NULL) {
10120         *pDst = ma_allocation_callbacks_init_default();
10121     } else {
10122         if (pSrc->pUserData == NULL && pSrc->onFree == NULL && pSrc->onMalloc == NULL && pSrc->onRealloc == NULL) {
10123             *pDst = ma_allocation_callbacks_init_default();
10124         } else {
10125             if (pSrc->onFree == NULL || (pSrc->onMalloc == NULL && pSrc->onRealloc == NULL)) {
10126                 return MA_INVALID_ARGS;    /* Invalid allocation callbacks. */
10127             } else {
10128                 *pDst = *pSrc;
10129             }
10130         }
10131     }
10132
10133     return MA_SUCCESS;
10134 }
10135
10136
10137 MA_API ma_uint64 ma_calculate_frame_count_after_resampling(ma_uint32 sampleRateOut, ma_uint32 sampleRateIn, ma_uint64 frameCountIn)
10138 {
10139     /* For robustness we're going to use a resampler object to calculate this since that already has a way of calculating this. */
10140     ma_result result;
10141     ma_uint64 frameCountOut;
10142     ma_resampler_config config;
10143     ma_resampler resampler;
10144
10145     if (sampleRateOut == sampleRateIn) {
10146         return frameCountIn;
10147     }
10148
10149     config = ma_resampler_config_init(ma_format_s16, 1, sampleRateIn, sampleRateOut, ma_resample_algorithm_linear);
10150     result = ma_resampler_init(&config, &resampler);
10151     if (result != MA_SUCCESS) {
10152         return 0;
10153     }
10154
10155     frameCountOut = ma_resampler_get_expected_output_frame_count(&resampler, frameCountIn);
10156
10157     ma_resampler_uninit(&resampler);
10158     return frameCountOut;
10159 }
10160
10161 #ifndef MA_DATA_CONVERTER_STACK_BUFFER_SIZE
10162 #define MA_DATA_CONVERTER_STACK_BUFFER_SIZE     4096
10163 #endif
10164
10165
10166
10167 #if defined(MA_WIN32)
10168 static ma_result ma_result_from_GetLastError(DWORD error)
10169 {
10170     switch (error)
10171     {
10172         case ERROR_SUCCESS:             return MA_SUCCESS;
10173         case ERROR_PATH_NOT_FOUND:      return MA_DOES_NOT_EXIST;
10174         case ERROR_TOO_MANY_OPEN_FILES: return MA_TOO_MANY_OPEN_FILES;
10175         case ERROR_NOT_ENOUGH_MEMORY:   return MA_OUT_OF_MEMORY;
10176         case ERROR_DISK_FULL:           return MA_NO_SPACE;
10177         case ERROR_HANDLE_EOF:          return MA_END_OF_FILE;
10178         case ERROR_NEGATIVE_SEEK:       return MA_BAD_SEEK;
10179         case ERROR_INVALID_PARAMETER:   return MA_INVALID_ARGS;
10180         case ERROR_ACCESS_DENIED:       return MA_ACCESS_DENIED;
10181         case ERROR_SEM_TIMEOUT:         return MA_TIMEOUT;
10182         case ERROR_FILE_NOT_FOUND:      return MA_DOES_NOT_EXIST;
10183         default: break;
10184     }
10185
10186     return MA_ERROR;
10187 }
10188 #endif  /* MA_WIN32 */
10189
10190
10191 /*******************************************************************************
10192
10193 Threading
10194
10195 *******************************************************************************/
10196 #ifndef MA_NO_THREADING
10197 #ifdef MA_WIN32
10198     #define MA_THREADCALL WINAPI
10199     typedef unsigned long ma_thread_result;
10200 #else
10201     #define MA_THREADCALL
10202     typedef void* ma_thread_result;
10203 #endif
10204 typedef ma_thread_result (MA_THREADCALL * ma_thread_entry_proc)(void* pData);
10205
10206 static MA_INLINE ma_result ma_spinlock_lock_ex(volatile ma_spinlock* pSpinlock, ma_bool32 yield)
10207 {
10208     if (pSpinlock == NULL) {
10209         return MA_INVALID_ARGS;
10210     }
10211
10212     for (;;) {
10213         if (c89atomic_exchange_explicit_32(pSpinlock, 1, c89atomic_memory_order_acquire) == 0) {
10214             break;
10215         }
10216
10217         while (c89atomic_load_explicit_32(pSpinlock, c89atomic_memory_order_relaxed) == 1) {
10218             if (yield) {
10219                 ma_yield();
10220             }
10221         }
10222     }
10223
10224     return MA_SUCCESS;
10225 }
10226
10227 MA_API ma_result ma_spinlock_lock(volatile ma_spinlock* pSpinlock)
10228 {
10229     return ma_spinlock_lock_ex(pSpinlock, MA_TRUE);
10230 }
10231
10232 MA_API ma_result ma_spinlock_lock_noyield(volatile ma_spinlock* pSpinlock)
10233 {
10234     return ma_spinlock_lock_ex(pSpinlock, MA_FALSE);
10235 }
10236
10237 MA_API ma_result ma_spinlock_unlock(volatile ma_spinlock* pSpinlock)
10238 {
10239     if (pSpinlock == NULL) {
10240         return MA_INVALID_ARGS;
10241     }
10242
10243     c89atomic_store_explicit_32(pSpinlock, 0, c89atomic_memory_order_release);
10244     return MA_SUCCESS;
10245 }
10246
10247 #ifdef MA_WIN32
10248 static int ma_thread_priority_to_win32(ma_thread_priority priority)
10249 {
10250     switch (priority) {
10251         case ma_thread_priority_idle:     return THREAD_PRIORITY_IDLE;
10252         case ma_thread_priority_lowest:   return THREAD_PRIORITY_LOWEST;
10253         case ma_thread_priority_low:      return THREAD_PRIORITY_BELOW_NORMAL;
10254         case ma_thread_priority_normal:   return THREAD_PRIORITY_NORMAL;
10255         case ma_thread_priority_high:     return THREAD_PRIORITY_ABOVE_NORMAL;
10256         case ma_thread_priority_highest:  return THREAD_PRIORITY_HIGHEST;
10257         case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL;
10258         default:                          return THREAD_PRIORITY_NORMAL;
10259     }
10260 }
10261
10262 static ma_result ma_thread_create__win32(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
10263 {
10264     *pThread = CreateThread(NULL, stackSize, entryProc, pData, 0, NULL);
10265     if (*pThread == NULL) {
10266         return ma_result_from_GetLastError(GetLastError());
10267     }
10268
10269     SetThreadPriority((HANDLE)*pThread, ma_thread_priority_to_win32(priority));
10270
10271     return MA_SUCCESS;
10272 }
10273
10274 static void ma_thread_wait__win32(ma_thread* pThread)
10275 {
10276     WaitForSingleObject((HANDLE)*pThread, INFINITE);
10277     CloseHandle((HANDLE)*pThread);
10278 }
10279
10280
10281 static ma_result ma_mutex_init__win32(ma_mutex* pMutex)
10282 {
10283     *pMutex = CreateEventW(NULL, FALSE, TRUE, NULL);
10284     if (*pMutex == NULL) {
10285         return ma_result_from_GetLastError(GetLastError());
10286     }
10287
10288     return MA_SUCCESS;
10289 }
10290
10291 static void ma_mutex_uninit__win32(ma_mutex* pMutex)
10292 {
10293     CloseHandle((HANDLE)*pMutex);
10294 }
10295
10296 static void ma_mutex_lock__win32(ma_mutex* pMutex)
10297 {
10298     WaitForSingleObject((HANDLE)*pMutex, INFINITE);
10299 }
10300
10301 static void ma_mutex_unlock__win32(ma_mutex* pMutex)
10302 {
10303     SetEvent((HANDLE)*pMutex);
10304 }
10305
10306
10307 static ma_result ma_event_init__win32(ma_event* pEvent)
10308 {
10309     *pEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
10310     if (*pEvent == NULL) {
10311         return ma_result_from_GetLastError(GetLastError());
10312     }
10313
10314     return MA_SUCCESS;
10315 }
10316
10317 static void ma_event_uninit__win32(ma_event* pEvent)
10318 {
10319     CloseHandle((HANDLE)*pEvent);
10320 }
10321
10322 static ma_result ma_event_wait__win32(ma_event* pEvent)
10323 {
10324     DWORD result = WaitForSingleObject((HANDLE)*pEvent, INFINITE);
10325     if (result == WAIT_OBJECT_0) {
10326         return MA_SUCCESS;
10327     }
10328
10329     if (result == WAIT_TIMEOUT) {
10330         return MA_TIMEOUT;
10331     }
10332
10333     return ma_result_from_GetLastError(GetLastError());
10334 }
10335
10336 static ma_result ma_event_signal__win32(ma_event* pEvent)
10337 {
10338     BOOL result = SetEvent((HANDLE)*pEvent);
10339     if (result == 0) {
10340         return ma_result_from_GetLastError(GetLastError());
10341     }
10342
10343     return MA_SUCCESS;
10344 }
10345
10346
10347 static ma_result ma_semaphore_init__win32(int initialValue, ma_semaphore* pSemaphore)
10348 {
10349     *pSemaphore = CreateSemaphoreW(NULL, (LONG)initialValue, LONG_MAX, NULL);
10350     if (*pSemaphore == NULL) {
10351         return ma_result_from_GetLastError(GetLastError());
10352     }
10353
10354     return MA_SUCCESS;
10355 }
10356
10357 static void ma_semaphore_uninit__win32(ma_semaphore* pSemaphore)
10358 {
10359     CloseHandle((HANDLE)*pSemaphore);
10360 }
10361
10362 static ma_result ma_semaphore_wait__win32(ma_semaphore* pSemaphore)
10363 {
10364     DWORD result = WaitForSingleObject((HANDLE)*pSemaphore, INFINITE);
10365     if (result == WAIT_OBJECT_0) {
10366         return MA_SUCCESS;
10367     }
10368
10369     if (result == WAIT_TIMEOUT) {
10370         return MA_TIMEOUT;
10371     }
10372
10373     return ma_result_from_GetLastError(GetLastError());
10374 }
10375
10376 static ma_result ma_semaphore_release__win32(ma_semaphore* pSemaphore)
10377 {
10378     BOOL result = ReleaseSemaphore((HANDLE)*pSemaphore, 1, NULL);
10379     if (result == 0) {
10380         return ma_result_from_GetLastError(GetLastError());
10381     }
10382
10383     return MA_SUCCESS;
10384 }
10385 #endif
10386
10387
10388 #ifdef MA_POSIX
10389 static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
10390 {
10391     int result;
10392     pthread_attr_t* pAttr = NULL;
10393
10394 #if !defined(__EMSCRIPTEN__)
10395     /* Try setting the thread priority. It's not critical if anything fails here. */
10396     pthread_attr_t attr;
10397     if (pthread_attr_init(&attr) == 0) {
10398         int scheduler = -1;
10399         if (priority == ma_thread_priority_idle) {
10400 #ifdef SCHED_IDLE
10401             if (pthread_attr_setschedpolicy(&attr, SCHED_IDLE) == 0) {
10402                 scheduler = SCHED_IDLE;
10403             }
10404 #endif
10405         } else if (priority == ma_thread_priority_realtime) {
10406 #ifdef SCHED_FIFO
10407             if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) {
10408                 scheduler = SCHED_FIFO;
10409             }
10410 #endif
10411 #ifdef MA_LINUX
10412         } else {
10413             scheduler = sched_getscheduler(0);
10414 #endif
10415         }
10416
10417         if (stackSize > 0) {
10418             pthread_attr_setstacksize(&attr, stackSize);
10419         }
10420
10421         if (scheduler != -1) {
10422             int priorityMin = sched_get_priority_min(scheduler);
10423             int priorityMax = sched_get_priority_max(scheduler);
10424             int priorityStep = (priorityMax - priorityMin) / 7;  /* 7 = number of priorities supported by miniaudio. */
10425
10426             struct sched_param sched;
10427             if (pthread_attr_getschedparam(&attr, &sched) == 0) {
10428                 if (priority == ma_thread_priority_idle) {
10429                     sched.sched_priority = priorityMin;
10430                 } else if (priority == ma_thread_priority_realtime) {
10431                     sched.sched_priority = priorityMax;
10432                 } else {
10433                     sched.sched_priority += ((int)priority + 5) * priorityStep;  /* +5 because the lowest priority is -5. */
10434                     if (sched.sched_priority < priorityMin) {
10435                         sched.sched_priority = priorityMin;
10436                     }
10437                     if (sched.sched_priority > priorityMax) {
10438                         sched.sched_priority = priorityMax;
10439                     }
10440                 }
10441
10442                 if (pthread_attr_setschedparam(&attr, &sched) == 0) {
10443                     pAttr = &attr;
10444                 }
10445             }
10446         }
10447     }
10448 #else
10449     /* It's the emscripten build. We'll have a few unused parameters. */
10450     (void)priority;
10451     (void)stackSize;
10452 #endif
10453
10454     result = pthread_create(pThread, pAttr, entryProc, pData);
10455
10456     /* The thread attributes object is no longer required. */
10457     if (pAttr != NULL) {
10458         pthread_attr_destroy(pAttr);
10459     }
10460
10461     if (result != 0) {
10462         return ma_result_from_errno(result);
10463     }
10464
10465     return MA_SUCCESS;
10466 }
10467
10468 static void ma_thread_wait__posix(ma_thread* pThread)
10469 {
10470     pthread_join(*pThread, NULL);
10471     pthread_detach(*pThread);
10472 }
10473
10474
10475 static ma_result ma_mutex_init__posix(ma_mutex* pMutex)
10476 {
10477     int result = pthread_mutex_init((pthread_mutex_t*)pMutex, NULL);
10478     if (result != 0) {
10479         return ma_result_from_errno(result);
10480     }
10481
10482     return MA_SUCCESS;
10483 }
10484
10485 static void ma_mutex_uninit__posix(ma_mutex* pMutex)
10486 {
10487     pthread_mutex_destroy((pthread_mutex_t*)pMutex);
10488 }
10489
10490 static void ma_mutex_lock__posix(ma_mutex* pMutex)
10491 {
10492     pthread_mutex_lock((pthread_mutex_t*)pMutex);
10493 }
10494
10495 static void ma_mutex_unlock__posix(ma_mutex* pMutex)
10496 {
10497     pthread_mutex_unlock((pthread_mutex_t*)pMutex);
10498 }
10499
10500
10501 static ma_result ma_event_init__posix(ma_event* pEvent)
10502 {
10503     int result;
10504
10505     result = pthread_mutex_init(&pEvent->lock, NULL);
10506     if (result != 0) {
10507         return ma_result_from_errno(result);
10508     }
10509
10510     result = pthread_cond_init(&pEvent->cond, NULL);
10511     if (result != 0) {
10512         pthread_mutex_destroy(&pEvent->lock);
10513         return ma_result_from_errno(result);
10514     }
10515
10516     pEvent->value = 0;
10517     return MA_SUCCESS;
10518 }
10519
10520 static void ma_event_uninit__posix(ma_event* pEvent)
10521 {
10522     pthread_cond_destroy(&pEvent->cond);
10523     pthread_mutex_destroy(&pEvent->lock);
10524 }
10525
10526 static ma_result ma_event_wait__posix(ma_event* pEvent)
10527 {
10528     pthread_mutex_lock(&pEvent->lock);
10529     {
10530         while (pEvent->value == 0) {
10531             pthread_cond_wait(&pEvent->cond, &pEvent->lock);
10532         }
10533         pEvent->value = 0;  /* Auto-reset. */
10534     }
10535     pthread_mutex_unlock(&pEvent->lock);
10536
10537     return MA_SUCCESS;
10538 }
10539
10540 static ma_result ma_event_signal__posix(ma_event* pEvent)
10541 {
10542     pthread_mutex_lock(&pEvent->lock);
10543     {
10544         pEvent->value = 1;
10545         pthread_cond_signal(&pEvent->cond);
10546     }
10547     pthread_mutex_unlock(&pEvent->lock);
10548
10549     return MA_SUCCESS;
10550 }
10551
10552
10553 static ma_result ma_semaphore_init__posix(int initialValue, ma_semaphore* pSemaphore)
10554 {
10555     int result;
10556
10557     if (pSemaphore == NULL) {
10558         return MA_INVALID_ARGS;
10559     }
10560
10561     pSemaphore->value = initialValue;
10562
10563     result = pthread_mutex_init(&pSemaphore->lock, NULL);
10564     if (result != 0) {
10565         return ma_result_from_errno(result);  /* Failed to create mutex. */
10566     }
10567
10568     result = pthread_cond_init(&pSemaphore->cond, NULL);
10569     if (result != 0) {
10570         pthread_mutex_destroy(&pSemaphore->lock);
10571         return ma_result_from_errno(result);  /* Failed to create condition variable. */
10572     }
10573
10574     return MA_SUCCESS;
10575 }
10576
10577 static void ma_semaphore_uninit__posix(ma_semaphore* pSemaphore)
10578 {
10579     if (pSemaphore == NULL) {
10580         return;
10581     }
10582
10583     pthread_cond_destroy(&pSemaphore->cond);
10584     pthread_mutex_destroy(&pSemaphore->lock);
10585 }
10586
10587 static ma_result ma_semaphore_wait__posix(ma_semaphore* pSemaphore)
10588 {
10589     if (pSemaphore == NULL) {
10590         return MA_INVALID_ARGS;
10591     }
10592
10593     pthread_mutex_lock(&pSemaphore->lock);
10594     {
10595         /* We need to wait on a condition variable before escaping. We can't return from this function until the semaphore has been signaled. */
10596         while (pSemaphore->value == 0) {
10597             pthread_cond_wait(&pSemaphore->cond, &pSemaphore->lock);
10598         }
10599
10600         pSemaphore->value -= 1;
10601     }
10602     pthread_mutex_unlock(&pSemaphore->lock);
10603
10604     return MA_SUCCESS;
10605 }
10606
10607 static ma_result ma_semaphore_release__posix(ma_semaphore* pSemaphore)
10608 {
10609     if (pSemaphore == NULL) {
10610         return MA_INVALID_ARGS;
10611     }
10612
10613     pthread_mutex_lock(&pSemaphore->lock);
10614     {
10615         pSemaphore->value += 1;
10616         pthread_cond_signal(&pSemaphore->cond);
10617     }
10618     pthread_mutex_unlock(&pSemaphore->lock);
10619
10620     return MA_SUCCESS;
10621 }
10622 #endif
10623
10624 static ma_result ma_thread_create(ma_thread* pThread, ma_thread_priority priority, size_t stackSize, ma_thread_entry_proc entryProc, void* pData)
10625 {
10626     if (pThread == NULL || entryProc == NULL) {
10627         return MA_FALSE;
10628     }
10629
10630 #ifdef MA_WIN32
10631     return ma_thread_create__win32(pThread, priority, stackSize, entryProc, pData);
10632 #endif
10633 #ifdef MA_POSIX
10634     return ma_thread_create__posix(pThread, priority, stackSize, entryProc, pData);
10635 #endif
10636 }
10637
10638 static void ma_thread_wait(ma_thread* pThread)
10639 {
10640     if (pThread == NULL) {
10641         return;
10642     }
10643
10644 #ifdef MA_WIN32
10645     ma_thread_wait__win32(pThread);
10646 #endif
10647 #ifdef MA_POSIX
10648     ma_thread_wait__posix(pThread);
10649 #endif
10650 }
10651
10652
10653 MA_API ma_result ma_mutex_init(ma_mutex* pMutex)
10654 {
10655     if (pMutex == NULL) {
10656         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
10657         return MA_INVALID_ARGS;
10658     }
10659
10660 #ifdef MA_WIN32
10661     return ma_mutex_init__win32(pMutex);
10662 #endif
10663 #ifdef MA_POSIX
10664     return ma_mutex_init__posix(pMutex);
10665 #endif
10666 }
10667
10668 MA_API void ma_mutex_uninit(ma_mutex* pMutex)
10669 {
10670     if (pMutex == NULL) {
10671         return;
10672     }
10673
10674 #ifdef MA_WIN32
10675     ma_mutex_uninit__win32(pMutex);
10676 #endif
10677 #ifdef MA_POSIX
10678     ma_mutex_uninit__posix(pMutex);
10679 #endif
10680 }
10681
10682 MA_API void ma_mutex_lock(ma_mutex* pMutex)
10683 {
10684     if (pMutex == NULL) {
10685         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
10686         return;
10687     }
10688
10689 #ifdef MA_WIN32
10690     ma_mutex_lock__win32(pMutex);
10691 #endif
10692 #ifdef MA_POSIX
10693     ma_mutex_lock__posix(pMutex);
10694 #endif
10695 }
10696
10697 MA_API void ma_mutex_unlock(ma_mutex* pMutex)
10698 {
10699     if (pMutex == NULL) {
10700         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
10701         return;
10702 }
10703
10704 #ifdef MA_WIN32
10705     ma_mutex_unlock__win32(pMutex);
10706 #endif
10707 #ifdef MA_POSIX
10708     ma_mutex_unlock__posix(pMutex);
10709 #endif
10710 }
10711
10712
10713 MA_API ma_result ma_event_init(ma_event* pEvent)
10714 {
10715     if (pEvent == NULL) {
10716         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
10717         return MA_INVALID_ARGS;
10718     }
10719
10720 #ifdef MA_WIN32
10721     return ma_event_init__win32(pEvent);
10722 #endif
10723 #ifdef MA_POSIX
10724     return ma_event_init__posix(pEvent);
10725 #endif
10726 }
10727
10728 #if 0
10729 static ma_result ma_event_alloc_and_init(ma_event** ppEvent, ma_allocation_callbacks* pAllocationCallbacks)
10730 {
10731     ma_result result;
10732     ma_event* pEvent;
10733
10734     if (ppEvent == NULL) {
10735         return MA_INVALID_ARGS;
10736     }
10737
10738     *ppEvent = NULL;
10739
10740     pEvent = ma_malloc(sizeof(*pEvent), pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/);
10741     if (pEvent == NULL) {
10742         return MA_OUT_OF_MEMORY;
10743     }
10744
10745     result = ma_event_init(pEvent);
10746     if (result != MA_SUCCESS) {
10747         ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/);
10748         return result;
10749     }
10750
10751     *ppEvent = pEvent;
10752     return result;
10753 }
10754 #endif
10755
10756 MA_API void ma_event_uninit(ma_event* pEvent)
10757 {
10758     if (pEvent == NULL) {
10759         return;
10760     }
10761
10762 #ifdef MA_WIN32
10763     ma_event_uninit__win32(pEvent);
10764 #endif
10765 #ifdef MA_POSIX
10766     ma_event_uninit__posix(pEvent);
10767 #endif
10768 }
10769
10770 #if 0
10771 static void ma_event_uninit_and_free(ma_event* pEvent, ma_allocation_callbacks* pAllocationCallbacks)
10772 {
10773     if (pEvent == NULL) {
10774         return;
10775     }
10776
10777     ma_event_uninit(pEvent);
10778     ma_free(pEvent, pAllocationCallbacks/*, MA_ALLOCATION_TYPE_EVENT*/);
10779 }
10780 #endif
10781
10782 MA_API ma_result ma_event_wait(ma_event* pEvent)
10783 {
10784     if (pEvent == NULL) {
10785         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
10786         return MA_INVALID_ARGS;
10787     }
10788
10789 #ifdef MA_WIN32
10790     return ma_event_wait__win32(pEvent);
10791 #endif
10792 #ifdef MA_POSIX
10793     return ma_event_wait__posix(pEvent);
10794 #endif
10795 }
10796
10797 MA_API ma_result ma_event_signal(ma_event* pEvent)
10798 {
10799     if (pEvent == NULL) {
10800         MA_ASSERT(MA_FALSE);    /* Fire an assert to the caller is aware of this bug. */
10801         return MA_INVALID_ARGS;
10802     }
10803
10804 #ifdef MA_WIN32
10805     return ma_event_signal__win32(pEvent);
10806 #endif
10807 #ifdef MA_POSIX
10808     return ma_event_signal__posix(pEvent);
10809 #endif
10810 }
10811
10812
10813 MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore* pSemaphore)
10814 {
10815     if (pSemaphore == NULL) {
10816         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
10817         return MA_INVALID_ARGS;
10818     }
10819
10820 #ifdef MA_WIN32
10821     return ma_semaphore_init__win32(initialValue, pSemaphore);
10822 #endif
10823 #ifdef MA_POSIX
10824     return ma_semaphore_init__posix(initialValue, pSemaphore);
10825 #endif
10826 }
10827
10828 MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore)
10829 {
10830     if (pSemaphore == NULL) {
10831         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
10832         return;
10833     }
10834
10835 #ifdef MA_WIN32
10836     ma_semaphore_uninit__win32(pSemaphore);
10837 #endif
10838 #ifdef MA_POSIX
10839     ma_semaphore_uninit__posix(pSemaphore);
10840 #endif
10841 }
10842
10843 MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore)
10844 {
10845     if (pSemaphore == NULL) {
10846         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
10847         return MA_INVALID_ARGS;
10848     }
10849
10850 #ifdef MA_WIN32
10851     return ma_semaphore_wait__win32(pSemaphore);
10852 #endif
10853 #ifdef MA_POSIX
10854     return ma_semaphore_wait__posix(pSemaphore);
10855 #endif
10856 }
10857
10858 MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore)
10859 {
10860     if (pSemaphore == NULL) {
10861         MA_ASSERT(MA_FALSE);    /* Fire an assert so the caller is aware of this bug. */
10862         return MA_INVALID_ARGS;
10863     }
10864
10865 #ifdef MA_WIN32
10866     return ma_semaphore_release__win32(pSemaphore);
10867 #endif
10868 #ifdef MA_POSIX
10869     return ma_semaphore_release__posix(pSemaphore);
10870 #endif
10871 }
10872 #else
10873 /* 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. */
10874 #ifndef MA_NO_DEVICE_IO
10875 #error "MA_NO_THREADING cannot be used without MA_NO_DEVICE_IO";
10876 #endif
10877 #endif  /* MA_NO_THREADING */
10878
10879
10880
10881 /************************************************************************************************************************************************************
10882 *************************************************************************************************************************************************************
10883
10884 DEVICE I/O
10885 ==========
10886
10887 *************************************************************************************************************************************************************
10888 ************************************************************************************************************************************************************/
10889 #ifndef MA_NO_DEVICE_IO
10890 #ifdef MA_WIN32
10891     #include <objbase.h>
10892     #include <mmreg.h>
10893     #include <mmsystem.h>
10894 #endif
10895
10896 #if defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
10897     #include <mach/mach_time.h> /* For mach_absolute_time() */
10898 #endif
10899
10900 #ifdef MA_POSIX
10901     #include <sys/types.h>
10902     #include <unistd.h>
10903     #include <dlfcn.h>
10904 #endif
10905
10906 /*
10907 Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When
10908 using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing
10909 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
10910 disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am
10911 not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere.
10912 */
10913 /*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/
10914
10915 /* Disable run-time linking on certain backends. */
10916 #ifndef MA_NO_RUNTIME_LINKING
10917     #if defined(MA_EMSCRIPTEN)
10918         #define MA_NO_RUNTIME_LINKING
10919     #endif
10920 #endif
10921
10922
10923 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)
10924 {
10925     if (pDeviceInfo == NULL) {
10926         return;
10927     }
10928
10929     if (pDeviceInfo->nativeDataFormatCount < ma_countof(pDeviceInfo->nativeDataFormats)) {
10930         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
10931         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
10932         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
10933         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = flags;
10934         pDeviceInfo->nativeDataFormatCount += 1;
10935     }
10936 }
10937
10938
10939 MA_API const char* ma_get_backend_name(ma_backend backend)
10940 {
10941     switch (backend)
10942     {
10943         case ma_backend_wasapi:     return "WASAPI";
10944         case ma_backend_dsound:     return "DirectSound";
10945         case ma_backend_winmm:      return "WinMM";
10946         case ma_backend_coreaudio:  return "Core Audio";
10947         case ma_backend_sndio:      return "sndio";
10948         case ma_backend_audio4:     return "audio(4)";
10949         case ma_backend_oss:        return "OSS";
10950         case ma_backend_pulseaudio: return "PulseAudio";
10951         case ma_backend_alsa:       return "ALSA";
10952         case ma_backend_jack:       return "JACK";
10953         case ma_backend_aaudio:     return "AAudio";
10954         case ma_backend_opensl:     return "OpenSL|ES";
10955         case ma_backend_webaudio:   return "Web Audio";
10956         case ma_backend_custom:     return "Custom";
10957         case ma_backend_null:       return "Null";
10958         default:                    return "Unknown";
10959     }
10960 }
10961
10962 MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend)
10963 {
10964     /*
10965     This looks a little bit gross, but we want all backends to be included in the switch to avoid warnings on some compilers
10966     about some enums not being handled by the switch statement.
10967     */
10968     switch (backend)
10969     {
10970         case ma_backend_wasapi:
10971         #if defined(MA_HAS_WASAPI)
10972             return MA_TRUE;
10973         #else
10974             return MA_FALSE;
10975         #endif
10976         case ma_backend_dsound:
10977         #if defined(MA_HAS_DSOUND)
10978             return MA_TRUE;
10979         #else
10980             return MA_FALSE;
10981         #endif
10982         case ma_backend_winmm:
10983         #if defined(MA_HAS_WINMM)
10984             return MA_TRUE;
10985         #else
10986             return MA_FALSE;
10987         #endif
10988         case ma_backend_coreaudio:
10989         #if defined(MA_HAS_COREAUDIO)
10990             return MA_TRUE;
10991         #else
10992             return MA_FALSE;
10993         #endif
10994         case ma_backend_sndio:
10995         #if defined(MA_HAS_SNDIO)
10996             return MA_TRUE;
10997         #else
10998             return MA_FALSE;
10999         #endif
11000         case ma_backend_audio4:
11001         #if defined(MA_HAS_AUDIO4)
11002             return MA_TRUE;
11003         #else
11004             return MA_FALSE;
11005         #endif
11006         case ma_backend_oss:
11007         #if defined(MA_HAS_OSS)
11008             return MA_TRUE;
11009         #else
11010             return MA_FALSE;
11011         #endif
11012         case ma_backend_pulseaudio:
11013         #if defined(MA_HAS_PULSEAUDIO)
11014             return MA_TRUE;
11015         #else
11016             return MA_FALSE;
11017         #endif
11018         case ma_backend_alsa:
11019         #if defined(MA_HAS_ALSA)
11020             return MA_TRUE;
11021         #else
11022             return MA_FALSE;
11023         #endif
11024         case ma_backend_jack:
11025         #if defined(MA_HAS_JACK)
11026             return MA_TRUE;
11027         #else
11028             return MA_FALSE;
11029         #endif
11030         case ma_backend_aaudio:
11031         #if defined(MA_HAS_AAUDIO)
11032             return MA_TRUE;
11033         #else
11034             return MA_FALSE;
11035         #endif
11036         case ma_backend_opensl:
11037         #if defined(MA_HAS_OPENSL)
11038             return MA_TRUE;
11039         #else
11040             return MA_FALSE;
11041         #endif
11042         case ma_backend_webaudio:
11043         #if defined(MA_HAS_WEBAUDIO)
11044             return MA_TRUE;
11045         #else
11046             return MA_FALSE;
11047         #endif
11048         case ma_backend_custom:
11049         #if defined(MA_HAS_CUSTOM)
11050             return MA_TRUE;
11051         #else
11052             return MA_FALSE;
11053         #endif
11054         case ma_backend_null:
11055         #if defined(MA_HAS_NULL)
11056             return MA_TRUE;
11057         #else
11058             return MA_FALSE;
11059         #endif
11060
11061         default: return MA_FALSE;
11062     }
11063 }
11064
11065 MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount)
11066 {
11067     size_t backendCount;
11068     size_t iBackend;
11069     ma_result result = MA_SUCCESS;
11070
11071     if (pBackendCount == NULL) {
11072         return MA_INVALID_ARGS;
11073     }
11074
11075     backendCount = 0;
11076
11077     for (iBackend = 0; iBackend <= ma_backend_null; iBackend += 1) {
11078         ma_backend backend = (ma_backend)iBackend;
11079
11080         if (ma_is_backend_enabled(backend)) {
11081             /* The backend is enabled. Try adding it to the list. If there's no room, MA_NO_SPACE needs to be returned. */
11082             if (backendCount == backendCap) {
11083                 result = MA_NO_SPACE;
11084                 break;
11085             } else {
11086                 pBackends[backendCount] = backend;
11087                 backendCount += 1;
11088             }
11089         }
11090     }
11091
11092     if (pBackendCount != NULL) {
11093         *pBackendCount = backendCount;
11094     }
11095
11096     return result;
11097 }
11098
11099 MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend)
11100 {
11101     switch (backend)
11102     {
11103         case ma_backend_wasapi:     return MA_TRUE;
11104         case ma_backend_dsound:     return MA_FALSE;
11105         case ma_backend_winmm:      return MA_FALSE;
11106         case ma_backend_coreaudio:  return MA_FALSE;
11107         case ma_backend_sndio:      return MA_FALSE;
11108         case ma_backend_audio4:     return MA_FALSE;
11109         case ma_backend_oss:        return MA_FALSE;
11110         case ma_backend_pulseaudio: return MA_FALSE;
11111         case ma_backend_alsa:       return MA_FALSE;
11112         case ma_backend_jack:       return MA_FALSE;
11113         case ma_backend_aaudio:     return MA_FALSE;
11114         case ma_backend_opensl:     return MA_FALSE;
11115         case ma_backend_webaudio:   return MA_FALSE;
11116         case ma_backend_custom:     return MA_FALSE;    /* <-- Will depend on the implementation of the backend. */
11117         case ma_backend_null:       return MA_FALSE;
11118         default:                    return MA_FALSE;
11119     }
11120 }
11121
11122
11123
11124 #ifdef MA_WIN32
11125 /* WASAPI error codes. */
11126 #define MA_AUDCLNT_E_NOT_INITIALIZED              ((HRESULT)0x88890001)
11127 #define MA_AUDCLNT_E_ALREADY_INITIALIZED          ((HRESULT)0x88890002)
11128 #define MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE          ((HRESULT)0x88890003)
11129 #define MA_AUDCLNT_E_DEVICE_INVALIDATED           ((HRESULT)0x88890004)
11130 #define MA_AUDCLNT_E_NOT_STOPPED                  ((HRESULT)0x88890005)
11131 #define MA_AUDCLNT_E_BUFFER_TOO_LARGE             ((HRESULT)0x88890006)
11132 #define MA_AUDCLNT_E_OUT_OF_ORDER                 ((HRESULT)0x88890007)
11133 #define MA_AUDCLNT_E_UNSUPPORTED_FORMAT           ((HRESULT)0x88890008)
11134 #define MA_AUDCLNT_E_INVALID_SIZE                 ((HRESULT)0x88890009)
11135 #define MA_AUDCLNT_E_DEVICE_IN_USE                ((HRESULT)0x8889000A)
11136 #define MA_AUDCLNT_E_BUFFER_OPERATION_PENDING     ((HRESULT)0x8889000B)
11137 #define MA_AUDCLNT_E_THREAD_NOT_REGISTERED        ((HRESULT)0x8889000C)
11138 #define MA_AUDCLNT_E_NO_SINGLE_PROCESS            ((HRESULT)0x8889000D)
11139 #define MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED   ((HRESULT)0x8889000E)
11140 #define MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED       ((HRESULT)0x8889000F)
11141 #define MA_AUDCLNT_E_SERVICE_NOT_RUNNING          ((HRESULT)0x88890010)
11142 #define MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED     ((HRESULT)0x88890011)
11143 #define MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY          ((HRESULT)0x88890012)
11144 #define MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL ((HRESULT)0x88890013)
11145 #define MA_AUDCLNT_E_EVENTHANDLE_NOT_SET          ((HRESULT)0x88890014)
11146 #define MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE        ((HRESULT)0x88890015)
11147 #define MA_AUDCLNT_E_BUFFER_SIZE_ERROR            ((HRESULT)0x88890016)
11148 #define MA_AUDCLNT_E_CPUUSAGE_EXCEEDED            ((HRESULT)0x88890017)
11149 #define MA_AUDCLNT_E_BUFFER_ERROR                 ((HRESULT)0x88890018)
11150 #define MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED      ((HRESULT)0x88890019)
11151 #define MA_AUDCLNT_E_INVALID_DEVICE_PERIOD        ((HRESULT)0x88890020)
11152 #define MA_AUDCLNT_E_INVALID_STREAM_FLAG          ((HRESULT)0x88890021)
11153 #define MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE ((HRESULT)0x88890022)
11154 #define MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES     ((HRESULT)0x88890023)
11155 #define MA_AUDCLNT_E_OFFLOAD_MODE_ONLY            ((HRESULT)0x88890024)
11156 #define MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY         ((HRESULT)0x88890025)
11157 #define MA_AUDCLNT_E_RESOURCES_INVALIDATED        ((HRESULT)0x88890026)
11158 #define MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED         ((HRESULT)0x88890027)
11159 #define MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED    ((HRESULT)0x88890028)
11160 #define MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED         ((HRESULT)0x88890029)
11161 #define MA_AUDCLNT_E_HEADTRACKING_ENABLED         ((HRESULT)0x88890030)
11162 #define MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED     ((HRESULT)0x88890040)
11163 #define MA_AUDCLNT_S_BUFFER_EMPTY                 ((HRESULT)0x08890001)
11164 #define MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED    ((HRESULT)0x08890002)
11165 #define MA_AUDCLNT_S_POSITION_STALLED             ((HRESULT)0x08890003)
11166
11167 #define MA_DS_OK                                  ((HRESULT)0)
11168 #define MA_DS_NO_VIRTUALIZATION                   ((HRESULT)0x0878000A)
11169 #define MA_DSERR_ALLOCATED                        ((HRESULT)0x8878000A)
11170 #define MA_DSERR_CONTROLUNAVAIL                   ((HRESULT)0x8878001E)
11171 #define MA_DSERR_INVALIDPARAM                     ((HRESULT)0x80070057) /*E_INVALIDARG*/
11172 #define MA_DSERR_INVALIDCALL                      ((HRESULT)0x88780032)
11173 #define MA_DSERR_GENERIC                          ((HRESULT)0x80004005) /*E_FAIL*/
11174 #define MA_DSERR_PRIOLEVELNEEDED                  ((HRESULT)0x88780046)
11175 #define MA_DSERR_OUTOFMEMORY                      ((HRESULT)0x8007000E) /*E_OUTOFMEMORY*/
11176 #define MA_DSERR_BADFORMAT                        ((HRESULT)0x88780064)
11177 #define MA_DSERR_UNSUPPORTED                      ((HRESULT)0x80004001) /*E_NOTIMPL*/
11178 #define MA_DSERR_NODRIVER                         ((HRESULT)0x88780078)
11179 #define MA_DSERR_ALREADYINITIALIZED               ((HRESULT)0x88780082)
11180 #define MA_DSERR_NOAGGREGATION                    ((HRESULT)0x80040110) /*CLASS_E_NOAGGREGATION*/
11181 #define MA_DSERR_BUFFERLOST                       ((HRESULT)0x88780096)
11182 #define MA_DSERR_OTHERAPPHASPRIO                  ((HRESULT)0x887800A0)
11183 #define MA_DSERR_UNINITIALIZED                    ((HRESULT)0x887800AA)
11184 #define MA_DSERR_NOINTERFACE                      ((HRESULT)0x80004002) /*E_NOINTERFACE*/
11185 #define MA_DSERR_ACCESSDENIED                     ((HRESULT)0x80070005) /*E_ACCESSDENIED*/
11186 #define MA_DSERR_BUFFERTOOSMALL                   ((HRESULT)0x887800B4)
11187 #define MA_DSERR_DS8_REQUIRED                     ((HRESULT)0x887800BE)
11188 #define MA_DSERR_SENDLOOP                         ((HRESULT)0x887800C8)
11189 #define MA_DSERR_BADSENDBUFFERGUID                ((HRESULT)0x887800D2)
11190 #define MA_DSERR_OBJECTNOTFOUND                   ((HRESULT)0x88781161)
11191 #define MA_DSERR_FXUNAVAILABLE                    ((HRESULT)0x887800DC)
11192
11193 static ma_result ma_result_from_HRESULT(HRESULT hr)
11194 {
11195     switch (hr)
11196     {
11197         case NOERROR:                                   return MA_SUCCESS;
11198         /*case S_OK:                                      return MA_SUCCESS;*/
11199
11200         case E_POINTER:                                 return MA_INVALID_ARGS;
11201         case E_UNEXPECTED:                              return MA_ERROR;
11202         case E_NOTIMPL:                                 return MA_NOT_IMPLEMENTED;
11203         case E_OUTOFMEMORY:                             return MA_OUT_OF_MEMORY;
11204         case E_INVALIDARG:                              return MA_INVALID_ARGS;
11205         case E_NOINTERFACE:                             return MA_API_NOT_FOUND;
11206         case E_HANDLE:                                  return MA_INVALID_ARGS;
11207         case E_ABORT:                                   return MA_ERROR;
11208         case E_FAIL:                                    return MA_ERROR;
11209         case E_ACCESSDENIED:                            return MA_ACCESS_DENIED;
11210
11211         /* WASAPI */
11212         case MA_AUDCLNT_E_NOT_INITIALIZED:              return MA_DEVICE_NOT_INITIALIZED;
11213         case MA_AUDCLNT_E_ALREADY_INITIALIZED:          return MA_DEVICE_ALREADY_INITIALIZED;
11214         case MA_AUDCLNT_E_WRONG_ENDPOINT_TYPE:          return MA_INVALID_ARGS;
11215         case MA_AUDCLNT_E_DEVICE_INVALIDATED:           return MA_UNAVAILABLE;
11216         case MA_AUDCLNT_E_NOT_STOPPED:                  return MA_DEVICE_NOT_STOPPED;
11217         case MA_AUDCLNT_E_BUFFER_TOO_LARGE:             return MA_TOO_BIG;
11218         case MA_AUDCLNT_E_OUT_OF_ORDER:                 return MA_INVALID_OPERATION;
11219         case MA_AUDCLNT_E_UNSUPPORTED_FORMAT:           return MA_FORMAT_NOT_SUPPORTED;
11220         case MA_AUDCLNT_E_INVALID_SIZE:                 return MA_INVALID_ARGS;
11221         case MA_AUDCLNT_E_DEVICE_IN_USE:                return MA_BUSY;
11222         case MA_AUDCLNT_E_BUFFER_OPERATION_PENDING:     return MA_INVALID_OPERATION;
11223         case MA_AUDCLNT_E_THREAD_NOT_REGISTERED:        return MA_DOES_NOT_EXIST;
11224         case MA_AUDCLNT_E_NO_SINGLE_PROCESS:            return MA_INVALID_OPERATION;
11225         case MA_AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:   return MA_SHARE_MODE_NOT_SUPPORTED;
11226         case MA_AUDCLNT_E_ENDPOINT_CREATE_FAILED:       return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
11227         case MA_AUDCLNT_E_SERVICE_NOT_RUNNING:          return MA_NOT_CONNECTED;
11228         case MA_AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED:     return MA_INVALID_ARGS;
11229         case MA_AUDCLNT_E_EXCLUSIVE_MODE_ONLY:          return MA_SHARE_MODE_NOT_SUPPORTED;
11230         case MA_AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL: return MA_INVALID_ARGS;
11231         case MA_AUDCLNT_E_EVENTHANDLE_NOT_SET:          return MA_INVALID_ARGS;
11232         case MA_AUDCLNT_E_INCORRECT_BUFFER_SIZE:        return MA_INVALID_ARGS;
11233         case MA_AUDCLNT_E_BUFFER_SIZE_ERROR:            return MA_INVALID_ARGS;
11234         case MA_AUDCLNT_E_CPUUSAGE_EXCEEDED:            return MA_ERROR;
11235         case MA_AUDCLNT_E_BUFFER_ERROR:                 return MA_ERROR;
11236         case MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:      return MA_INVALID_ARGS;
11237         case MA_AUDCLNT_E_INVALID_DEVICE_PERIOD:        return MA_INVALID_ARGS;
11238         case MA_AUDCLNT_E_INVALID_STREAM_FLAG:          return MA_INVALID_ARGS;
11239         case MA_AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE: return MA_INVALID_OPERATION;
11240         case MA_AUDCLNT_E_OUT_OF_OFFLOAD_RESOURCES:     return MA_OUT_OF_MEMORY;
11241         case MA_AUDCLNT_E_OFFLOAD_MODE_ONLY:            return MA_INVALID_OPERATION;
11242         case MA_AUDCLNT_E_NONOFFLOAD_MODE_ONLY:         return MA_INVALID_OPERATION;
11243         case MA_AUDCLNT_E_RESOURCES_INVALIDATED:        return MA_INVALID_DATA;
11244         case MA_AUDCLNT_E_RAW_MODE_UNSUPPORTED:         return MA_INVALID_OPERATION;
11245         case MA_AUDCLNT_E_ENGINE_PERIODICITY_LOCKED:    return MA_INVALID_OPERATION;
11246         case MA_AUDCLNT_E_ENGINE_FORMAT_LOCKED:         return MA_INVALID_OPERATION;
11247         case MA_AUDCLNT_E_HEADTRACKING_ENABLED:         return MA_INVALID_OPERATION;
11248         case MA_AUDCLNT_E_HEADTRACKING_UNSUPPORTED:     return MA_INVALID_OPERATION;
11249         case MA_AUDCLNT_S_BUFFER_EMPTY:                 return MA_NO_SPACE;
11250         case MA_AUDCLNT_S_THREAD_ALREADY_REGISTERED:    return MA_ALREADY_EXISTS;
11251         case MA_AUDCLNT_S_POSITION_STALLED:             return MA_ERROR;
11252
11253         /* DirectSound */
11254         /*case MA_DS_OK:                                  return MA_SUCCESS;*/          /* S_OK */
11255         case MA_DS_NO_VIRTUALIZATION:                   return MA_SUCCESS;
11256         case MA_DSERR_ALLOCATED:                        return MA_ALREADY_IN_USE;
11257         case MA_DSERR_CONTROLUNAVAIL:                   return MA_INVALID_OPERATION;
11258         /*case MA_DSERR_INVALIDPARAM:                    return MA_INVALID_ARGS;*/      /* E_INVALIDARG */
11259         case MA_DSERR_INVALIDCALL:                      return MA_INVALID_OPERATION;
11260         /*case MA_DSERR_GENERIC:                          return MA_ERROR;*/            /* E_FAIL */
11261         case MA_DSERR_PRIOLEVELNEEDED:                  return MA_INVALID_OPERATION;
11262         /*case MA_DSERR_OUTOFMEMORY:                      return MA_OUT_OF_MEMORY;*/    /* E_OUTOFMEMORY */
11263         case MA_DSERR_BADFORMAT:                        return MA_FORMAT_NOT_SUPPORTED;
11264         /*case MA_DSERR_UNSUPPORTED:                      return MA_NOT_IMPLEMENTED;*/  /* E_NOTIMPL */
11265         case MA_DSERR_NODRIVER:                         return MA_FAILED_TO_INIT_BACKEND;
11266         case MA_DSERR_ALREADYINITIALIZED:               return MA_DEVICE_ALREADY_INITIALIZED;
11267         case MA_DSERR_NOAGGREGATION:                    return MA_ERROR;
11268         case MA_DSERR_BUFFERLOST:                       return MA_UNAVAILABLE;
11269         case MA_DSERR_OTHERAPPHASPRIO:                  return MA_ACCESS_DENIED;
11270         case MA_DSERR_UNINITIALIZED:                    return MA_DEVICE_NOT_INITIALIZED;
11271         /*case MA_DSERR_NOINTERFACE:                      return MA_API_NOT_FOUND;*/    /* E_NOINTERFACE */
11272         /*case MA_DSERR_ACCESSDENIED:                     return MA_ACCESS_DENIED;*/    /* E_ACCESSDENIED */
11273         case MA_DSERR_BUFFERTOOSMALL:                   return MA_NO_SPACE;
11274         case MA_DSERR_DS8_REQUIRED:                     return MA_INVALID_OPERATION;
11275         case MA_DSERR_SENDLOOP:                         return MA_DEADLOCK;
11276         case MA_DSERR_BADSENDBUFFERGUID:                return MA_INVALID_ARGS;
11277         case MA_DSERR_OBJECTNOTFOUND:                   return MA_NO_DEVICE;
11278         case MA_DSERR_FXUNAVAILABLE:                    return MA_UNAVAILABLE;
11279
11280         default:                                        return MA_ERROR;
11281     }
11282 }
11283
11284 typedef HRESULT (WINAPI * MA_PFN_CoInitializeEx)(LPVOID pvReserved, DWORD  dwCoInit);
11285 typedef void    (WINAPI * MA_PFN_CoUninitialize)(void);
11286 typedef HRESULT (WINAPI * MA_PFN_CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
11287 typedef void    (WINAPI * MA_PFN_CoTaskMemFree)(LPVOID pv);
11288 typedef HRESULT (WINAPI * MA_PFN_PropVariantClear)(PROPVARIANT *pvar);
11289 typedef int     (WINAPI * MA_PFN_StringFromGUID2)(const GUID* const rguid, LPOLESTR lpsz, int cchMax);
11290
11291 typedef HWND (WINAPI * MA_PFN_GetForegroundWindow)(void);
11292 typedef HWND (WINAPI * MA_PFN_GetDesktopWindow)(void);
11293
11294 /* Microsoft documents these APIs as returning LSTATUS, but the Win32 API shipping with some compilers do not define it. It's just a LONG. */
11295 typedef LONG (WINAPI * MA_PFN_RegOpenKeyExA)(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
11296 typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey);
11297 typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
11298 #endif
11299
11300
11301 #define MA_DEFAULT_PLAYBACK_DEVICE_NAME    "Default Playback Device"
11302 #define MA_DEFAULT_CAPTURE_DEVICE_NAME     "Default Capture Device"
11303
11304
11305 MA_API const char* ma_log_level_to_string(ma_uint32 logLevel)
11306 {
11307     switch (logLevel)
11308     {
11309         case MA_LOG_LEVEL_VERBOSE: return "";
11310         case MA_LOG_LEVEL_INFO:    return "INFO";
11311         case MA_LOG_LEVEL_WARNING: return "WARNING";
11312         case MA_LOG_LEVEL_ERROR:   return "ERROR";
11313         default:                   return "ERROR";
11314     }
11315 }
11316
11317 /* Posts a log message. */
11318 static void ma_post_log_message(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
11319 {
11320     if (pContext == NULL) {
11321         if (pDevice != NULL) {
11322             pContext = pDevice->pContext;
11323         }
11324     }
11325
11326     /* All logs must be output when debug output is enabled. */
11327 #if defined(MA_DEBUG_OUTPUT)
11328     printf("%s: %s\n", ma_log_level_to_string(logLevel), message);
11329 #endif
11330
11331     if (pContext == NULL) {
11332         return;
11333     }
11334
11335 #if defined(MA_LOG_LEVEL)
11336     if (logLevel <= MA_LOG_LEVEL) {
11337         ma_log_proc onLog;
11338
11339         onLog = pContext->logCallback;
11340         if (onLog) {
11341             onLog(pContext, pDevice, logLevel, message);
11342         }
11343     }
11344 #endif
11345 }
11346
11347 /*
11348 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
11349 logging function, I'm happy to keep this simple. In the VC6 build we can implement this in terms of _vsnprintf().
11350 */
11351 #if defined(_MSC_VER) && _MSC_VER < 1900
11352 int ma_vscprintf(const char* format, va_list args)
11353 {
11354 #if _MSC_VER > 1200
11355     return _vscprintf(format, args);
11356 #else
11357     int result;
11358     char* pTempBuffer = NULL;
11359     size_t tempBufferCap = 1024;
11360
11361     if (format == NULL) {
11362         errno = EINVAL;
11363         return -1;
11364     }
11365
11366     for (;;) {
11367         char* pNewTempBuffer = (char*)ma_realloc(pTempBuffer, tempBufferCap, NULL);    /* TODO: Add support for custom memory allocators? */
11368         if (pNewTempBuffer == NULL) {
11369             ma_free(pTempBuffer, NULL);
11370             errno = ENOMEM;
11371             return -1;  /* Out of memory. */
11372         }
11373
11374         pTempBuffer = pNewTempBuffer;
11375
11376         result = _vsnprintf(pTempBuffer, tempBufferCap, format, args);
11377         ma_free(pTempBuffer, NULL);
11378
11379         if (result != -1) {
11380             break;  /* Got it. */
11381         }
11382
11383         /* 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. */
11384         tempBufferCap *= 2;
11385     }
11386
11387     return result;
11388 #endif
11389 }
11390 #endif
11391
11392 /* Posts a formatted log message. */
11393 static void ma_post_log_messagev(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* pFormat, va_list args)
11394 {
11395 #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || ((!defined(_MSC_VER) || _MSC_VER >= 1900) && !defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
11396     {
11397         char pFormattedMessage[1024];
11398         vsnprintf(pFormattedMessage, sizeof(pFormattedMessage), pFormat, args);
11399         ma_post_log_message(pContext, pDevice, logLevel, pFormattedMessage);
11400     }
11401 #else
11402     {
11403         /*
11404         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
11405         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
11406         a fixed sized stack allocated buffer.
11407         */
11408     #if defined(_MSC_VER) && _MSC_VER >= 1200   /* 1200 = VC6 */
11409         int formattedLen;
11410         va_list args2;
11411
11412     #if _MSC_VER >= 1800
11413         va_copy(args2, args);
11414     #else
11415         args2 = args;
11416     #endif
11417         formattedLen = ma_vscprintf(pFormat, args2);
11418         va_end(args2);
11419
11420         if (formattedLen > 0) {
11421             char* pFormattedMessage = NULL;
11422             ma_allocation_callbacks* pAllocationCallbacks = NULL;
11423
11424             /* Make sure we have a context so we can allocate memory. */
11425             if (pContext == NULL) {
11426                 if (pDevice != NULL) {
11427                     pContext = pDevice->pContext;
11428                 }
11429             }
11430
11431             if (pContext != NULL) {
11432                 pAllocationCallbacks = &pContext->allocationCallbacks;
11433             }
11434
11435             pFormattedMessage = (char*)ma_malloc(formattedLen + 1, pAllocationCallbacks);
11436             if (pFormattedMessage != NULL) {
11437                 /* We'll get errors on newer versions of Visual Studio if we try to use vsprintf().  */
11438             #if _MSC_VER >= 1400    /* 1400 = Visual Studio 2005 */
11439                 vsprintf_s(pFormattedMessage, formattedLen + 1, pFormat, args);
11440             #else
11441                 vsprintf(pFormattedMessage, pFormat, args);
11442             #endif
11443
11444                 ma_post_log_message(pContext, pDevice, logLevel, pFormattedMessage);
11445                 ma_free(pFormattedMessage, pAllocationCallbacks);
11446             }
11447         }
11448     #else
11449         /* Can't do anything because we don't have a safe way of to emulate vsnprintf() without a manual solution. */
11450         (void)pContext;
11451         (void)pDevice;
11452         (void)logLevel;
11453         (void)pFormat;
11454         (void)args;
11455     #endif
11456     }
11457 #endif
11458 }
11459
11460 MA_API void ma_post_log_messagef(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* pFormat, ...)
11461 {
11462     va_list args;
11463     va_start(args, pFormat);
11464     {
11465         ma_post_log_messagev(pContext, pDevice, logLevel, pFormat, args);
11466     }
11467     va_end(args);
11468 }
11469
11470 /* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */
11471 static ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
11472 {
11473     ma_post_log_message(pContext, pDevice, logLevel, message);
11474     return resultCode;
11475 }
11476
11477 static ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode)
11478 {
11479     return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode);
11480 }
11481
11482
11483 /*******************************************************************************
11484
11485 Timing
11486
11487 *******************************************************************************/
11488 #ifdef MA_WIN32
11489     static LARGE_INTEGER g_ma_TimerFrequency;   /* <-- Initialized to zero since it's static. */
11490     static void ma_timer_init(ma_timer* pTimer)
11491     {
11492         LARGE_INTEGER counter;
11493
11494         if (g_ma_TimerFrequency.QuadPart == 0) {
11495             QueryPerformanceFrequency(&g_ma_TimerFrequency);
11496         }
11497
11498         QueryPerformanceCounter(&counter);
11499         pTimer->counter = counter.QuadPart;
11500     }
11501
11502     static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
11503     {
11504         LARGE_INTEGER counter;
11505         if (!QueryPerformanceCounter(&counter)) {
11506             return 0;
11507         }
11508
11509         return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart;
11510     }
11511 #elif defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200)
11512     static ma_uint64 g_ma_TimerFrequency = 0;
11513     static void ma_timer_init(ma_timer* pTimer)
11514     {
11515         mach_timebase_info_data_t baseTime;
11516         mach_timebase_info(&baseTime);
11517         g_ma_TimerFrequency = (baseTime.denom * 1e9) / baseTime.numer;
11518
11519         pTimer->counter = mach_absolute_time();
11520     }
11521
11522     static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
11523     {
11524         ma_uint64 newTimeCounter = mach_absolute_time();
11525         ma_uint64 oldTimeCounter = pTimer->counter;
11526
11527         return (newTimeCounter - oldTimeCounter) / g_ma_TimerFrequency;
11528     }
11529 #elif defined(MA_EMSCRIPTEN)
11530     static MA_INLINE void ma_timer_init(ma_timer* pTimer)
11531     {
11532         pTimer->counterD = emscripten_get_now();
11533     }
11534
11535     static MA_INLINE double ma_timer_get_time_in_seconds(ma_timer* pTimer)
11536     {
11537         return (emscripten_get_now() - pTimer->counterD) / 1000;    /* Emscripten is in milliseconds. */
11538     }
11539 #else
11540     #if _POSIX_C_SOURCE >= 199309L
11541         #if defined(CLOCK_MONOTONIC)
11542             #define MA_CLOCK_ID CLOCK_MONOTONIC
11543         #else
11544             #define MA_CLOCK_ID CLOCK_REALTIME
11545         #endif
11546
11547         static void ma_timer_init(ma_timer* pTimer)
11548         {
11549             struct timespec newTime;
11550             clock_gettime(MA_CLOCK_ID, &newTime);
11551
11552             pTimer->counter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
11553         }
11554
11555         static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
11556         {
11557             ma_uint64 newTimeCounter;
11558             ma_uint64 oldTimeCounter;
11559
11560             struct timespec newTime;
11561             clock_gettime(MA_CLOCK_ID, &newTime);
11562
11563             newTimeCounter = (newTime.tv_sec * 1000000000) + newTime.tv_nsec;
11564             oldTimeCounter = pTimer->counter;
11565
11566             return (newTimeCounter - oldTimeCounter) / 1000000000.0;
11567         }
11568     #else
11569         static void ma_timer_init(ma_timer* pTimer)
11570         {
11571             struct timeval newTime;
11572             gettimeofday(&newTime, NULL);
11573
11574             pTimer->counter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
11575         }
11576
11577         static double ma_timer_get_time_in_seconds(ma_timer* pTimer)
11578         {
11579             ma_uint64 newTimeCounter;
11580             ma_uint64 oldTimeCounter;
11581
11582             struct timeval newTime;
11583             gettimeofday(&newTime, NULL);
11584
11585             newTimeCounter = (newTime.tv_sec * 1000000) + newTime.tv_usec;
11586             oldTimeCounter = pTimer->counter;
11587
11588             return (newTimeCounter - oldTimeCounter) / 1000000.0;
11589         }
11590     #endif
11591 #endif
11592
11593
11594 /*******************************************************************************
11595
11596 Dynamic Linking
11597
11598 *******************************************************************************/
11599 MA_API ma_handle ma_dlopen(ma_context* pContext, const char* filename)
11600 {
11601     ma_handle handle;
11602
11603 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE
11604     if (pContext != NULL) {
11605         char message[256];
11606         ma_strappend(message, sizeof(message), "Loading library: ", filename);
11607         ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
11608     }
11609 #endif
11610
11611 #ifdef _WIN32
11612 #ifdef MA_WIN32_DESKTOP
11613     handle = (ma_handle)LoadLibraryA(filename);
11614 #else
11615     /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */
11616     WCHAR filenameW[4096];
11617     if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) {
11618         handle = NULL;
11619     } else {
11620         handle = (ma_handle)LoadPackagedLibrary(filenameW, 0);
11621     }
11622 #endif
11623 #else
11624     handle = (ma_handle)dlopen(filename, RTLD_NOW);
11625 #endif
11626
11627     /*
11628     I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority
11629     backend is a deliberate design choice. Instead I'm logging it as an informational message.
11630     */
11631 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_INFO
11632     if (handle == NULL) {
11633         char message[256];
11634         ma_strappend(message, sizeof(message), "Failed to load library: ", filename);
11635         ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, message);
11636     }
11637 #endif
11638
11639     (void)pContext; /* It's possible for pContext to be unused. */
11640     return handle;
11641 }
11642
11643 MA_API void ma_dlclose(ma_context* pContext, ma_handle handle)
11644 {
11645 #ifdef _WIN32
11646     FreeLibrary((HMODULE)handle);
11647 #else
11648     dlclose((void*)handle);
11649 #endif
11650
11651     (void)pContext;
11652 }
11653
11654 MA_API ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol)
11655 {
11656     ma_proc proc;
11657
11658 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE
11659     if (pContext != NULL) {
11660         char message[256];
11661         ma_strappend(message, sizeof(message), "Loading symbol: ", symbol);
11662         ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message);
11663     }
11664 #endif
11665
11666 #ifdef _WIN32
11667     proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol);
11668 #else
11669 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
11670     #pragma GCC diagnostic push
11671     #pragma GCC diagnostic ignored "-Wpedantic"
11672 #endif
11673     proc = (ma_proc)dlsym((void*)handle, symbol);
11674 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
11675     #pragma GCC diagnostic pop
11676 #endif
11677 #endif
11678
11679 #if MA_LOG_LEVEL >= MA_LOG_LEVEL_WARNING
11680     if (handle == NULL) {
11681         char message[256];
11682         ma_strappend(message, sizeof(message), "Failed to load symbol: ", symbol);
11683         ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_WARNING, message);
11684     }
11685 #endif
11686
11687     (void)pContext; /* It's possible for pContext to be unused. */
11688     return proc;
11689 }
11690
11691
11692 #if 0
11693 static ma_uint32 ma_get_closest_standard_sample_rate(ma_uint32 sampleRateIn)
11694 {
11695     ma_uint32 closestRate = 0;
11696     ma_uint32 closestDiff = 0xFFFFFFFF;
11697     size_t iStandardRate;
11698
11699     for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
11700         ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
11701         ma_uint32 diff;
11702
11703         if (sampleRateIn > standardRate) {
11704             diff = sampleRateIn - standardRate;
11705         } else {
11706             diff = standardRate - sampleRateIn;
11707         }
11708
11709         if (diff == 0) {
11710             return standardRate;    /* The input sample rate is a standard rate. */
11711         }
11712
11713         if (closestDiff > diff) {
11714             closestDiff = diff;
11715             closestRate = standardRate;
11716         }
11717     }
11718
11719     return closestRate;
11720 }
11721 #endif
11722
11723
11724 static void ma_device__on_data(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
11725 {
11726     float masterVolumeFactor;
11727
11728     ma_device_get_master_volume(pDevice, &masterVolumeFactor);  /* Use ma_device_get_master_volume() to ensure the volume is loaded atomically. */
11729
11730     if (pDevice->onData) {
11731         if (!pDevice->noPreZeroedOutputBuffer && pFramesOut != NULL) {
11732             ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels);
11733         }
11734
11735         /* 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. */
11736         if (pFramesIn != NULL && masterVolumeFactor < 1) {
11737             ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
11738             ma_uint32 bpfCapture  = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
11739             ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
11740             ma_uint32 totalFramesProcessed = 0;
11741             while (totalFramesProcessed < frameCount) {
11742                 ma_uint32 framesToProcessThisIteration = frameCount - totalFramesProcessed;
11743                 if (framesToProcessThisIteration > sizeof(tempFramesIn)/bpfCapture) {
11744                     framesToProcessThisIteration = sizeof(tempFramesIn)/bpfCapture;
11745                 }
11746
11747                 ma_copy_and_apply_volume_factor_pcm_frames(tempFramesIn, ma_offset_ptr(pFramesIn, totalFramesProcessed*bpfCapture), framesToProcessThisIteration, pDevice->capture.format, pDevice->capture.channels, masterVolumeFactor);
11748
11749                 pDevice->onData(pDevice, ma_offset_ptr(pFramesOut, totalFramesProcessed*bpfPlayback), tempFramesIn, framesToProcessThisIteration);
11750
11751                 totalFramesProcessed += framesToProcessThisIteration;
11752             }
11753         } else {
11754             pDevice->onData(pDevice, pFramesOut, pFramesIn, frameCount);
11755         }
11756
11757         /* Volume control and clipping for playback devices. */
11758         if (pFramesOut != NULL) {
11759             if (masterVolumeFactor < 1) {
11760                 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. */
11761                     ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor);
11762                 }
11763             }
11764
11765             if (!pDevice->noClip && pDevice->playback.format == ma_format_f32) {
11766                 ma_clip_pcm_frames_f32((float*)pFramesOut, frameCount, pDevice->playback.channels);
11767             }
11768         }
11769     }
11770 }
11771
11772
11773
11774 /* A helper function for reading sample data from the client. */
11775 static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 frameCount, void* pFramesOut)
11776 {
11777     MA_ASSERT(pDevice != NULL);
11778     MA_ASSERT(frameCount > 0);
11779     MA_ASSERT(pFramesOut != NULL);
11780
11781     if (pDevice->playback.converter.isPassthrough) {
11782         ma_device__on_data(pDevice, pFramesOut, NULL, frameCount);
11783     } else {
11784         ma_result result;
11785         ma_uint64 totalFramesReadOut;
11786         ma_uint64 totalFramesReadIn;
11787         void* pRunningFramesOut;
11788
11789         totalFramesReadOut = 0;
11790         totalFramesReadIn  = 0;
11791         pRunningFramesOut  = pFramesOut;
11792
11793         while (totalFramesReadOut < frameCount) {
11794             ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In client format. */
11795             ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
11796             ma_uint64 framesToReadThisIterationIn;
11797             ma_uint64 framesReadThisIterationIn;
11798             ma_uint64 framesToReadThisIterationOut;
11799             ma_uint64 framesReadThisIterationOut;
11800             ma_uint64 requiredInputFrameCount;
11801
11802             framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
11803             framesToReadThisIterationIn = framesToReadThisIterationOut;
11804             if (framesToReadThisIterationIn > intermediaryBufferCap) {
11805                 framesToReadThisIterationIn = intermediaryBufferCap;
11806             }
11807
11808             requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, framesToReadThisIterationOut);
11809             if (framesToReadThisIterationIn > requiredInputFrameCount) {
11810                 framesToReadThisIterationIn = requiredInputFrameCount;
11811             }
11812
11813             if (framesToReadThisIterationIn > 0) {
11814                 ma_device__on_data(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn);
11815                 totalFramesReadIn += framesToReadThisIterationIn;
11816             }
11817
11818             /*
11819             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
11820             input frames, we still want to try processing frames because there may some output frames generated from cached input data.
11821             */
11822             framesReadThisIterationIn  = framesToReadThisIterationIn;
11823             framesReadThisIterationOut = framesToReadThisIterationOut;
11824             result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut);
11825             if (result != MA_SUCCESS) {
11826                 break;
11827             }
11828
11829             totalFramesReadOut += framesReadThisIterationOut;
11830             pRunningFramesOut   = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
11831
11832             if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
11833                 break;  /* We're done. */
11834             }
11835         }
11836     }
11837 }
11838
11839 /* A helper for sending sample data to the client. */
11840 static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat)
11841 {
11842     MA_ASSERT(pDevice != NULL);
11843     MA_ASSERT(frameCountInDeviceFormat > 0);
11844     MA_ASSERT(pFramesInDeviceFormat != NULL);
11845
11846     if (pDevice->capture.converter.isPassthrough) {
11847         ma_device__on_data(pDevice, NULL, pFramesInDeviceFormat, frameCountInDeviceFormat);
11848     } else {
11849         ma_result result;
11850         ma_uint8 pFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
11851         ma_uint64 framesInClientFormatCap = sizeof(pFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
11852         ma_uint64 totalDeviceFramesProcessed = 0;
11853         ma_uint64 totalClientFramesProcessed = 0;
11854         const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
11855
11856         /* We just keep going until we've exhaused all of our input frames and cannot generate any more output frames. */
11857         for (;;) {
11858             ma_uint64 deviceFramesProcessedThisIteration;
11859             ma_uint64 clientFramesProcessedThisIteration;
11860
11861             deviceFramesProcessedThisIteration = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
11862             clientFramesProcessedThisIteration = framesInClientFormatCap;
11863
11864             result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &deviceFramesProcessedThisIteration, pFramesInClientFormat, &clientFramesProcessedThisIteration);
11865             if (result != MA_SUCCESS) {
11866                 break;
11867             }
11868
11869             if (clientFramesProcessedThisIteration > 0) {
11870                 ma_device__on_data(pDevice, NULL, pFramesInClientFormat, (ma_uint32)clientFramesProcessedThisIteration);    /* Safe cast. */
11871             }
11872
11873             pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, deviceFramesProcessedThisIteration * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
11874             totalDeviceFramesProcessed  += deviceFramesProcessedThisIteration;
11875             totalClientFramesProcessed  += clientFramesProcessedThisIteration;
11876
11877             if (deviceFramesProcessedThisIteration == 0 && clientFramesProcessedThisIteration == 0) {
11878                 break;  /* We're done. */
11879             }
11880         }
11881     }
11882 }
11883
11884 static ma_result ma_device__handle_duplex_callback_capture(ma_device* pDevice, ma_uint32 frameCountInDeviceFormat, const void* pFramesInDeviceFormat, ma_pcm_rb* pRB)
11885 {
11886     ma_result result;
11887     ma_uint32 totalDeviceFramesProcessed = 0;
11888     const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat;
11889
11890     MA_ASSERT(pDevice != NULL);
11891     MA_ASSERT(frameCountInDeviceFormat > 0);
11892     MA_ASSERT(pFramesInDeviceFormat != NULL);
11893     MA_ASSERT(pRB != NULL);
11894
11895     /* Write to the ring buffer. The ring buffer is in the client format which means we need to convert. */
11896     for (;;) {
11897         ma_uint32 framesToProcessInDeviceFormat = (frameCountInDeviceFormat - totalDeviceFramesProcessed);
11898         ma_uint32 framesToProcessInClientFormat = MA_DATA_CONVERTER_STACK_BUFFER_SIZE / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
11899         ma_uint64 framesProcessedInDeviceFormat;
11900         ma_uint64 framesProcessedInClientFormat;
11901         void* pFramesInClientFormat;
11902
11903         result = ma_pcm_rb_acquire_write(pRB, &framesToProcessInClientFormat, &pFramesInClientFormat);
11904         if (result != MA_SUCCESS) {
11905             ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to acquire capture PCM frames from ring buffer.", result);
11906             break;
11907         }
11908
11909         if (framesToProcessInClientFormat == 0) {
11910             if (ma_pcm_rb_pointer_distance(pRB) == (ma_int32)ma_pcm_rb_get_subbuffer_size(pRB)) {
11911                 break;  /* Overrun. Not enough room in the ring buffer for input frame. Excess frames are dropped. */
11912             }
11913         }
11914
11915         /* Convert. */
11916         framesProcessedInDeviceFormat = framesToProcessInDeviceFormat;
11917         framesProcessedInClientFormat = framesToProcessInClientFormat;
11918         result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningFramesInDeviceFormat, &framesProcessedInDeviceFormat, pFramesInClientFormat, &framesProcessedInClientFormat);
11919         if (result != MA_SUCCESS) {
11920             break;
11921         }
11922
11923         result = ma_pcm_rb_commit_write(pRB, (ma_uint32)framesProcessedInClientFormat, pFramesInClientFormat);  /* Safe cast. */
11924         if (result != MA_SUCCESS) {
11925             ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "Failed to commit capture PCM frames to ring buffer.", result);
11926             break;
11927         }
11928
11929         pRunningFramesInDeviceFormat = ma_offset_ptr(pRunningFramesInDeviceFormat, framesProcessedInDeviceFormat * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
11930         totalDeviceFramesProcessed += (ma_uint32)framesProcessedInDeviceFormat; /* Safe cast. */
11931
11932         /* We're done when we're unable to process any client nor device frames. */
11933         if (framesProcessedInClientFormat == 0 && framesProcessedInDeviceFormat == 0) {
11934             break;  /* Done. */
11935         }
11936     }
11937
11938     return MA_SUCCESS;
11939 }
11940
11941 static ma_result ma_device__handle_duplex_callback_playback(ma_device* pDevice, ma_uint32 frameCount, void* pFramesInInternalFormat, ma_pcm_rb* pRB)
11942 {
11943     ma_result result;
11944     ma_uint8 playbackFramesInExternalFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
11945     ma_uint8 silentInputFrames[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
11946     ma_uint32 totalFramesToReadFromClient;
11947     ma_uint32 totalFramesReadFromClient;
11948     ma_uint32 totalFramesReadOut = 0;
11949
11950     MA_ASSERT(pDevice != NULL);
11951     MA_ASSERT(frameCount > 0);
11952     MA_ASSERT(pFramesInInternalFormat != NULL);
11953     MA_ASSERT(pRB != NULL);
11954
11955     /*
11956     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
11957     the whole frameCount frames we just use silence instead for the input data.
11958     */
11959     MA_ZERO_MEMORY(silentInputFrames, sizeof(silentInputFrames));
11960
11961     /* We need to calculate how many output frames are required to be read from the client to completely fill frameCount internal frames. */
11962     totalFramesToReadFromClient = (ma_uint32)ma_data_converter_get_required_input_frame_count(&pDevice->playback.converter, frameCount);
11963     totalFramesReadFromClient = 0;
11964     while (totalFramesReadFromClient < totalFramesToReadFromClient && ma_device_is_started(pDevice)) {
11965         ma_uint32 framesRemainingFromClient;
11966         ma_uint32 framesToProcessFromClient;
11967         ma_uint32 inputFrameCount;
11968         void* pInputFrames;
11969
11970         framesRemainingFromClient = (totalFramesToReadFromClient - totalFramesReadFromClient);
11971         framesToProcessFromClient = sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
11972         if (framesToProcessFromClient > framesRemainingFromClient) {
11973             framesToProcessFromClient = framesRemainingFromClient;
11974         }
11975
11976         /* We need to grab captured samples before firing the callback. If there's not enough input samples we just pass silence. */
11977         inputFrameCount = framesToProcessFromClient;
11978         result = ma_pcm_rb_acquire_read(pRB, &inputFrameCount, &pInputFrames);
11979         if (result == MA_SUCCESS) {
11980             if (inputFrameCount > 0) {
11981                 /* Use actual input frames. */
11982                 ma_device__on_data(pDevice, playbackFramesInExternalFormat, pInputFrames, inputFrameCount);
11983             } else {
11984                 if (ma_pcm_rb_pointer_distance(pRB) == 0) {
11985                     break;  /* Underrun. */
11986                 }
11987             }
11988
11989             /* We're done with the captured samples. */
11990             result = ma_pcm_rb_commit_read(pRB, inputFrameCount, pInputFrames);
11991             if (result != MA_SUCCESS) {
11992                 break; /* Don't know what to do here... Just abandon ship. */
11993             }
11994         } else {
11995             /* Use silent input frames. */
11996             inputFrameCount = ma_min(
11997                 sizeof(playbackFramesInExternalFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels),
11998                 sizeof(silentInputFrames)              / ma_get_bytes_per_frame(pDevice->capture.format,  pDevice->capture.channels)
11999             );
12000
12001             ma_device__on_data(pDevice, playbackFramesInExternalFormat, silentInputFrames, inputFrameCount);
12002         }
12003
12004         /* We have samples in external format so now we need to convert to internal format and output to the device. */
12005         {
12006             ma_uint64 framesConvertedIn  = inputFrameCount;
12007             ma_uint64 framesConvertedOut = (frameCount - totalFramesReadOut);
12008             ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackFramesInExternalFormat, &framesConvertedIn, pFramesInInternalFormat, &framesConvertedOut);
12009
12010             totalFramesReadFromClient += (ma_uint32)framesConvertedIn;  /* Safe cast. */
12011             totalFramesReadOut        += (ma_uint32)framesConvertedOut; /* Safe cast. */
12012             pFramesInInternalFormat    = ma_offset_ptr(pFramesInInternalFormat, framesConvertedOut * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
12013         }
12014     }
12015
12016     return MA_SUCCESS;
12017 }
12018
12019 /* A helper for changing the state of the device. */
12020 static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_uint32 newState)
12021 {
12022     c89atomic_exchange_32(&pDevice->state, newState);
12023 }
12024
12025
12026 #ifdef MA_WIN32
12027     GUID MA_GUID_KSDATAFORMAT_SUBTYPE_PCM        = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
12028     GUID MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
12029     /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_ALAW       = {0x00000006, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
12030     /*GUID MA_GUID_KSDATAFORMAT_SUBTYPE_MULAW      = {0x00000007, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};*/
12031 #endif
12032
12033
12034
12035 MA_API ma_uint32 ma_get_format_priority_index(ma_format format) /* Lower = better. */
12036 {
12037     ma_uint32 i;
12038     for (i = 0; i < ma_countof(g_maFormatPriorities); ++i) {
12039         if (g_maFormatPriorities[i] == format) {
12040             return i;
12041         }
12042     }
12043
12044     /* Getting here means the format could not be found or is equal to ma_format_unknown. */
12045     return (ma_uint32)-1;
12046 }
12047
12048 static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType);
12049
12050
12051 static ma_bool32 ma_device_descriptor_is_valid(const ma_device_descriptor* pDeviceDescriptor)
12052 {
12053     if (pDeviceDescriptor == NULL) {
12054         return MA_FALSE;
12055     }
12056
12057     if (pDeviceDescriptor->format == ma_format_unknown) {
12058         return MA_FALSE;
12059     }
12060
12061     if (pDeviceDescriptor->channels < MA_MIN_CHANNELS || pDeviceDescriptor->channels > MA_MAX_CHANNELS) {
12062         return MA_FALSE;
12063     }
12064
12065     if (pDeviceDescriptor->sampleRate == 0) {
12066         return MA_FALSE;
12067     }
12068
12069     return MA_TRUE;
12070 }
12071
12072
12073 static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice)
12074 {
12075     ma_result result = MA_SUCCESS;
12076     ma_bool32 exitLoop = MA_FALSE;
12077     ma_uint8  capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
12078     ma_uint8  playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
12079     ma_uint32 capturedDeviceDataCapInFrames = 0;
12080     ma_uint32 playbackDeviceDataCapInFrames = 0;
12081
12082     MA_ASSERT(pDevice != NULL);
12083
12084     /* Just some quick validation on the device type and the available callbacks. */
12085     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
12086         if (pDevice->pContext->callbacks.onDeviceRead == NULL) {
12087             return MA_NOT_IMPLEMENTED;
12088         }
12089
12090         capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat,  pDevice->capture.internalChannels);
12091     }
12092
12093     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
12094         if (pDevice->pContext->callbacks.onDeviceWrite == NULL) {
12095             return MA_NOT_IMPLEMENTED;
12096         }
12097
12098         playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
12099     }
12100
12101     /* NOTE: The device was started outside of this function, in the worker thread. */
12102
12103     while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
12104         switch (pDevice->type) {
12105             case ma_device_type_duplex:
12106             {
12107                 /* The process is: onDeviceRead() -> convert -> callback -> convert -> onDeviceWrite() */
12108                 ma_uint32 totalCapturedDeviceFramesProcessed = 0;
12109                 ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
12110
12111                 while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
12112                     ma_uint32 capturedDeviceFramesRemaining;
12113                     ma_uint32 capturedDeviceFramesProcessed;
12114                     ma_uint32 capturedDeviceFramesToProcess;
12115                     ma_uint32 capturedDeviceFramesToTryProcessing = capturedDevicePeriodSizeInFrames - totalCapturedDeviceFramesProcessed;
12116                     if (capturedDeviceFramesToTryProcessing > capturedDeviceDataCapInFrames) {
12117                         capturedDeviceFramesToTryProcessing = capturedDeviceDataCapInFrames;
12118                     }
12119
12120                     result = pDevice->pContext->callbacks.onDeviceRead(pDevice, capturedDeviceData, capturedDeviceFramesToTryProcessing, &capturedDeviceFramesToProcess);
12121                     if (result != MA_SUCCESS) {
12122                         exitLoop = MA_TRUE;
12123                         break;
12124                     }
12125
12126                     capturedDeviceFramesRemaining = capturedDeviceFramesToProcess;
12127                     capturedDeviceFramesProcessed = 0;
12128
12129                     /* At this point we have our captured data in device format and we now need to convert it to client format. */
12130                     for (;;) {
12131                         ma_uint8  capturedClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
12132                         ma_uint8  playbackClientData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
12133                         ma_uint32 capturedClientDataCapInFrames = sizeof(capturedClientData) / ma_get_bytes_per_frame(pDevice->capture.format,  pDevice->capture.channels);
12134                         ma_uint32 playbackClientDataCapInFrames = sizeof(playbackClientData) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
12135                         ma_uint64 capturedClientFramesToProcessThisIteration = ma_min(capturedClientDataCapInFrames, playbackClientDataCapInFrames);
12136                         ma_uint64 capturedDeviceFramesToProcessThisIteration = capturedDeviceFramesRemaining;
12137                         ma_uint8* pRunningCapturedDeviceFrames = ma_offset_ptr(capturedDeviceData, capturedDeviceFramesProcessed * ma_get_bytes_per_frame(pDevice->capture.internalFormat,  pDevice->capture.internalChannels));
12138
12139                         /* Convert capture data from device format to client format. */
12140                         result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningCapturedDeviceFrames, &capturedDeviceFramesToProcessThisIteration, capturedClientData, &capturedClientFramesToProcessThisIteration);
12141                         if (result != MA_SUCCESS) {
12142                             break;
12143                         }
12144
12145                         /*
12146                         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
12147                         which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE.
12148                         */
12149                         if (capturedClientFramesToProcessThisIteration == 0) {
12150                             break;
12151                         }
12152
12153                         ma_device__on_data(pDevice, playbackClientData, capturedClientData, (ma_uint32)capturedClientFramesToProcessThisIteration);    /* Safe cast .*/
12154
12155                         capturedDeviceFramesProcessed += (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
12156                         capturedDeviceFramesRemaining -= (ma_uint32)capturedDeviceFramesToProcessThisIteration; /* Safe cast. */
12157
12158                         /* At this point the playbackClientData buffer should be holding data that needs to be written to the device. */
12159                         for (;;) {
12160                             ma_uint64 convertedClientFrameCount = capturedClientFramesToProcessThisIteration;
12161                             ma_uint64 convertedDeviceFrameCount = playbackDeviceDataCapInFrames;
12162                             result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, playbackClientData, &convertedClientFrameCount, playbackDeviceData, &convertedDeviceFrameCount);
12163                             if (result != MA_SUCCESS) {
12164                                 break;
12165                             }
12166
12167                             result = pDevice->pContext->callbacks.onDeviceWrite(pDevice, playbackDeviceData, (ma_uint32)convertedDeviceFrameCount, NULL);   /* Safe cast. */
12168                             if (result != MA_SUCCESS) {
12169                                 exitLoop = MA_TRUE;
12170                                 break;
12171                             }
12172
12173                             capturedClientFramesToProcessThisIteration -= (ma_uint32)convertedClientFrameCount;  /* Safe cast. */
12174                             if (capturedClientFramesToProcessThisIteration == 0) {
12175                                 break;
12176                             }
12177                         }
12178
12179                         /* In case an error happened from ma_device_write__null()... */
12180                         if (result != MA_SUCCESS) {
12181                             exitLoop = MA_TRUE;
12182                             break;
12183                         }
12184                     }
12185
12186                     totalCapturedDeviceFramesProcessed += capturedDeviceFramesProcessed;
12187                 }
12188             } break;
12189
12190             case ma_device_type_capture:
12191             case ma_device_type_loopback:
12192             {
12193                 ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
12194                 ma_uint32 framesReadThisPeriod = 0;
12195                 while (framesReadThisPeriod < periodSizeInFrames) {
12196                     ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
12197                     ma_uint32 framesProcessed;
12198                     ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
12199                     if (framesToReadThisIteration > capturedDeviceDataCapInFrames) {
12200                         framesToReadThisIteration = capturedDeviceDataCapInFrames;
12201                     }
12202
12203                     result = pDevice->pContext->callbacks.onDeviceRead(pDevice, capturedDeviceData, framesToReadThisIteration, &framesProcessed);
12204                     if (result != MA_SUCCESS) {
12205                         exitLoop = MA_TRUE;
12206                         break;
12207                     }
12208
12209                     ma_device__send_frames_to_client(pDevice, framesProcessed, capturedDeviceData);
12210
12211                     framesReadThisPeriod += framesProcessed;
12212                 }
12213             } break;
12214
12215             case ma_device_type_playback:
12216             {
12217                 /* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
12218                 ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
12219                 ma_uint32 framesWrittenThisPeriod = 0;
12220                 while (framesWrittenThisPeriod < periodSizeInFrames) {
12221                     ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
12222                     ma_uint32 framesProcessed;
12223                     ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
12224                     if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) {
12225                         framesToWriteThisIteration = playbackDeviceDataCapInFrames;
12226                     }
12227
12228                     ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData);
12229
12230                     result = pDevice->pContext->callbacks.onDeviceWrite(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed);
12231                     if (result != MA_SUCCESS) {
12232                         exitLoop = MA_TRUE;
12233                         break;
12234                     }
12235
12236                     framesWrittenThisPeriod += framesProcessed;
12237                 }
12238             } break;
12239
12240             /* Should never get here. */
12241             default: break;
12242         }
12243     }
12244
12245     return result;
12246 }
12247
12248
12249
12250 /*******************************************************************************
12251
12252 Null Backend
12253
12254 *******************************************************************************/
12255 #ifdef MA_HAS_NULL
12256
12257 #define MA_DEVICE_OP_NONE__NULL    0
12258 #define MA_DEVICE_OP_START__NULL   1
12259 #define MA_DEVICE_OP_SUSPEND__NULL 2
12260 #define MA_DEVICE_OP_KILL__NULL    3
12261
12262 static ma_thread_result MA_THREADCALL ma_device_thread__null(void* pData)
12263 {
12264     ma_device* pDevice = (ma_device*)pData;
12265     MA_ASSERT(pDevice != NULL);
12266
12267     for (;;) {  /* Keep the thread alive until the device is uninitialized. */
12268         ma_uint32 operation;
12269
12270         /* Wait for an operation to be requested. */
12271         ma_event_wait(&pDevice->null_device.operationEvent);
12272
12273         /* At this point an event should have been triggered. */
12274         operation = pDevice->null_device.operation;
12275
12276         /* Starting the device needs to put the thread into a loop. */
12277         if (operation == MA_DEVICE_OP_START__NULL) {
12278             /* Reset the timer just in case. */
12279             ma_timer_init(&pDevice->null_device.timer);
12280
12281             /* Getting here means a suspend or kill operation has been requested. */
12282             pDevice->null_device.operationResult = MA_SUCCESS;
12283             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
12284             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
12285             continue;
12286         }
12287
12288         /* Suspending the device means we need to stop the timer and just continue the loop. */
12289         if (operation == MA_DEVICE_OP_SUSPEND__NULL) {
12290             /* We need to add the current run time to the prior run time, then reset the timer. */
12291             pDevice->null_device.priorRunTime += ma_timer_get_time_in_seconds(&pDevice->null_device.timer);
12292             ma_timer_init(&pDevice->null_device.timer);
12293
12294             /* We're done. */
12295             pDevice->null_device.operationResult = MA_SUCCESS;
12296             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
12297             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
12298             continue;
12299         }
12300
12301         /* Killing the device means we need to get out of this loop so that this thread can terminate. */
12302         if (operation == MA_DEVICE_OP_KILL__NULL) {
12303             pDevice->null_device.operationResult = MA_SUCCESS;
12304             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
12305             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
12306             break;
12307         }
12308
12309         /* Getting a signal on a "none" operation probably means an error. Return invalid operation. */
12310         if (operation == MA_DEVICE_OP_NONE__NULL) {
12311             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). */
12312             pDevice->null_device.operationResult = MA_INVALID_OPERATION;
12313             ma_event_signal(&pDevice->null_device.operationCompletionEvent);
12314             ma_semaphore_release(&pDevice->null_device.operationSemaphore);
12315             continue;   /* Continue the loop. Don't terminate. */
12316         }
12317     }
12318
12319     return (ma_thread_result)0;
12320 }
12321
12322 static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 operation)
12323 {
12324     ma_result result;
12325
12326     /*
12327     TODO: Need to review this and consider just using mutual exclusion. I think the original motivation
12328     for this was to just post the event to a queue and return immediately, but that has since changed
12329     and now this function is synchronous. I think this can be simplified to just use a mutex.
12330     */
12331
12332     /*
12333     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
12334     to support queing of operations.
12335     */
12336     result = ma_semaphore_wait(&pDevice->null_device.operationSemaphore);
12337     if (result != MA_SUCCESS) {
12338         return result;  /* Failed to wait for the event. */
12339     }
12340
12341     /*
12342     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
12343     signal an event to the worker thread to let it know that it can start work.
12344     */
12345     pDevice->null_device.operation = operation;
12346
12347     /* Once the operation code has been set, the worker thread can start work. */
12348     if (ma_event_signal(&pDevice->null_device.operationEvent) != MA_SUCCESS) {
12349         return MA_ERROR;
12350     }
12351
12352     /* We want everything to be synchronous so we're going to wait for the worker thread to complete it's operation. */
12353     if (ma_event_wait(&pDevice->null_device.operationCompletionEvent) != MA_SUCCESS) {
12354         return MA_ERROR;
12355     }
12356
12357     return pDevice->null_device.operationResult;
12358 }
12359
12360 static ma_uint64 ma_device_get_total_run_time_in_frames__null(ma_device* pDevice)
12361 {
12362     ma_uint32 internalSampleRate;
12363     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
12364         internalSampleRate = pDevice->capture.internalSampleRate;
12365     } else {
12366         internalSampleRate = pDevice->playback.internalSampleRate;
12367     }
12368
12369     return (ma_uint64)((pDevice->null_device.priorRunTime + ma_timer_get_time_in_seconds(&pDevice->null_device.timer)) * internalSampleRate);
12370 }
12371
12372 static ma_result ma_context_enumerate_devices__null(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
12373 {
12374     ma_bool32 cbResult = MA_TRUE;
12375
12376     MA_ASSERT(pContext != NULL);
12377     MA_ASSERT(callback != NULL);
12378
12379     /* Playback. */
12380     if (cbResult) {
12381         ma_device_info deviceInfo;
12382         MA_ZERO_OBJECT(&deviceInfo);
12383         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Playback Device", (size_t)-1);
12384         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
12385     }
12386
12387     /* Capture. */
12388     if (cbResult) {
12389         ma_device_info deviceInfo;
12390         MA_ZERO_OBJECT(&deviceInfo);
12391         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "NULL Capture Device", (size_t)-1);
12392         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
12393     }
12394
12395     (void)cbResult; /* Silence a static analysis warning. */
12396
12397     return MA_SUCCESS;
12398 }
12399
12400 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)
12401 {
12402     MA_ASSERT(pContext != NULL);
12403
12404     if (pDeviceID != NULL && pDeviceID->nullbackend != 0) {
12405         return MA_NO_DEVICE;   /* Don't know the device. */
12406     }
12407
12408     /* Name / Description */
12409     if (deviceType == ma_device_type_playback) {
12410         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Playback Device", (size_t)-1);
12411     } else {
12412         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), "NULL Capture Device", (size_t)-1);
12413     }
12414
12415     /* Support everything on the null backend. */
12416     pDeviceInfo->nativeDataFormats[0].format     = ma_format_unknown;
12417     pDeviceInfo->nativeDataFormats[0].channels   = 0;
12418     pDeviceInfo->nativeDataFormats[0].sampleRate = 0;
12419     pDeviceInfo->nativeDataFormats[0].flags      = 0;
12420     pDeviceInfo->nativeDataFormatCount = 1;
12421
12422     (void)pContext;
12423     return MA_SUCCESS;
12424 }
12425
12426
12427 static ma_result ma_device_uninit__null(ma_device* pDevice)
12428 {
12429     MA_ASSERT(pDevice != NULL);
12430
12431     /* Keep it clean and wait for the device thread to finish before returning. */
12432     ma_device_do_operation__null(pDevice, MA_DEVICE_OP_KILL__NULL);
12433
12434     /* Wait for the thread to finish before continuing. */
12435     ma_thread_wait(&pDevice->null_device.deviceThread);
12436
12437     /* At this point the loop in the device thread is as good as terminated so we can uninitialize our events. */
12438     ma_semaphore_uninit(&pDevice->null_device.operationSemaphore);
12439     ma_event_uninit(&pDevice->null_device.operationCompletionEvent);
12440     ma_event_uninit(&pDevice->null_device.operationEvent);
12441
12442     return MA_SUCCESS;
12443 }
12444
12445 static ma_result ma_device_init__null(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
12446 {
12447     ma_result result;
12448
12449     MA_ASSERT(pDevice != NULL);
12450
12451     MA_ZERO_OBJECT(&pDevice->null_device);
12452
12453     if (pConfig->deviceType == ma_device_type_loopback) {
12454         return MA_DEVICE_TYPE_NOT_SUPPORTED;
12455     }
12456
12457     /* The null backend supports everything exactly as we specify it. */
12458     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
12459         pDescriptorCapture->format     = (pDescriptorCapture->format     != ma_format_unknown) ? pDescriptorCapture->format     : MA_DEFAULT_FORMAT;
12460         pDescriptorCapture->channels   = (pDescriptorCapture->channels   != 0)                 ? pDescriptorCapture->channels   : MA_DEFAULT_CHANNELS;
12461         pDescriptorCapture->sampleRate = (pDescriptorCapture->sampleRate != 0)                 ? pDescriptorCapture->sampleRate : MA_DEFAULT_SAMPLE_RATE;
12462
12463         if (pDescriptorCapture->channelMap[0] == MA_CHANNEL_NONE) {
12464             ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
12465         }
12466
12467         pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
12468     }
12469
12470     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
12471         pDescriptorPlayback->format     = (pDescriptorPlayback->format     != ma_format_unknown) ? pDescriptorPlayback->format     : MA_DEFAULT_FORMAT;
12472         pDescriptorPlayback->channels   = (pDescriptorPlayback->channels   != 0)                 ? pDescriptorPlayback->channels   : MA_DEFAULT_CHANNELS;
12473         pDescriptorPlayback->sampleRate = (pDescriptorPlayback->sampleRate != 0)                 ? pDescriptorPlayback->sampleRate : MA_DEFAULT_SAMPLE_RATE;
12474
12475         if (pDescriptorPlayback->channelMap[0] == MA_CHANNEL_NONE) {
12476             ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
12477         }
12478
12479         pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
12480     }
12481
12482     /*
12483     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
12484     first period is "written" to it, and then stopped in ma_device_stop__null().
12485     */
12486     result = ma_event_init(&pDevice->null_device.operationEvent);
12487     if (result != MA_SUCCESS) {
12488         return result;
12489     }
12490
12491     result = ma_event_init(&pDevice->null_device.operationCompletionEvent);
12492     if (result != MA_SUCCESS) {
12493         return result;
12494     }
12495
12496     result = ma_semaphore_init(1, &pDevice->null_device.operationSemaphore);    /* <-- It's important that the initial value is set to 1. */
12497     if (result != MA_SUCCESS) {
12498         return result;
12499     }
12500
12501     result = ma_thread_create(&pDevice->null_device.deviceThread, pDevice->pContext->threadPriority, 0, ma_device_thread__null, pDevice);
12502     if (result != MA_SUCCESS) {
12503         return result;
12504     }
12505
12506     return MA_SUCCESS;
12507 }
12508
12509 static ma_result ma_device_start__null(ma_device* pDevice)
12510 {
12511     MA_ASSERT(pDevice != NULL);
12512
12513     ma_device_do_operation__null(pDevice, MA_DEVICE_OP_START__NULL);
12514
12515     c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_TRUE);
12516     return MA_SUCCESS;
12517 }
12518
12519 static ma_result ma_device_stop__null(ma_device* pDevice)
12520 {
12521     MA_ASSERT(pDevice != NULL);
12522
12523     ma_device_do_operation__null(pDevice, MA_DEVICE_OP_SUSPEND__NULL);
12524
12525     c89atomic_exchange_32(&pDevice->null_device.isStarted, MA_FALSE);
12526     return MA_SUCCESS;
12527 }
12528
12529 static ma_result ma_device_write__null(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
12530 {
12531     ma_result result = MA_SUCCESS;
12532     ma_uint32 totalPCMFramesProcessed;
12533     ma_bool32 wasStartedOnEntry;
12534
12535     if (pFramesWritten != NULL) {
12536         *pFramesWritten = 0;
12537     }
12538
12539     wasStartedOnEntry = c89atomic_load_32(&pDevice->null_device.isStarted);
12540
12541     /* Keep going until everything has been read. */
12542     totalPCMFramesProcessed = 0;
12543     while (totalPCMFramesProcessed < frameCount) {
12544         ma_uint64 targetFrame;
12545
12546         /* If there are any frames remaining in the current period, consume those first. */
12547         if (pDevice->null_device.currentPeriodFramesRemainingPlayback > 0) {
12548             ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
12549             ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingPlayback;
12550             if (framesToProcess > framesRemaining) {
12551                 framesToProcess = framesRemaining;
12552             }
12553
12554             /* We don't actually do anything with pPCMFrames, so just mark it as unused to prevent a warning. */
12555             (void)pPCMFrames;
12556
12557             pDevice->null_device.currentPeriodFramesRemainingPlayback -= framesToProcess;
12558             totalPCMFramesProcessed += framesToProcess;
12559         }
12560
12561         /* 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. */
12562         if (pDevice->null_device.currentPeriodFramesRemainingPlayback == 0) {
12563             pDevice->null_device.currentPeriodFramesRemainingPlayback = 0;
12564
12565             if (!c89atomic_load_32(&pDevice->null_device.isStarted) && !wasStartedOnEntry) {
12566                 result = ma_device_start__null(pDevice);
12567                 if (result != MA_SUCCESS) {
12568                     break;
12569                 }
12570             }
12571         }
12572
12573         /* If we've consumed the whole buffer we can return now. */
12574         MA_ASSERT(totalPCMFramesProcessed <= frameCount);
12575         if (totalPCMFramesProcessed == frameCount) {
12576             break;
12577         }
12578
12579         /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */
12580         targetFrame = pDevice->null_device.lastProcessedFramePlayback;
12581         for (;;) {
12582             ma_uint64 currentFrame;
12583
12584             /* Stop waiting if the device has been stopped. */
12585             if (!c89atomic_load_32(&pDevice->null_device.isStarted)) {
12586                 break;
12587             }
12588
12589             currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice);
12590             if (currentFrame >= targetFrame) {
12591                 break;
12592             }
12593
12594             /* Getting here means we haven't yet reached the target sample, so continue waiting. */
12595             ma_sleep(10);
12596         }
12597
12598         pDevice->null_device.lastProcessedFramePlayback          += pDevice->playback.internalPeriodSizeInFrames;
12599         pDevice->null_device.currentPeriodFramesRemainingPlayback = pDevice->playback.internalPeriodSizeInFrames;
12600     }
12601
12602     if (pFramesWritten != NULL) {
12603         *pFramesWritten = totalPCMFramesProcessed;
12604     }
12605
12606     return result;
12607 }
12608
12609 static ma_result ma_device_read__null(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
12610 {
12611     ma_result result = MA_SUCCESS;
12612     ma_uint32 totalPCMFramesProcessed;
12613
12614     if (pFramesRead != NULL) {
12615         *pFramesRead = 0;
12616     }
12617
12618     /* Keep going until everything has been read. */
12619     totalPCMFramesProcessed = 0;
12620     while (totalPCMFramesProcessed < frameCount) {
12621         ma_uint64 targetFrame;
12622
12623         /* If there are any frames remaining in the current period, consume those first. */
12624         if (pDevice->null_device.currentPeriodFramesRemainingCapture > 0) {
12625             ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
12626             ma_uint32 framesRemaining = (frameCount - totalPCMFramesProcessed);
12627             ma_uint32 framesToProcess = pDevice->null_device.currentPeriodFramesRemainingCapture;
12628             if (framesToProcess > framesRemaining) {
12629                 framesToProcess = framesRemaining;
12630             }
12631
12632             /* We need to ensure the output buffer is zeroed. */
12633             MA_ZERO_MEMORY(ma_offset_ptr(pPCMFrames, totalPCMFramesProcessed*bpf), framesToProcess*bpf);
12634
12635             pDevice->null_device.currentPeriodFramesRemainingCapture -= framesToProcess;
12636             totalPCMFramesProcessed += framesToProcess;
12637         }
12638
12639         /* 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. */
12640         if (pDevice->null_device.currentPeriodFramesRemainingCapture == 0) {
12641             pDevice->null_device.currentPeriodFramesRemainingCapture = 0;
12642         }
12643
12644         /* If we've consumed the whole buffer we can return now. */
12645         MA_ASSERT(totalPCMFramesProcessed <= frameCount);
12646         if (totalPCMFramesProcessed == frameCount) {
12647             break;
12648         }
12649
12650         /* Getting here means we've still got more frames to consume, we but need to wait for it to become available. */
12651         targetFrame = pDevice->null_device.lastProcessedFrameCapture + pDevice->capture.internalPeriodSizeInFrames;
12652         for (;;) {
12653             ma_uint64 currentFrame;
12654
12655             /* Stop waiting if the device has been stopped. */
12656             if (!c89atomic_load_32(&pDevice->null_device.isStarted)) {
12657                 break;
12658             }
12659
12660             currentFrame = ma_device_get_total_run_time_in_frames__null(pDevice);
12661             if (currentFrame >= targetFrame) {
12662                 break;
12663             }
12664
12665             /* Getting here means we haven't yet reached the target sample, so continue waiting. */
12666             ma_sleep(10);
12667         }
12668
12669         pDevice->null_device.lastProcessedFrameCapture          += pDevice->capture.internalPeriodSizeInFrames;
12670         pDevice->null_device.currentPeriodFramesRemainingCapture = pDevice->capture.internalPeriodSizeInFrames;
12671     }
12672
12673     if (pFramesRead != NULL) {
12674         *pFramesRead = totalPCMFramesProcessed;
12675     }
12676
12677     return result;
12678 }
12679
12680 static ma_result ma_context_uninit__null(ma_context* pContext)
12681 {
12682     MA_ASSERT(pContext != NULL);
12683     MA_ASSERT(pContext->backend == ma_backend_null);
12684
12685     (void)pContext;
12686     return MA_SUCCESS;
12687 }
12688
12689 static ma_result ma_context_init__null(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
12690 {
12691     MA_ASSERT(pContext != NULL);
12692
12693     (void)pConfig;
12694     (void)pContext;
12695
12696     pCallbacks->onContextInit             = ma_context_init__null;
12697     pCallbacks->onContextUninit           = ma_context_uninit__null;
12698     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__null;
12699     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__null;
12700     pCallbacks->onDeviceInit              = ma_device_init__null;
12701     pCallbacks->onDeviceUninit            = ma_device_uninit__null;
12702     pCallbacks->onDeviceStart             = ma_device_start__null;
12703     pCallbacks->onDeviceStop              = ma_device_stop__null;
12704     pCallbacks->onDeviceRead              = ma_device_read__null;
12705     pCallbacks->onDeviceWrite             = ma_device_write__null;
12706     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. */
12707
12708     /* The null backend always works. */
12709     return MA_SUCCESS;
12710 }
12711 #endif
12712
12713
12714
12715 /*******************************************************************************
12716
12717 WIN32 COMMON
12718
12719 *******************************************************************************/
12720 #if defined(MA_WIN32)
12721 #if defined(MA_WIN32_DESKTOP)
12722     #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit)                          ((MA_PFN_CoInitializeEx)pContext->win32.CoInitializeEx)(pvReserved, dwCoInit)
12723     #define ma_CoUninitialize(pContext)                                                ((MA_PFN_CoUninitialize)pContext->win32.CoUninitialize)()
12724     #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv)  ((MA_PFN_CoCreateInstance)pContext->win32.CoCreateInstance)(rclsid, pUnkOuter, dwClsContext, riid, ppv)
12725     #define ma_CoTaskMemFree(pContext, pv)                                             ((MA_PFN_CoTaskMemFree)pContext->win32.CoTaskMemFree)(pv)
12726     #define ma_PropVariantClear(pContext, pvar)                                        ((MA_PFN_PropVariantClear)pContext->win32.PropVariantClear)(pvar)
12727 #else
12728     #define ma_CoInitializeEx(pContext, pvReserved, dwCoInit)                          CoInitializeEx(pvReserved, dwCoInit)
12729     #define ma_CoUninitialize(pContext)                                                CoUninitialize()
12730     #define ma_CoCreateInstance(pContext, rclsid, pUnkOuter, dwClsContext, riid, ppv)  CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv)
12731     #define ma_CoTaskMemFree(pContext, pv)                                             CoTaskMemFree(pv)
12732     #define ma_PropVariantClear(pContext, pvar)                                        PropVariantClear(pvar)
12733 #endif
12734
12735 #if !defined(MAXULONG_PTR) && !defined(__WATCOMC__)
12736 typedef size_t DWORD_PTR;
12737 #endif
12738
12739 #if !defined(WAVE_FORMAT_44M08)
12740 #define WAVE_FORMAT_44M08 0x00000100
12741 #define WAVE_FORMAT_44S08 0x00000200
12742 #define WAVE_FORMAT_44M16 0x00000400
12743 #define WAVE_FORMAT_44S16 0x00000800
12744 #define WAVE_FORMAT_48M08 0x00001000
12745 #define WAVE_FORMAT_48S08 0x00002000
12746 #define WAVE_FORMAT_48M16 0x00004000
12747 #define WAVE_FORMAT_48S16 0x00008000
12748 #define WAVE_FORMAT_96M08 0x00010000
12749 #define WAVE_FORMAT_96S08 0x00020000
12750 #define WAVE_FORMAT_96M16 0x00040000
12751 #define WAVE_FORMAT_96S16 0x00080000
12752 #endif
12753
12754 #ifndef SPEAKER_FRONT_LEFT
12755 #define SPEAKER_FRONT_LEFT            0x1
12756 #define SPEAKER_FRONT_RIGHT           0x2
12757 #define SPEAKER_FRONT_CENTER          0x4
12758 #define SPEAKER_LOW_FREQUENCY         0x8
12759 #define SPEAKER_BACK_LEFT             0x10
12760 #define SPEAKER_BACK_RIGHT            0x20
12761 #define SPEAKER_FRONT_LEFT_OF_CENTER  0x40
12762 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
12763 #define SPEAKER_BACK_CENTER           0x100
12764 #define SPEAKER_SIDE_LEFT             0x200
12765 #define SPEAKER_SIDE_RIGHT            0x400
12766 #define SPEAKER_TOP_CENTER            0x800
12767 #define SPEAKER_TOP_FRONT_LEFT        0x1000
12768 #define SPEAKER_TOP_FRONT_CENTER      0x2000
12769 #define SPEAKER_TOP_FRONT_RIGHT       0x4000
12770 #define SPEAKER_TOP_BACK_LEFT         0x8000
12771 #define SPEAKER_TOP_BACK_CENTER       0x10000
12772 #define SPEAKER_TOP_BACK_RIGHT        0x20000
12773 #endif
12774
12775 /*
12776 The SDK that comes with old versions of MSVC (VC6, for example) does not appear to define WAVEFORMATEXTENSIBLE. We
12777 define our own implementation in this case.
12778 */
12779 #if (defined(_MSC_VER) && !defined(_WAVEFORMATEXTENSIBLE_)) || defined(__DMC__)
12780 typedef struct
12781 {
12782     WAVEFORMATEX Format;
12783     union
12784     {
12785         WORD wValidBitsPerSample;
12786         WORD wSamplesPerBlock;
12787         WORD wReserved;
12788     } Samples;
12789     DWORD dwChannelMask;
12790     GUID SubFormat;
12791 } WAVEFORMATEXTENSIBLE;
12792 #endif
12793
12794 #ifndef WAVE_FORMAT_EXTENSIBLE
12795 #define WAVE_FORMAT_EXTENSIBLE  0xFFFE
12796 #endif
12797
12798 #ifndef WAVE_FORMAT_IEEE_FLOAT
12799 #define WAVE_FORMAT_IEEE_FLOAT  0x0003
12800 #endif
12801
12802 /* Converts an individual Win32-style channel identifier (SPEAKER_FRONT_LEFT, etc.) to miniaudio. */
12803 static ma_uint8 ma_channel_id_to_ma__win32(DWORD id)
12804 {
12805     switch (id)
12806     {
12807         case SPEAKER_FRONT_LEFT:            return MA_CHANNEL_FRONT_LEFT;
12808         case SPEAKER_FRONT_RIGHT:           return MA_CHANNEL_FRONT_RIGHT;
12809         case SPEAKER_FRONT_CENTER:          return MA_CHANNEL_FRONT_CENTER;
12810         case SPEAKER_LOW_FREQUENCY:         return MA_CHANNEL_LFE;
12811         case SPEAKER_BACK_LEFT:             return MA_CHANNEL_BACK_LEFT;
12812         case SPEAKER_BACK_RIGHT:            return MA_CHANNEL_BACK_RIGHT;
12813         case SPEAKER_FRONT_LEFT_OF_CENTER:  return MA_CHANNEL_FRONT_LEFT_CENTER;
12814         case SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
12815         case SPEAKER_BACK_CENTER:           return MA_CHANNEL_BACK_CENTER;
12816         case SPEAKER_SIDE_LEFT:             return MA_CHANNEL_SIDE_LEFT;
12817         case SPEAKER_SIDE_RIGHT:            return MA_CHANNEL_SIDE_RIGHT;
12818         case SPEAKER_TOP_CENTER:            return MA_CHANNEL_TOP_CENTER;
12819         case SPEAKER_TOP_FRONT_LEFT:        return MA_CHANNEL_TOP_FRONT_LEFT;
12820         case SPEAKER_TOP_FRONT_CENTER:      return MA_CHANNEL_TOP_FRONT_CENTER;
12821         case SPEAKER_TOP_FRONT_RIGHT:       return MA_CHANNEL_TOP_FRONT_RIGHT;
12822         case SPEAKER_TOP_BACK_LEFT:         return MA_CHANNEL_TOP_BACK_LEFT;
12823         case SPEAKER_TOP_BACK_CENTER:       return MA_CHANNEL_TOP_BACK_CENTER;
12824         case SPEAKER_TOP_BACK_RIGHT:        return MA_CHANNEL_TOP_BACK_RIGHT;
12825         default: return 0;
12826     }
12827 }
12828
12829 /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to Win32-style. */
12830 static DWORD ma_channel_id_to_win32(DWORD id)
12831 {
12832     switch (id)
12833     {
12834         case MA_CHANNEL_MONO:               return SPEAKER_FRONT_CENTER;
12835         case MA_CHANNEL_FRONT_LEFT:         return SPEAKER_FRONT_LEFT;
12836         case MA_CHANNEL_FRONT_RIGHT:        return SPEAKER_FRONT_RIGHT;
12837         case MA_CHANNEL_FRONT_CENTER:       return SPEAKER_FRONT_CENTER;
12838         case MA_CHANNEL_LFE:                return SPEAKER_LOW_FREQUENCY;
12839         case MA_CHANNEL_BACK_LEFT:          return SPEAKER_BACK_LEFT;
12840         case MA_CHANNEL_BACK_RIGHT:         return SPEAKER_BACK_RIGHT;
12841         case MA_CHANNEL_FRONT_LEFT_CENTER:  return SPEAKER_FRONT_LEFT_OF_CENTER;
12842         case MA_CHANNEL_FRONT_RIGHT_CENTER: return SPEAKER_FRONT_RIGHT_OF_CENTER;
12843         case MA_CHANNEL_BACK_CENTER:        return SPEAKER_BACK_CENTER;
12844         case MA_CHANNEL_SIDE_LEFT:          return SPEAKER_SIDE_LEFT;
12845         case MA_CHANNEL_SIDE_RIGHT:         return SPEAKER_SIDE_RIGHT;
12846         case MA_CHANNEL_TOP_CENTER:         return SPEAKER_TOP_CENTER;
12847         case MA_CHANNEL_TOP_FRONT_LEFT:     return SPEAKER_TOP_FRONT_LEFT;
12848         case MA_CHANNEL_TOP_FRONT_CENTER:   return SPEAKER_TOP_FRONT_CENTER;
12849         case MA_CHANNEL_TOP_FRONT_RIGHT:    return SPEAKER_TOP_FRONT_RIGHT;
12850         case MA_CHANNEL_TOP_BACK_LEFT:      return SPEAKER_TOP_BACK_LEFT;
12851         case MA_CHANNEL_TOP_BACK_CENTER:    return SPEAKER_TOP_BACK_CENTER;
12852         case MA_CHANNEL_TOP_BACK_RIGHT:     return SPEAKER_TOP_BACK_RIGHT;
12853         default: return 0;
12854     }
12855 }
12856
12857 /* Converts a channel mapping to a Win32-style channel mask. */
12858 static DWORD ma_channel_map_to_channel_mask__win32(const ma_channel* pChannelMap, ma_uint32 channels)
12859 {
12860     DWORD dwChannelMask = 0;
12861     ma_uint32 iChannel;
12862
12863     for (iChannel = 0; iChannel < channels; ++iChannel) {
12864         dwChannelMask |= ma_channel_id_to_win32(pChannelMap[iChannel]);
12865     }
12866
12867     return dwChannelMask;
12868 }
12869
12870 /* Converts a Win32-style channel mask to a miniaudio channel map. */
12871 static void ma_channel_mask_to_channel_map__win32(DWORD dwChannelMask, ma_uint32 channels, ma_channel* pChannelMap)
12872 {
12873     if (channels == 1 && dwChannelMask == 0) {
12874         pChannelMap[0] = MA_CHANNEL_MONO;
12875     } else if (channels == 2 && dwChannelMask == 0) {
12876         pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
12877         pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
12878     } else {
12879         if (channels == 1 && (dwChannelMask & SPEAKER_FRONT_CENTER) != 0) {
12880             pChannelMap[0] = MA_CHANNEL_MONO;
12881         } else {
12882             /* Just iterate over each bit. */
12883             ma_uint32 iChannel = 0;
12884             ma_uint32 iBit;
12885
12886             for (iBit = 0; iBit < 32 && iChannel < channels; ++iBit) {
12887                 DWORD bitValue = (dwChannelMask & (1UL << iBit));
12888                 if (bitValue != 0) {
12889                     /* The bit is set. */
12890                     pChannelMap[iChannel] = ma_channel_id_to_ma__win32(bitValue);
12891                     iChannel += 1;
12892                 }
12893             }
12894         }
12895     }
12896 }
12897
12898 #ifdef __cplusplus
12899 static ma_bool32 ma_is_guid_equal(const void* a, const void* b)
12900 {
12901     return IsEqualGUID(*(const GUID*)a, *(const GUID*)b);
12902 }
12903 #else
12904 #define ma_is_guid_equal(a, b) IsEqualGUID((const GUID*)a, (const GUID*)b)
12905 #endif
12906
12907 static MA_INLINE ma_bool32 ma_is_guid_null(const void* guid)
12908 {
12909     static GUID nullguid = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
12910     return ma_is_guid_equal(guid, &nullguid);
12911 }
12912
12913 static ma_format ma_format_from_WAVEFORMATEX(const WAVEFORMATEX* pWF)
12914 {
12915     MA_ASSERT(pWF != NULL);
12916
12917     if (pWF->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
12918         const WAVEFORMATEXTENSIBLE* pWFEX = (const WAVEFORMATEXTENSIBLE*)pWF;
12919         if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_PCM)) {
12920             if (pWFEX->Samples.wValidBitsPerSample == 32) {
12921                 return ma_format_s32;
12922             }
12923             if (pWFEX->Samples.wValidBitsPerSample == 24) {
12924                 if (pWFEX->Format.wBitsPerSample == 32) {
12925                     /*return ma_format_s24_32;*/
12926                 }
12927                 if (pWFEX->Format.wBitsPerSample == 24) {
12928                     return ma_format_s24;
12929                 }
12930             }
12931             if (pWFEX->Samples.wValidBitsPerSample == 16) {
12932                 return ma_format_s16;
12933             }
12934             if (pWFEX->Samples.wValidBitsPerSample == 8) {
12935                 return ma_format_u8;
12936             }
12937         }
12938         if (ma_is_guid_equal(&pWFEX->SubFormat, &MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
12939             if (pWFEX->Samples.wValidBitsPerSample == 32) {
12940                 return ma_format_f32;
12941             }
12942             /*
12943             if (pWFEX->Samples.wValidBitsPerSample == 64) {
12944                 return ma_format_f64;
12945             }
12946             */
12947         }
12948     } else {
12949         if (pWF->wFormatTag == WAVE_FORMAT_PCM) {
12950             if (pWF->wBitsPerSample == 32) {
12951                 return ma_format_s32;
12952             }
12953             if (pWF->wBitsPerSample == 24) {
12954                 return ma_format_s24;
12955             }
12956             if (pWF->wBitsPerSample == 16) {
12957                 return ma_format_s16;
12958             }
12959             if (pWF->wBitsPerSample == 8) {
12960                 return ma_format_u8;
12961             }
12962         }
12963         if (pWF->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
12964             if (pWF->wBitsPerSample == 32) {
12965                 return ma_format_f32;
12966             }
12967             if (pWF->wBitsPerSample == 64) {
12968                 /*return ma_format_f64;*/
12969             }
12970         }
12971     }
12972
12973     return ma_format_unknown;
12974 }
12975 #endif
12976
12977
12978 /*******************************************************************************
12979
12980 WASAPI Backend
12981
12982 *******************************************************************************/
12983 #ifdef MA_HAS_WASAPI
12984 #if 0
12985 #if defined(_MSC_VER)
12986     #pragma warning(push)
12987     #pragma warning(disable:4091)   /* 'typedef ': ignored on left of '' when no variable is declared */
12988 #endif
12989 #include <audioclient.h>
12990 #include <mmdeviceapi.h>
12991 #if defined(_MSC_VER)
12992     #pragma warning(pop)
12993 #endif
12994 #endif  /* 0 */
12995
12996 static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType);
12997
12998 /* Some compilers don't define VerifyVersionInfoW. Need to write this ourselves. */
12999 #define MA_WIN32_WINNT_VISTA    0x0600
13000 #define MA_VER_MINORVERSION     0x01
13001 #define MA_VER_MAJORVERSION     0x02
13002 #define MA_VER_SERVICEPACKMAJOR 0x20
13003 #define MA_VER_GREATER_EQUAL    0x03
13004
13005 typedef struct  {
13006     DWORD dwOSVersionInfoSize;
13007     DWORD dwMajorVersion;
13008     DWORD dwMinorVersion;
13009     DWORD dwBuildNumber;
13010     DWORD dwPlatformId;
13011     WCHAR szCSDVersion[128];
13012     WORD  wServicePackMajor;
13013     WORD  wServicePackMinor;
13014     WORD  wSuiteMask;
13015     BYTE  wProductType;
13016     BYTE  wReserved;
13017 } ma_OSVERSIONINFOEXW;
13018
13019 typedef BOOL      (WINAPI * ma_PFNVerifyVersionInfoW) (ma_OSVERSIONINFOEXW* lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask);
13020 typedef ULONGLONG (WINAPI * ma_PFNVerSetConditionMask)(ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask);
13021
13022
13023 #ifndef PROPERTYKEY_DEFINED
13024 #define PROPERTYKEY_DEFINED
13025 #ifndef __WATCOMC__
13026 typedef struct
13027 {
13028     GUID fmtid;
13029     DWORD pid;
13030 } PROPERTYKEY;
13031 #endif
13032 #endif
13033
13034 /* Some compilers don't define PropVariantInit(). We just do this ourselves since it's just a memset(). */
13035 static MA_INLINE void ma_PropVariantInit(PROPVARIANT* pProp)
13036 {
13037     MA_ZERO_OBJECT(pProp);
13038 }
13039
13040
13041 static const PROPERTYKEY MA_PKEY_Device_FriendlyName             = {{0xA45C254E, 0xDF1C, 0x4EFD, {0x80, 0x20, 0x67, 0xD1, 0x46, 0xA8, 0x50, 0xE0}}, 14};
13042 static const PROPERTYKEY MA_PKEY_AudioEngine_DeviceFormat        = {{0xF19F064D, 0x82C,  0x4E27, {0xBC, 0x73, 0x68, 0x82, 0xA1, 0xBB, 0x8E, 0x4C}},  0};
13043
13044 static const IID MA_IID_IUnknown                                 = {0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; /* 00000000-0000-0000-C000-000000000046 */
13045 #ifndef MA_WIN32_DESKTOP
13046 static const IID MA_IID_IAgileObject                             = {0x94EA2B94, 0xE9CC, 0x49E0, {0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90}}; /* 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90 */
13047 #endif
13048
13049 static const IID MA_IID_IAudioClient                             = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}}; /* 1CB9AD4C-DBFA-4C32-B178-C2F568A703B2 = __uuidof(IAudioClient) */
13050 static const IID MA_IID_IAudioClient2                            = {0x726778CD, 0xF60A, 0x4EDA, {0x82, 0xDE, 0xE4, 0x76, 0x10, 0xCD, 0x78, 0xAA}}; /* 726778CD-F60A-4EDA-82DE-E47610CD78AA = __uuidof(IAudioClient2) */
13051 static const IID MA_IID_IAudioClient3                            = {0x7ED4EE07, 0x8E67, 0x4CD4, {0x8C, 0x1A, 0x2B, 0x7A, 0x59, 0x87, 0xAD, 0x42}}; /* 7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42 = __uuidof(IAudioClient3) */
13052 static const IID MA_IID_IAudioRenderClient                       = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; /* F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) */
13053 static const IID MA_IID_IAudioCaptureClient                      = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; /* C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) */
13054 static const IID MA_IID_IMMNotificationClient                    = {0x7991EEC9, 0x7E89, 0x4D85, {0x83, 0x90, 0x6C, 0x70, 0x3C, 0xEC, 0x60, 0xC0}}; /* 7991EEC9-7E89-4D85-8390-6C703CEC60C0 = __uuidof(IMMNotificationClient) */
13055 #ifndef MA_WIN32_DESKTOP
13056 static const IID MA_IID_DEVINTERFACE_AUDIO_RENDER                = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; /* E6327CAD-DCEC-4949-AE8A-991E976A79D2 */
13057 static const IID MA_IID_DEVINTERFACE_AUDIO_CAPTURE               = {0x2EEF81BE, 0x33FA, 0x4800, {0x96, 0x70, 0x1C, 0xD4, 0x74, 0x97, 0x2C, 0x3F}}; /* 2EEF81BE-33FA-4800-9670-1CD474972C3F */
13058 static const IID MA_IID_IActivateAudioInterfaceCompletionHandler = {0x41D949AB, 0x9862, 0x444A, {0x80, 0xF6, 0xC2, 0x61, 0x33, 0x4D, 0xA5, 0xEB}}; /* 41D949AB-9862-444A-80F6-C261334DA5EB */
13059 #endif
13060
13061 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) */
13062 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) */
13063 #ifdef __cplusplus
13064 #define MA_CLSID_MMDeviceEnumerator MA_CLSID_MMDeviceEnumerator_Instance
13065 #define MA_IID_IMMDeviceEnumerator  MA_IID_IMMDeviceEnumerator_Instance
13066 #else
13067 #define MA_CLSID_MMDeviceEnumerator &MA_CLSID_MMDeviceEnumerator_Instance
13068 #define MA_IID_IMMDeviceEnumerator  &MA_IID_IMMDeviceEnumerator_Instance
13069 #endif
13070
13071 typedef struct ma_IUnknown                                 ma_IUnknown;
13072 #ifdef MA_WIN32_DESKTOP
13073 #define MA_MM_DEVICE_STATE_ACTIVE                          1
13074 #define MA_MM_DEVICE_STATE_DISABLED                        2
13075 #define MA_MM_DEVICE_STATE_NOTPRESENT                      4
13076 #define MA_MM_DEVICE_STATE_UNPLUGGED                       8
13077
13078 typedef struct ma_IMMDeviceEnumerator                      ma_IMMDeviceEnumerator;
13079 typedef struct ma_IMMDeviceCollection                      ma_IMMDeviceCollection;
13080 typedef struct ma_IMMDevice                                ma_IMMDevice;
13081 #else
13082 typedef struct ma_IActivateAudioInterfaceCompletionHandler ma_IActivateAudioInterfaceCompletionHandler;
13083 typedef struct ma_IActivateAudioInterfaceAsyncOperation    ma_IActivateAudioInterfaceAsyncOperation;
13084 #endif
13085 typedef struct ma_IPropertyStore                           ma_IPropertyStore;
13086 typedef struct ma_IAudioClient                             ma_IAudioClient;
13087 typedef struct ma_IAudioClient2                            ma_IAudioClient2;
13088 typedef struct ma_IAudioClient3                            ma_IAudioClient3;
13089 typedef struct ma_IAudioRenderClient                       ma_IAudioRenderClient;
13090 typedef struct ma_IAudioCaptureClient                      ma_IAudioCaptureClient;
13091
13092 typedef ma_int64                                           MA_REFERENCE_TIME;
13093
13094 #define MA_AUDCLNT_STREAMFLAGS_CROSSPROCESS                0x00010000
13095 #define MA_AUDCLNT_STREAMFLAGS_LOOPBACK                    0x00020000
13096 #define MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK               0x00040000
13097 #define MA_AUDCLNT_STREAMFLAGS_NOPERSIST                   0x00080000
13098 #define MA_AUDCLNT_STREAMFLAGS_RATEADJUST                  0x00100000
13099 #define MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY         0x08000000
13100 #define MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM              0x80000000
13101 #define MA_AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED          0x10000000
13102 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE               0x20000000
13103 #define MA_AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED    0x40000000
13104
13105 /* Buffer flags. */
13106 #define MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY          1
13107 #define MA_AUDCLNT_BUFFERFLAGS_SILENT                      2
13108 #define MA_AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR             4
13109
13110 typedef enum
13111 {
13112     ma_eRender  = 0,
13113     ma_eCapture = 1,
13114     ma_eAll     = 2
13115 } ma_EDataFlow;
13116
13117 typedef enum
13118 {
13119     ma_eConsole        = 0,
13120     ma_eMultimedia     = 1,
13121     ma_eCommunications = 2
13122 } ma_ERole;
13123
13124 typedef enum
13125 {
13126     MA_AUDCLNT_SHAREMODE_SHARED,
13127     MA_AUDCLNT_SHAREMODE_EXCLUSIVE
13128 } MA_AUDCLNT_SHAREMODE;
13129
13130 typedef enum
13131 {
13132     MA_AudioCategory_Other = 0  /* <-- miniaudio is only caring about Other. */
13133 } MA_AUDIO_STREAM_CATEGORY;
13134
13135 typedef struct
13136 {
13137     ma_uint32 cbSize;
13138     BOOL bIsOffload;
13139     MA_AUDIO_STREAM_CATEGORY eCategory;
13140 } ma_AudioClientProperties;
13141
13142 /* IUnknown */
13143 typedef struct
13144 {
13145     /* IUnknown */
13146     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IUnknown* pThis, const IID* const riid, void** ppObject);
13147     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IUnknown* pThis);
13148     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IUnknown* pThis);
13149 } ma_IUnknownVtbl;
13150 struct ma_IUnknown
13151 {
13152     ma_IUnknownVtbl* lpVtbl;
13153 };
13154 static MA_INLINE HRESULT ma_IUnknown_QueryInterface(ma_IUnknown* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13155 static MA_INLINE ULONG   ma_IUnknown_AddRef(ma_IUnknown* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
13156 static MA_INLINE ULONG   ma_IUnknown_Release(ma_IUnknown* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
13157
13158 #ifdef MA_WIN32_DESKTOP
13159     /* IMMNotificationClient */
13160     typedef struct
13161     {
13162         /* IUnknown */
13163         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject);
13164         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMNotificationClient* pThis);
13165         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMNotificationClient* pThis);
13166
13167         /* IMMNotificationClient */
13168         HRESULT (STDMETHODCALLTYPE * OnDeviceStateChanged)  (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState);
13169         HRESULT (STDMETHODCALLTYPE * OnDeviceAdded)         (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID);
13170         HRESULT (STDMETHODCALLTYPE * OnDeviceRemoved)       (ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID);
13171         HRESULT (STDMETHODCALLTYPE * OnDefaultDeviceChanged)(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID);
13172         HRESULT (STDMETHODCALLTYPE * OnPropertyValueChanged)(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key);
13173     } ma_IMMNotificationClientVtbl;
13174
13175     /* IMMDeviceEnumerator */
13176     typedef struct
13177     {
13178         /* IUnknown */
13179         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject);
13180         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMDeviceEnumerator* pThis);
13181         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMDeviceEnumerator* pThis);
13182
13183         /* IMMDeviceEnumerator */
13184         HRESULT (STDMETHODCALLTYPE * EnumAudioEndpoints)                    (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, DWORD dwStateMask, ma_IMMDeviceCollection** ppDevices);
13185         HRESULT (STDMETHODCALLTYPE * GetDefaultAudioEndpoint)               (ma_IMMDeviceEnumerator* pThis, ma_EDataFlow dataFlow, ma_ERole role, ma_IMMDevice** ppEndpoint);
13186         HRESULT (STDMETHODCALLTYPE * GetDevice)                             (ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice);
13187         HRESULT (STDMETHODCALLTYPE * RegisterEndpointNotificationCallback)  (ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient);
13188         HRESULT (STDMETHODCALLTYPE * UnregisterEndpointNotificationCallback)(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient);
13189     } ma_IMMDeviceEnumeratorVtbl;
13190     struct ma_IMMDeviceEnumerator
13191     {
13192         ma_IMMDeviceEnumeratorVtbl* lpVtbl;
13193     };
13194     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_QueryInterface(ma_IMMDeviceEnumerator* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13195     static MA_INLINE ULONG   ma_IMMDeviceEnumerator_AddRef(ma_IMMDeviceEnumerator* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
13196     static MA_INLINE ULONG   ma_IMMDeviceEnumerator_Release(ma_IMMDeviceEnumerator* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
13197     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); }
13198     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); }
13199     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_GetDevice(ma_IMMDeviceEnumerator* pThis, LPCWSTR pID, ma_IMMDevice** ppDevice)        { return pThis->lpVtbl->GetDevice(pThis, pID, ppDevice); }
13200     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_RegisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->RegisterEndpointNotificationCallback(pThis, pClient); }
13201     static MA_INLINE HRESULT ma_IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(ma_IMMDeviceEnumerator* pThis, ma_IMMNotificationClient* pClient) { return pThis->lpVtbl->UnregisterEndpointNotificationCallback(pThis, pClient); }
13202
13203
13204     /* IMMDeviceCollection */
13205     typedef struct
13206     {
13207         /* IUnknown */
13208         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject);
13209         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMDeviceCollection* pThis);
13210         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMDeviceCollection* pThis);
13211
13212         /* IMMDeviceCollection */
13213         HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IMMDeviceCollection* pThis, UINT* pDevices);
13214         HRESULT (STDMETHODCALLTYPE * Item)    (ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice);
13215     } ma_IMMDeviceCollectionVtbl;
13216     struct ma_IMMDeviceCollection
13217     {
13218         ma_IMMDeviceCollectionVtbl* lpVtbl;
13219     };
13220     static MA_INLINE HRESULT ma_IMMDeviceCollection_QueryInterface(ma_IMMDeviceCollection* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13221     static MA_INLINE ULONG   ma_IMMDeviceCollection_AddRef(ma_IMMDeviceCollection* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
13222     static MA_INLINE ULONG   ma_IMMDeviceCollection_Release(ma_IMMDeviceCollection* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
13223     static MA_INLINE HRESULT ma_IMMDeviceCollection_GetCount(ma_IMMDeviceCollection* pThis, UINT* pDevices)                               { return pThis->lpVtbl->GetCount(pThis, pDevices); }
13224     static MA_INLINE HRESULT ma_IMMDeviceCollection_Item(ma_IMMDeviceCollection* pThis, UINT nDevice, ma_IMMDevice** ppDevice)            { return pThis->lpVtbl->Item(pThis, nDevice, ppDevice); }
13225
13226
13227     /* IMMDevice */
13228     typedef struct
13229     {
13230         /* IUnknown */
13231         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IMMDevice* pThis, const IID* const riid, void** ppObject);
13232         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IMMDevice* pThis);
13233         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IMMDevice* pThis);
13234
13235         /* IMMDevice */
13236         HRESULT (STDMETHODCALLTYPE * Activate)         (ma_IMMDevice* pThis, const IID* const iid, DWORD dwClsCtx, PROPVARIANT* pActivationParams, void** ppInterface);
13237         HRESULT (STDMETHODCALLTYPE * OpenPropertyStore)(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties);
13238         HRESULT (STDMETHODCALLTYPE * GetId)            (ma_IMMDevice* pThis, LPWSTR *pID);
13239         HRESULT (STDMETHODCALLTYPE * GetState)         (ma_IMMDevice* pThis, DWORD *pState);
13240     } ma_IMMDeviceVtbl;
13241     struct ma_IMMDevice
13242     {
13243         ma_IMMDeviceVtbl* lpVtbl;
13244     };
13245     static MA_INLINE HRESULT ma_IMMDevice_QueryInterface(ma_IMMDevice* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13246     static MA_INLINE ULONG   ma_IMMDevice_AddRef(ma_IMMDevice* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
13247     static MA_INLINE ULONG   ma_IMMDevice_Release(ma_IMMDevice* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
13248     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); }
13249     static MA_INLINE HRESULT ma_IMMDevice_OpenPropertyStore(ma_IMMDevice* pThis, DWORD stgmAccess, ma_IPropertyStore** ppProperties) { return pThis->lpVtbl->OpenPropertyStore(pThis, stgmAccess, ppProperties); }
13250     static MA_INLINE HRESULT ma_IMMDevice_GetId(ma_IMMDevice* pThis, LPWSTR *pID)                                     { return pThis->lpVtbl->GetId(pThis, pID); }
13251     static MA_INLINE HRESULT ma_IMMDevice_GetState(ma_IMMDevice* pThis, DWORD *pState)                                { return pThis->lpVtbl->GetState(pThis, pState); }
13252 #else
13253     /* IActivateAudioInterfaceAsyncOperation */
13254     typedef struct
13255     {
13256         /* IUnknown */
13257         HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject);
13258         ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IActivateAudioInterfaceAsyncOperation* pThis);
13259         ULONG   (STDMETHODCALLTYPE * Release)       (ma_IActivateAudioInterfaceAsyncOperation* pThis);
13260
13261         /* IActivateAudioInterfaceAsyncOperation */
13262         HRESULT (STDMETHODCALLTYPE * GetActivateResult)(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface);
13263     } ma_IActivateAudioInterfaceAsyncOperationVtbl;
13264     struct ma_IActivateAudioInterfaceAsyncOperation
13265     {
13266         ma_IActivateAudioInterfaceAsyncOperationVtbl* lpVtbl;
13267     };
13268     static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_QueryInterface(ma_IActivateAudioInterfaceAsyncOperation* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13269     static MA_INLINE ULONG   ma_IActivateAudioInterfaceAsyncOperation_AddRef(ma_IActivateAudioInterfaceAsyncOperation* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
13270     static MA_INLINE ULONG   ma_IActivateAudioInterfaceAsyncOperation_Release(ma_IActivateAudioInterfaceAsyncOperation* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
13271     static MA_INLINE HRESULT ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(ma_IActivateAudioInterfaceAsyncOperation* pThis, HRESULT *pActivateResult, ma_IUnknown** ppActivatedInterface) { return pThis->lpVtbl->GetActivateResult(pThis, pActivateResult, ppActivatedInterface); }
13272 #endif
13273
13274 /* IPropertyStore */
13275 typedef struct
13276 {
13277     /* IUnknown */
13278     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject);
13279     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IPropertyStore* pThis);
13280     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IPropertyStore* pThis);
13281
13282     /* IPropertyStore */
13283     HRESULT (STDMETHODCALLTYPE * GetCount)(ma_IPropertyStore* pThis, DWORD* pPropCount);
13284     HRESULT (STDMETHODCALLTYPE * GetAt)   (ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey);
13285     HRESULT (STDMETHODCALLTYPE * GetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar);
13286     HRESULT (STDMETHODCALLTYPE * SetValue)(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, const PROPVARIANT* const pPropVar);
13287     HRESULT (STDMETHODCALLTYPE * Commit)  (ma_IPropertyStore* pThis);
13288 } ma_IPropertyStoreVtbl;
13289 struct ma_IPropertyStore
13290 {
13291     ma_IPropertyStoreVtbl* lpVtbl;
13292 };
13293 static MA_INLINE HRESULT ma_IPropertyStore_QueryInterface(ma_IPropertyStore* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13294 static MA_INLINE ULONG   ma_IPropertyStore_AddRef(ma_IPropertyStore* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
13295 static MA_INLINE ULONG   ma_IPropertyStore_Release(ma_IPropertyStore* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
13296 static MA_INLINE HRESULT ma_IPropertyStore_GetCount(ma_IPropertyStore* pThis, DWORD* pPropCount)                            { return pThis->lpVtbl->GetCount(pThis, pPropCount); }
13297 static MA_INLINE HRESULT ma_IPropertyStore_GetAt(ma_IPropertyStore* pThis, DWORD propIndex, PROPERTYKEY* pPropKey)          { return pThis->lpVtbl->GetAt(pThis, propIndex, pPropKey); }
13298 static MA_INLINE HRESULT ma_IPropertyStore_GetValue(ma_IPropertyStore* pThis, const PROPERTYKEY* const pKey, PROPVARIANT* pPropVar) { return pThis->lpVtbl->GetValue(pThis, pKey, pPropVar); }
13299 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); }
13300 static MA_INLINE HRESULT ma_IPropertyStore_Commit(ma_IPropertyStore* pThis)                                                 { return pThis->lpVtbl->Commit(pThis); }
13301
13302
13303 /* IAudioClient */
13304 typedef struct
13305 {
13306     /* IUnknown */
13307     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient* pThis, const IID* const riid, void** ppObject);
13308     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioClient* pThis);
13309     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioClient* pThis);
13310
13311     /* IAudioClient */
13312     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);
13313     HRESULT (STDMETHODCALLTYPE * GetBufferSize)    (ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames);
13314     HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency);
13315     HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames);
13316     HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
13317     HRESULT (STDMETHODCALLTYPE * GetMixFormat)     (ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat);
13318     HRESULT (STDMETHODCALLTYPE * GetDevicePeriod)  (ma_IAudioClient* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
13319     HRESULT (STDMETHODCALLTYPE * Start)            (ma_IAudioClient* pThis);
13320     HRESULT (STDMETHODCALLTYPE * Stop)             (ma_IAudioClient* pThis);
13321     HRESULT (STDMETHODCALLTYPE * Reset)            (ma_IAudioClient* pThis);
13322     HRESULT (STDMETHODCALLTYPE * SetEventHandle)   (ma_IAudioClient* pThis, HANDLE eventHandle);
13323     HRESULT (STDMETHODCALLTYPE * GetService)       (ma_IAudioClient* pThis, const IID* const riid, void** pp);
13324 } ma_IAudioClientVtbl;
13325 struct ma_IAudioClient
13326 {
13327     ma_IAudioClientVtbl* lpVtbl;
13328 };
13329 static MA_INLINE HRESULT ma_IAudioClient_QueryInterface(ma_IAudioClient* pThis, const IID* const riid, void** ppObject)    { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13330 static MA_INLINE ULONG   ma_IAudioClient_AddRef(ma_IAudioClient* pThis)                                                    { return pThis->lpVtbl->AddRef(pThis); }
13331 static MA_INLINE ULONG   ma_IAudioClient_Release(ma_IAudioClient* pThis)                                                   { return pThis->lpVtbl->Release(pThis); }
13332 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); }
13333 static MA_INLINE HRESULT ma_IAudioClient_GetBufferSize(ma_IAudioClient* pThis, ma_uint32* pNumBufferFrames)                { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
13334 static MA_INLINE HRESULT ma_IAudioClient_GetStreamLatency(ma_IAudioClient* pThis, MA_REFERENCE_TIME* pLatency)             { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
13335 static MA_INLINE HRESULT ma_IAudioClient_GetCurrentPadding(ma_IAudioClient* pThis, ma_uint32* pNumPaddingFrames)           { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
13336 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); }
13337 static MA_INLINE HRESULT ma_IAudioClient_GetMixFormat(ma_IAudioClient* pThis, WAVEFORMATEX** ppDeviceFormat)               { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
13338 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); }
13339 static MA_INLINE HRESULT ma_IAudioClient_Start(ma_IAudioClient* pThis)                                                     { return pThis->lpVtbl->Start(pThis); }
13340 static MA_INLINE HRESULT ma_IAudioClient_Stop(ma_IAudioClient* pThis)                                                      { return pThis->lpVtbl->Stop(pThis); }
13341 static MA_INLINE HRESULT ma_IAudioClient_Reset(ma_IAudioClient* pThis)                                                     { return pThis->lpVtbl->Reset(pThis); }
13342 static MA_INLINE HRESULT ma_IAudioClient_SetEventHandle(ma_IAudioClient* pThis, HANDLE eventHandle)                        { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
13343 static MA_INLINE HRESULT ma_IAudioClient_GetService(ma_IAudioClient* pThis, const IID* const riid, void** pp)              { return pThis->lpVtbl->GetService(pThis, riid, pp); }
13344
13345 /* IAudioClient2 */
13346 typedef struct
13347 {
13348     /* IUnknown */
13349     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject);
13350     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioClient2* pThis);
13351     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioClient2* pThis);
13352
13353     /* IAudioClient */
13354     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);
13355     HRESULT (STDMETHODCALLTYPE * GetBufferSize)    (ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames);
13356     HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency);
13357     HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames);
13358     HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient2* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
13359     HRESULT (STDMETHODCALLTYPE * GetMixFormat)     (ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat);
13360     HRESULT (STDMETHODCALLTYPE * GetDevicePeriod)  (ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
13361     HRESULT (STDMETHODCALLTYPE * Start)            (ma_IAudioClient2* pThis);
13362     HRESULT (STDMETHODCALLTYPE * Stop)             (ma_IAudioClient2* pThis);
13363     HRESULT (STDMETHODCALLTYPE * Reset)            (ma_IAudioClient2* pThis);
13364     HRESULT (STDMETHODCALLTYPE * SetEventHandle)   (ma_IAudioClient2* pThis, HANDLE eventHandle);
13365     HRESULT (STDMETHODCALLTYPE * GetService)       (ma_IAudioClient2* pThis, const IID* const riid, void** pp);
13366
13367     /* IAudioClient2 */
13368     HRESULT (STDMETHODCALLTYPE * IsOffloadCapable)   (ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable);
13369     HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties);
13370     HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient2* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration);
13371 } ma_IAudioClient2Vtbl;
13372 struct ma_IAudioClient2
13373 {
13374     ma_IAudioClient2Vtbl* lpVtbl;
13375 };
13376 static MA_INLINE HRESULT ma_IAudioClient2_QueryInterface(ma_IAudioClient2* pThis, const IID* const riid, void** ppObject)    { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13377 static MA_INLINE ULONG   ma_IAudioClient2_AddRef(ma_IAudioClient2* pThis)                                                    { return pThis->lpVtbl->AddRef(pThis); }
13378 static MA_INLINE ULONG   ma_IAudioClient2_Release(ma_IAudioClient2* pThis)                                                   { return pThis->lpVtbl->Release(pThis); }
13379 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); }
13380 static MA_INLINE HRESULT ma_IAudioClient2_GetBufferSize(ma_IAudioClient2* pThis, ma_uint32* pNumBufferFrames)                { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
13381 static MA_INLINE HRESULT ma_IAudioClient2_GetStreamLatency(ma_IAudioClient2* pThis, MA_REFERENCE_TIME* pLatency)             { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
13382 static MA_INLINE HRESULT ma_IAudioClient2_GetCurrentPadding(ma_IAudioClient2* pThis, ma_uint32* pNumPaddingFrames)           { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
13383 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); }
13384 static MA_INLINE HRESULT ma_IAudioClient2_GetMixFormat(ma_IAudioClient2* pThis, WAVEFORMATEX** ppDeviceFormat)               { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
13385 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); }
13386 static MA_INLINE HRESULT ma_IAudioClient2_Start(ma_IAudioClient2* pThis)                                                     { return pThis->lpVtbl->Start(pThis); }
13387 static MA_INLINE HRESULT ma_IAudioClient2_Stop(ma_IAudioClient2* pThis)                                                      { return pThis->lpVtbl->Stop(pThis); }
13388 static MA_INLINE HRESULT ma_IAudioClient2_Reset(ma_IAudioClient2* pThis)                                                     { return pThis->lpVtbl->Reset(pThis); }
13389 static MA_INLINE HRESULT ma_IAudioClient2_SetEventHandle(ma_IAudioClient2* pThis, HANDLE eventHandle)                        { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
13390 static MA_INLINE HRESULT ma_IAudioClient2_GetService(ma_IAudioClient2* pThis, const IID* const riid, void** pp)              { return pThis->lpVtbl->GetService(pThis, riid, pp); }
13391 static MA_INLINE HRESULT ma_IAudioClient2_IsOffloadCapable(ma_IAudioClient2* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); }
13392 static MA_INLINE HRESULT ma_IAudioClient2_SetClientProperties(ma_IAudioClient2* pThis, const ma_AudioClientProperties* pProperties)           { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); }
13393 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); }
13394
13395
13396 /* IAudioClient3 */
13397 typedef struct
13398 {
13399     /* IUnknown */
13400     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject);
13401     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioClient3* pThis);
13402     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioClient3* pThis);
13403
13404     /* IAudioClient */
13405     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);
13406     HRESULT (STDMETHODCALLTYPE * GetBufferSize)    (ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames);
13407     HRESULT (STDMETHODCALLTYPE * GetStreamLatency) (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency);
13408     HRESULT (STDMETHODCALLTYPE * GetCurrentPadding)(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames);
13409     HRESULT (STDMETHODCALLTYPE * IsFormatSupported)(ma_IAudioClient3* pThis, MA_AUDCLNT_SHAREMODE shareMode, const WAVEFORMATEX* pFormat, WAVEFORMATEX** ppClosestMatch);
13410     HRESULT (STDMETHODCALLTYPE * GetMixFormat)     (ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat);
13411     HRESULT (STDMETHODCALLTYPE * GetDevicePeriod)  (ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pDefaultDevicePeriod, MA_REFERENCE_TIME* pMinimumDevicePeriod);
13412     HRESULT (STDMETHODCALLTYPE * Start)            (ma_IAudioClient3* pThis);
13413     HRESULT (STDMETHODCALLTYPE * Stop)             (ma_IAudioClient3* pThis);
13414     HRESULT (STDMETHODCALLTYPE * Reset)            (ma_IAudioClient3* pThis);
13415     HRESULT (STDMETHODCALLTYPE * SetEventHandle)   (ma_IAudioClient3* pThis, HANDLE eventHandle);
13416     HRESULT (STDMETHODCALLTYPE * GetService)       (ma_IAudioClient3* pThis, const IID* const riid, void** pp);
13417
13418     /* IAudioClient2 */
13419     HRESULT (STDMETHODCALLTYPE * IsOffloadCapable)   (ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable);
13420     HRESULT (STDMETHODCALLTYPE * SetClientProperties)(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties);
13421     HRESULT (STDMETHODCALLTYPE * GetBufferSizeLimits)(ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, BOOL eventDriven, MA_REFERENCE_TIME* pMinBufferDuration, MA_REFERENCE_TIME* pMaxBufferDuration);
13422
13423     /* IAudioClient3 */
13424     HRESULT (STDMETHODCALLTYPE * GetSharedModeEnginePeriod)       (ma_IAudioClient3* pThis, const WAVEFORMATEX* pFormat, ma_uint32* pDefaultPeriodInFrames, ma_uint32* pFundamentalPeriodInFrames, ma_uint32* pMinPeriodInFrames, ma_uint32* pMaxPeriodInFrames);
13425     HRESULT (STDMETHODCALLTYPE * GetCurrentSharedModeEnginePeriod)(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames);
13426     HRESULT (STDMETHODCALLTYPE * InitializeSharedAudioStream)     (ma_IAudioClient3* pThis, DWORD streamFlags, ma_uint32 periodInFrames, const WAVEFORMATEX* pFormat, const GUID* pAudioSessionGuid);
13427 } ma_IAudioClient3Vtbl;
13428 struct ma_IAudioClient3
13429 {
13430     ma_IAudioClient3Vtbl* lpVtbl;
13431 };
13432 static MA_INLINE HRESULT ma_IAudioClient3_QueryInterface(ma_IAudioClient3* pThis, const IID* const riid, void** ppObject)    { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13433 static MA_INLINE ULONG   ma_IAudioClient3_AddRef(ma_IAudioClient3* pThis)                                                    { return pThis->lpVtbl->AddRef(pThis); }
13434 static MA_INLINE ULONG   ma_IAudioClient3_Release(ma_IAudioClient3* pThis)                                                   { return pThis->lpVtbl->Release(pThis); }
13435 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); }
13436 static MA_INLINE HRESULT ma_IAudioClient3_GetBufferSize(ma_IAudioClient3* pThis, ma_uint32* pNumBufferFrames)                { return pThis->lpVtbl->GetBufferSize(pThis, pNumBufferFrames); }
13437 static MA_INLINE HRESULT ma_IAudioClient3_GetStreamLatency(ma_IAudioClient3* pThis, MA_REFERENCE_TIME* pLatency)             { return pThis->lpVtbl->GetStreamLatency(pThis, pLatency); }
13438 static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentPadding(ma_IAudioClient3* pThis, ma_uint32* pNumPaddingFrames)           { return pThis->lpVtbl->GetCurrentPadding(pThis, pNumPaddingFrames); }
13439 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); }
13440 static MA_INLINE HRESULT ma_IAudioClient3_GetMixFormat(ma_IAudioClient3* pThis, WAVEFORMATEX** ppDeviceFormat)               { return pThis->lpVtbl->GetMixFormat(pThis, ppDeviceFormat); }
13441 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); }
13442 static MA_INLINE HRESULT ma_IAudioClient3_Start(ma_IAudioClient3* pThis)                                                     { return pThis->lpVtbl->Start(pThis); }
13443 static MA_INLINE HRESULT ma_IAudioClient3_Stop(ma_IAudioClient3* pThis)                                                      { return pThis->lpVtbl->Stop(pThis); }
13444 static MA_INLINE HRESULT ma_IAudioClient3_Reset(ma_IAudioClient3* pThis)                                                     { return pThis->lpVtbl->Reset(pThis); }
13445 static MA_INLINE HRESULT ma_IAudioClient3_SetEventHandle(ma_IAudioClient3* pThis, HANDLE eventHandle)                        { return pThis->lpVtbl->SetEventHandle(pThis, eventHandle); }
13446 static MA_INLINE HRESULT ma_IAudioClient3_GetService(ma_IAudioClient3* pThis, const IID* const riid, void** pp)              { return pThis->lpVtbl->GetService(pThis, riid, pp); }
13447 static MA_INLINE HRESULT ma_IAudioClient3_IsOffloadCapable(ma_IAudioClient3* pThis, MA_AUDIO_STREAM_CATEGORY category, BOOL* pOffloadCapable) { return pThis->lpVtbl->IsOffloadCapable(pThis, category, pOffloadCapable); }
13448 static MA_INLINE HRESULT ma_IAudioClient3_SetClientProperties(ma_IAudioClient3* pThis, const ma_AudioClientProperties* pProperties)           { return pThis->lpVtbl->SetClientProperties(pThis, pProperties); }
13449 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); }
13450 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); }
13451 static MA_INLINE HRESULT ma_IAudioClient3_GetCurrentSharedModeEnginePeriod(ma_IAudioClient3* pThis, WAVEFORMATEX** ppFormat, ma_uint32* pCurrentPeriodInFrames) { return pThis->lpVtbl->GetCurrentSharedModeEnginePeriod(pThis, ppFormat, pCurrentPeriodInFrames); }
13452 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); }
13453
13454
13455 /* IAudioRenderClient */
13456 typedef struct
13457 {
13458     /* IUnknown */
13459     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject);
13460     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioRenderClient* pThis);
13461     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioRenderClient* pThis);
13462
13463     /* IAudioRenderClient */
13464     HRESULT (STDMETHODCALLTYPE * GetBuffer)    (ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData);
13465     HRESULT (STDMETHODCALLTYPE * ReleaseBuffer)(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags);
13466 } ma_IAudioRenderClientVtbl;
13467 struct ma_IAudioRenderClient
13468 {
13469     ma_IAudioRenderClientVtbl* lpVtbl;
13470 };
13471 static MA_INLINE HRESULT ma_IAudioRenderClient_QueryInterface(ma_IAudioRenderClient* pThis, const IID* const riid, void** ppObject)   { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13472 static MA_INLINE ULONG   ma_IAudioRenderClient_AddRef(ma_IAudioRenderClient* pThis)                                                   { return pThis->lpVtbl->AddRef(pThis); }
13473 static MA_INLINE ULONG   ma_IAudioRenderClient_Release(ma_IAudioRenderClient* pThis)                                                  { return pThis->lpVtbl->Release(pThis); }
13474 static MA_INLINE HRESULT ma_IAudioRenderClient_GetBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesRequested, BYTE** ppData)   { return pThis->lpVtbl->GetBuffer(pThis, numFramesRequested, ppData); }
13475 static MA_INLINE HRESULT ma_IAudioRenderClient_ReleaseBuffer(ma_IAudioRenderClient* pThis, ma_uint32 numFramesWritten, DWORD dwFlags) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesWritten, dwFlags); }
13476
13477
13478 /* IAudioCaptureClient */
13479 typedef struct
13480 {
13481     /* IUnknown */
13482     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject);
13483     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IAudioCaptureClient* pThis);
13484     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IAudioCaptureClient* pThis);
13485
13486     /* IAudioRenderClient */
13487     HRESULT (STDMETHODCALLTYPE * GetBuffer)        (ma_IAudioCaptureClient* pThis, BYTE** ppData, ma_uint32* pNumFramesToRead, DWORD* pFlags, ma_uint64* pDevicePosition, ma_uint64* pQPCPosition);
13488     HRESULT (STDMETHODCALLTYPE * ReleaseBuffer)    (ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead);
13489     HRESULT (STDMETHODCALLTYPE * GetNextPacketSize)(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket);
13490 } ma_IAudioCaptureClientVtbl;
13491 struct ma_IAudioCaptureClient
13492 {
13493     ma_IAudioCaptureClientVtbl* lpVtbl;
13494 };
13495 static MA_INLINE HRESULT ma_IAudioCaptureClient_QueryInterface(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
13496 static MA_INLINE ULONG   ma_IAudioCaptureClient_AddRef(ma_IAudioCaptureClient* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
13497 static MA_INLINE ULONG   ma_IAudioCaptureClient_Release(ma_IAudioCaptureClient* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
13498 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); }
13499 static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead)                 { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); }
13500 static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket)   { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); }
13501
13502 #ifndef MA_WIN32_DESKTOP
13503 #include <mmdeviceapi.h>
13504 typedef struct ma_completion_handler_uwp ma_completion_handler_uwp;
13505
13506 typedef struct
13507 {
13508     /* IUnknown */
13509     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject);
13510     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_completion_handler_uwp* pThis);
13511     ULONG   (STDMETHODCALLTYPE * Release)       (ma_completion_handler_uwp* pThis);
13512
13513     /* IActivateAudioInterfaceCompletionHandler */
13514     HRESULT (STDMETHODCALLTYPE * ActivateCompleted)(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation);
13515 } ma_completion_handler_uwp_vtbl;
13516 struct ma_completion_handler_uwp
13517 {
13518     ma_completion_handler_uwp_vtbl* lpVtbl;
13519     MA_ATOMIC ma_uint32 counter;
13520     HANDLE hEvent;
13521 };
13522
13523 static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_QueryInterface(ma_completion_handler_uwp* pThis, const IID* const riid, void** ppObject)
13524 {
13525     /*
13526     We need to "implement" IAgileObject which is just an indicator that's used internally by WASAPI for some multithreading management. To
13527     "implement" this, we just make sure we return pThis when the IAgileObject is requested.
13528     */
13529     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)) {
13530         *ppObject = NULL;
13531         return E_NOINTERFACE;
13532     }
13533
13534     /* Getting here means the IID is IUnknown or IMMNotificationClient. */
13535     *ppObject = (void*)pThis;
13536     ((ma_completion_handler_uwp_vtbl*)pThis->lpVtbl)->AddRef(pThis);
13537     return S_OK;
13538 }
13539
13540 static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_AddRef(ma_completion_handler_uwp* pThis)
13541 {
13542     return (ULONG)c89atomic_fetch_add_32(&pThis->counter, 1) + 1;
13543 }
13544
13545 static ULONG STDMETHODCALLTYPE ma_completion_handler_uwp_Release(ma_completion_handler_uwp* pThis)
13546 {
13547     ma_uint32 newRefCount = c89atomic_fetch_sub_32(&pThis->counter, 1) - 1;
13548     if (newRefCount == 0) {
13549         return 0;   /* We don't free anything here because we never allocate the object on the heap. */
13550     }
13551
13552     return (ULONG)newRefCount;
13553 }
13554
13555 static HRESULT STDMETHODCALLTYPE ma_completion_handler_uwp_ActivateCompleted(ma_completion_handler_uwp* pThis, ma_IActivateAudioInterfaceAsyncOperation* pActivateOperation)
13556 {
13557     (void)pActivateOperation;
13558     SetEvent(pThis->hEvent);
13559     return S_OK;
13560 }
13561
13562
13563 static ma_completion_handler_uwp_vtbl g_maCompletionHandlerVtblInstance = {
13564     ma_completion_handler_uwp_QueryInterface,
13565     ma_completion_handler_uwp_AddRef,
13566     ma_completion_handler_uwp_Release,
13567     ma_completion_handler_uwp_ActivateCompleted
13568 };
13569
13570 static ma_result ma_completion_handler_uwp_init(ma_completion_handler_uwp* pHandler)
13571 {
13572     MA_ASSERT(pHandler != NULL);
13573     MA_ZERO_OBJECT(pHandler);
13574
13575     pHandler->lpVtbl = &g_maCompletionHandlerVtblInstance;
13576     pHandler->counter = 1;
13577     pHandler->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
13578     if (pHandler->hEvent == NULL) {
13579         return ma_result_from_GetLastError(GetLastError());
13580     }
13581
13582     return MA_SUCCESS;
13583 }
13584
13585 static void ma_completion_handler_uwp_uninit(ma_completion_handler_uwp* pHandler)
13586 {
13587     if (pHandler->hEvent != NULL) {
13588         CloseHandle(pHandler->hEvent);
13589     }
13590 }
13591
13592 static void ma_completion_handler_uwp_wait(ma_completion_handler_uwp* pHandler)
13593 {
13594     WaitForSingleObject(pHandler->hEvent, INFINITE);
13595 }
13596 #endif  /* !MA_WIN32_DESKTOP */
13597
13598 /* We need a virtual table for our notification client object that's used for detecting changes to the default device. */
13599 #ifdef MA_WIN32_DESKTOP
13600 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_QueryInterface(ma_IMMNotificationClient* pThis, const IID* const riid, void** ppObject)
13601 {
13602     /*
13603     We care about two interfaces - IUnknown and IMMNotificationClient. If the requested IID is something else
13604     we just return E_NOINTERFACE. Otherwise we need to increment the reference counter and return S_OK.
13605     */
13606     if (!ma_is_guid_equal(riid, &MA_IID_IUnknown) && !ma_is_guid_equal(riid, &MA_IID_IMMNotificationClient)) {
13607         *ppObject = NULL;
13608         return E_NOINTERFACE;
13609     }
13610
13611     /* Getting here means the IID is IUnknown or IMMNotificationClient. */
13612     *ppObject = (void*)pThis;
13613     ((ma_IMMNotificationClientVtbl*)pThis->lpVtbl)->AddRef(pThis);
13614     return S_OK;
13615 }
13616
13617 static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_AddRef(ma_IMMNotificationClient* pThis)
13618 {
13619     return (ULONG)c89atomic_fetch_add_32(&pThis->counter, 1) + 1;
13620 }
13621
13622 static ULONG STDMETHODCALLTYPE ma_IMMNotificationClient_Release(ma_IMMNotificationClient* pThis)
13623 {
13624     ma_uint32 newRefCount = c89atomic_fetch_sub_32(&pThis->counter, 1) - 1;
13625     if (newRefCount == 0) {
13626         return 0;   /* We don't free anything here because we never allocate the object on the heap. */
13627     }
13628
13629     return (ULONG)newRefCount;
13630 }
13631
13632 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceStateChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, DWORD dwNewState)
13633 {
13634     ma_bool32 isThisDevice = MA_FALSE;
13635     ma_bool32 isCapture    = MA_FALSE;
13636     ma_bool32 isPlayback   = MA_FALSE;
13637     
13638
13639 #ifdef MA_DEBUG_OUTPUT
13640     printf("IMMNotificationClient_OnDeviceStateChanged(pDeviceID=%S, dwNewState=%u)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)", (unsigned int)dwNewState);
13641 #endif
13642
13643     /*
13644     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
13645     that the device is disabled or has been unplugged.
13646     */
13647     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)) {
13648         isCapture = MA_TRUE;
13649         if (wcscmp(pThis->pDevice->capture.id.wasapi, pDeviceID) == 0) {
13650             isThisDevice = MA_TRUE;
13651         }
13652     }
13653
13654     if (pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting && (pThis->pDevice->type == ma_device_type_playback || pThis->pDevice->type == ma_device_type_duplex)) {
13655         isPlayback = MA_TRUE;
13656         if (wcscmp(pThis->pDevice->playback.id.wasapi, pDeviceID) == 0) {
13657             isThisDevice = MA_TRUE;
13658         }
13659     }
13660
13661
13662     /*
13663     If the device ID matches our device we need to mark our device as detached and stop it. When a
13664     device is added in OnDeviceAdded(), we'll restart it. We only mark it as detached if the device
13665     was started at the time of being removed.
13666     */
13667     if (isThisDevice) {
13668         if ((dwNewState & MA_MM_DEVICE_STATE_ACTIVE) == 0) {
13669             /*
13670             Unplugged or otherwise unavailable. Mark as detached if we were in a playing state. We'll
13671             use this to determine whether or not we need to automatically start the device when it's
13672             plugged back in again.
13673             */
13674             if (ma_device_get_state(pThis->pDevice) == MA_STATE_STARTED) {
13675                 if (isPlayback) {
13676                     pThis->pDevice->wasapi.isDetachedPlayback = MA_TRUE;
13677                 }
13678                 if (isCapture) {
13679                     pThis->pDevice->wasapi.isDetachedCapture = MA_TRUE;
13680                 }
13681
13682                 ma_device_stop(pThis->pDevice);
13683             }
13684         }
13685
13686         if ((dwNewState & MA_MM_DEVICE_STATE_ACTIVE) != 0) {
13687             /* The device was activated. If we were detached, we need to start it again. */
13688             ma_bool8 tryRestartingDevice = MA_FALSE;
13689
13690             if (isPlayback) {
13691                 if (pThis->pDevice->wasapi.isDetachedPlayback) {
13692                     pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE;
13693                     ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback);
13694                     tryRestartingDevice = MA_TRUE;
13695                 }
13696             }
13697
13698             if (isCapture) {
13699                 if (pThis->pDevice->wasapi.isDetachedCapture) {
13700                     pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE;
13701                     ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture);
13702                     tryRestartingDevice = MA_TRUE;
13703                 }
13704             }
13705
13706             if (tryRestartingDevice) {
13707                 if (pThis->pDevice->wasapi.isDetachedPlayback == MA_FALSE && pThis->pDevice->wasapi.isDetachedCapture == MA_FALSE) {
13708                     ma_device_start(pThis->pDevice);
13709                 }
13710             }
13711         }
13712     }
13713
13714     return S_OK;
13715 }
13716
13717 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceAdded(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
13718 {
13719 #ifdef MA_DEBUG_OUTPUT
13720     /*printf("IMMNotificationClient_OnDeviceAdded(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
13721 #endif
13722
13723     /* We don't need to worry about this event for our purposes. */
13724     (void)pThis;
13725     (void)pDeviceID;
13726     return S_OK;
13727 }
13728
13729 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDeviceRemoved(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID)
13730 {
13731 #ifdef MA_DEBUG_OUTPUT
13732     printf("IMMNotificationClient_OnDeviceRemoved(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");
13733 #endif
13734
13735     /* We don't need to worry about this event for our purposes. */
13736     (void)pThis;
13737     (void)pDeviceID;
13738     return S_OK;
13739 }
13740
13741 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnDefaultDeviceChanged(ma_IMMNotificationClient* pThis, ma_EDataFlow dataFlow, ma_ERole role, LPCWSTR pDefaultDeviceID)
13742 {
13743 #ifdef MA_DEBUG_OUTPUT
13744     printf("IMMNotificationClient_OnDefaultDeviceChanged(dataFlow=%d, role=%d, pDefaultDeviceID=%S)\n", dataFlow, role, (pDefaultDeviceID != NULL) ? pDefaultDeviceID : L"(NULL)");
13745 #endif
13746
13747     /* We only ever use the eConsole role in miniaudio. */
13748     if (role != ma_eConsole) {
13749     #ifdef MA_DEBUG_OUTPUT
13750         printf("[WASAPI] Stream rerouting: role != eConsole\n");
13751     #endif
13752         return S_OK;
13753     }
13754
13755     /* We only care about devices with the same data flow and role as the current device. */
13756     if ((pThis->pDevice->type == ma_device_type_playback && dataFlow != ma_eRender) ||
13757         (pThis->pDevice->type == ma_device_type_capture  && dataFlow != ma_eCapture)) {
13758     #ifdef MA_DEBUG_OUTPUT
13759         printf("[WASAPI] Stream rerouting abandoned because dataFlow does match device type.\n");
13760     #endif
13761         return S_OK;
13762     }
13763
13764     /* Don't do automatic stream routing if we're not allowed. */
13765     if ((dataFlow == ma_eRender  && pThis->pDevice->wasapi.allowPlaybackAutoStreamRouting == MA_FALSE) ||
13766         (dataFlow == ma_eCapture && pThis->pDevice->wasapi.allowCaptureAutoStreamRouting  == MA_FALSE)) {
13767     #ifdef MA_DEBUG_OUTPUT
13768         printf("[WASAPI] Stream rerouting abandoned because automatic stream routing has been disabled by the device config.\n");
13769     #endif
13770         return S_OK;
13771     }
13772
13773     /*
13774     Not currently supporting automatic stream routing in exclusive mode. This is not working correctly on my machine due to
13775     AUDCLNT_E_DEVICE_IN_USE errors when reinitializing the device. If this is a bug in miniaudio, we can try re-enabling this once
13776     it's fixed.
13777     */
13778     if ((dataFlow == ma_eRender  && pThis->pDevice->playback.shareMode == ma_share_mode_exclusive) ||
13779         (dataFlow == ma_eCapture && pThis->pDevice->capture.shareMode  == ma_share_mode_exclusive)) {
13780     #ifdef MA_DEBUG_OUTPUT
13781         printf("[WASAPI] Stream rerouting abandoned because the device shared mode is exclusive.\n");
13782     #endif
13783         return S_OK;
13784     }
13785
13786
13787
13788
13789     /*
13790     Second attempt at device rerouting. We're going to retrieve the device's state at the time of
13791     the route change. We're then going to stop the device, reinitialize the device, and then start
13792     it again if the state before stopping was MA_STATE_STARTED.
13793     */
13794     {
13795         ma_uint32 previousState = ma_device_get_state(pThis->pDevice);
13796         ma_bool8 restartDevice = MA_FALSE;
13797
13798         if (previousState == MA_STATE_STARTED) {
13799             ma_device_stop(pThis->pDevice);
13800             restartDevice = MA_TRUE;
13801         }
13802
13803         if (pDefaultDeviceID != NULL) { /* <-- The input device ID will be null if there's no other device available. */
13804             if (dataFlow == ma_eRender) {
13805                 ma_device_reroute__wasapi(pThis->pDevice, ma_device_type_playback);
13806
13807                 if (pThis->pDevice->wasapi.isDetachedPlayback) {
13808                     pThis->pDevice->wasapi.isDetachedPlayback = MA_FALSE;
13809                     
13810                     if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedCapture) {
13811                         restartDevice = MA_FALSE;   /* It's a duplex device and the capture side is detached. We cannot be restarting the device just yet. */
13812                     } else {
13813                         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. */
13814                     }
13815                 }
13816             } else {
13817                 ma_device_reroute__wasapi(pThis->pDevice, (pThis->pDevice->type == ma_device_type_loopback) ? ma_device_type_loopback : ma_device_type_capture);
13818
13819                 if (pThis->pDevice->wasapi.isDetachedCapture) {
13820                     pThis->pDevice->wasapi.isDetachedCapture = MA_FALSE;
13821                     
13822                     if (pThis->pDevice->type == ma_device_type_duplex && pThis->pDevice->wasapi.isDetachedPlayback) {
13823                         restartDevice = MA_FALSE;   /* It's a duplex device and the playback side is detached. We cannot be restarting the device just yet. */
13824                     } else {
13825                         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. */
13826                     }
13827                 }
13828             }
13829
13830             if (restartDevice) {
13831                 ma_device_start(pThis->pDevice);
13832             }
13833         }
13834     }
13835
13836     return S_OK;
13837 }
13838
13839 static HRESULT STDMETHODCALLTYPE ma_IMMNotificationClient_OnPropertyValueChanged(ma_IMMNotificationClient* pThis, LPCWSTR pDeviceID, const PROPERTYKEY key)
13840 {
13841 #ifdef MA_DEBUG_OUTPUT
13842     /*printf("IMMNotificationClient_OnPropertyValueChanged(pDeviceID=%S)\n", (pDeviceID != NULL) ? pDeviceID : L"(NULL)");*/
13843 #endif
13844
13845     (void)pThis;
13846     (void)pDeviceID;
13847     (void)key;
13848     return S_OK;
13849 }
13850
13851 static ma_IMMNotificationClientVtbl g_maNotificationCientVtbl = {
13852     ma_IMMNotificationClient_QueryInterface,
13853     ma_IMMNotificationClient_AddRef,
13854     ma_IMMNotificationClient_Release,
13855     ma_IMMNotificationClient_OnDeviceStateChanged,
13856     ma_IMMNotificationClient_OnDeviceAdded,
13857     ma_IMMNotificationClient_OnDeviceRemoved,
13858     ma_IMMNotificationClient_OnDefaultDeviceChanged,
13859     ma_IMMNotificationClient_OnPropertyValueChanged
13860 };
13861 #endif  /* MA_WIN32_DESKTOP */
13862
13863 #ifdef MA_WIN32_DESKTOP
13864 typedef ma_IMMDevice ma_WASAPIDeviceInterface;
13865 #else
13866 typedef ma_IUnknown ma_WASAPIDeviceInterface;
13867 #endif
13868
13869
13870 #define MA_CONTEXT_COMMAND_QUIT__WASAPI                 1
13871 #define MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI  2
13872 #define MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI 3
13873
13874 static ma_context_command__wasapi ma_context_init_command__wasapi(int code)
13875 {
13876     ma_context_command__wasapi cmd;
13877     
13878     MA_ZERO_OBJECT(&cmd);
13879     cmd.code = code;
13880
13881     return cmd;
13882 }
13883
13884 static ma_result ma_context_post_command__wasapi(ma_context* pContext, const ma_context_command__wasapi* pCmd)
13885 {
13886     /* For now we are doing everything synchronously, but I might relax this later if the need arises. */
13887     ma_result result;
13888     ma_bool32 isUsingLocalEvent = MA_FALSE;
13889     ma_event localEvent;
13890
13891     MA_ASSERT(pContext != NULL);
13892     MA_ASSERT(pCmd     != NULL);
13893
13894     if (pCmd->pEvent == NULL) {
13895         isUsingLocalEvent = MA_TRUE;
13896
13897         result = ma_event_init(&localEvent);
13898         if (result != MA_SUCCESS) {
13899             return result;  /* Failed to create the event for this command. */
13900         }
13901     }
13902
13903     /* Here is where we add the command to the list. If there's not enough room we'll spin until there is. */
13904     ma_mutex_lock(&pContext->wasapi.commandLock);
13905     {
13906         ma_uint32 index;
13907
13908         /* Spin until we've got some space available. */
13909         while (pContext->wasapi.commandCount == ma_countof(pContext->wasapi.commands)) {
13910             ma_yield();
13911         }
13912
13913         /* Space is now available. Can safely add to the list. */
13914         index = (pContext->wasapi.commandIndex + pContext->wasapi.commandCount) % ma_countof(pContext->wasapi.commands);
13915         pContext->wasapi.commands[index]        = *pCmd;
13916         pContext->wasapi.commands[index].pEvent = &localEvent;
13917         pContext->wasapi.commandCount += 1;
13918
13919         /* Now that the command has been added, release the semaphore so ma_context_next_command__wasapi() can return. */
13920         ma_semaphore_release(&pContext->wasapi.commandSem);
13921     }
13922     ma_mutex_unlock(&pContext->wasapi.commandLock);    
13923
13924     if (isUsingLocalEvent) {
13925         ma_event_wait(&localEvent);
13926         ma_event_uninit(&localEvent);
13927     }
13928
13929     return MA_SUCCESS;
13930 }
13931
13932 static ma_result ma_context_next_command__wasapi(ma_context* pContext, ma_context_command__wasapi* pCmd)
13933 {
13934     ma_result result = MA_SUCCESS;
13935
13936     MA_ASSERT(pContext != NULL);
13937     MA_ASSERT(pCmd     != NULL);
13938
13939     result = ma_semaphore_wait(&pContext->wasapi.commandSem);
13940     if (result == MA_SUCCESS) {
13941         ma_mutex_lock(&pContext->wasapi.commandLock);
13942         {
13943             *pCmd = pContext->wasapi.commands[pContext->wasapi.commandIndex];
13944             pContext->wasapi.commandIndex  = (pContext->wasapi.commandIndex + 1) % ma_countof(pContext->wasapi.commands);
13945             pContext->wasapi.commandCount -= 1;
13946         }
13947         ma_mutex_unlock(&pContext->wasapi.commandLock);
13948     }    
13949
13950     return result;
13951 }
13952
13953 static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pUserData)
13954 {
13955     ma_result result;
13956     ma_context* pContext = (ma_context*)pUserData;
13957     MA_ASSERT(pContext != NULL);
13958
13959     for (;;) {
13960         ma_context_command__wasapi cmd;
13961         result = ma_context_next_command__wasapi(pContext, &cmd);
13962         if (result != MA_SUCCESS) {
13963             break;
13964         }
13965
13966         switch (cmd.code)
13967         {
13968             case MA_CONTEXT_COMMAND_QUIT__WASAPI:
13969             {
13970                 /* Do nothing. Handled after the switch. */
13971             } break;
13972
13973             case MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI:
13974             {
13975                 if (cmd.data.createAudioClient.deviceType == ma_device_type_playback) {
13976                     result = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioRenderClient, cmd.data.createAudioClient.ppAudioClientService));
13977                 } else {
13978                     result = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioCaptureClient, cmd.data.createAudioClient.ppAudioClientService));
13979                 }
13980             } break;
13981
13982             case MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI:
13983             {
13984                 if (cmd.data.releaseAudioClient.deviceType == ma_device_type_playback) { 
13985                     if (cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback != NULL) {
13986                         ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback);
13987                         cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientPlayback = NULL;
13988                     }
13989                 }
13990
13991                 if (cmd.data.releaseAudioClient.deviceType == ma_device_type_capture) {
13992                     if (cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture != NULL) {
13993                         ma_IAudioClient_Release((ma_IAudioClient*)cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture);
13994                         cmd.data.releaseAudioClient.pDevice->wasapi.pAudioClientCapture = NULL;
13995                     }
13996                 }
13997             } break;
13998
13999             default:
14000             {
14001                 /* Unknown command. Ignore it, but trigger an assert in debug mode so we're aware of it. */
14002                 MA_ASSERT(MA_FALSE);
14003             } break;
14004         }
14005
14006         if (cmd.pEvent != NULL) {
14007             ma_event_signal(cmd.pEvent);
14008         }
14009
14010         if (cmd.code == MA_CONTEXT_COMMAND_QUIT__WASAPI) {
14011             break;  /* Received a quit message. Get out of here. */
14012         }
14013     }
14014
14015     return (ma_thread_result)0;
14016 }
14017
14018 static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService)
14019 {
14020     ma_result result;
14021     ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI);
14022     cmd.data.createAudioClient.deviceType           = deviceType;
14023     cmd.data.createAudioClient.pAudioClient         = (void*)pAudioClient;
14024     cmd.data.createAudioClient.ppAudioClientService = ppAudioClientService;
14025     cmd.data.createAudioClient.result               = MA_SUCCESS;
14026     
14027     result = ma_context_post_command__wasapi(pContext, &cmd);  /* This will not return until the command has actually been run. */
14028     if (result != MA_SUCCESS) {
14029         return result;
14030     }
14031
14032     return cmd.data.createAudioClient.result;
14033 }
14034
14035 #if 0   /* Not used at the moment, but leaving here for future use. */
14036 static ma_result ma_device_release_IAudioClient_service__wasapi(ma_device* pDevice, ma_device_type deviceType)
14037 {
14038     ma_result result;
14039     ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI);
14040     cmd.data.releaseAudioClient.pDevice    = pDevice;
14041     cmd.data.releaseAudioClient.deviceType = deviceType;
14042
14043     result = ma_context_post_command__wasapi(pDevice->pContext, &cmd);  /* This will not return until the command has actually been run. */
14044     if (result != MA_SUCCESS) {
14045         return result;
14046     }
14047
14048     return MA_SUCCESS;
14049 }
14050 #endif
14051
14052
14053 static void ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const WAVEFORMATEX* pWF, ma_share_mode shareMode, ma_device_info* pInfo)
14054 {
14055     MA_ASSERT(pWF != NULL);
14056     MA_ASSERT(pInfo != NULL);
14057
14058     if (pInfo->nativeDataFormatCount >= ma_countof(pInfo->nativeDataFormats)) {
14059         return; /* Too many data formats. Need to ignore this one. Don't think this should ever happen with WASAPI. */
14060     }
14061
14062     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].format     = ma_format_from_WAVEFORMATEX(pWF);
14063     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].channels   = pWF->nChannels;
14064     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].sampleRate = pWF->nSamplesPerSec;
14065     pInfo->nativeDataFormats[pInfo->nativeDataFormatCount].flags      = (shareMode == ma_share_mode_exclusive) ? MA_DATA_FORMAT_FLAG_EXCLUSIVE_MODE : 0;
14066     pInfo->nativeDataFormatCount += 1;
14067 }
14068
14069 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)
14070 {
14071     HRESULT hr;
14072     WAVEFORMATEX* pWF = NULL;
14073
14074     MA_ASSERT(pAudioClient != NULL);
14075     MA_ASSERT(pInfo != NULL);
14076
14077     /* Shared Mode. We use GetMixFormat() here. */
14078     hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pAudioClient, (WAVEFORMATEX**)&pWF);
14079     if (SUCCEEDED(hr)) {
14080         ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_shared, pInfo);
14081     } else {
14082         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve mix format for device info retrieval.", ma_result_from_HRESULT(hr));
14083     }
14084
14085     /*
14086     Exlcusive Mode. We repeatedly call IsFormatSupported() here. This is not currently supported on
14087     UWP. Failure to retrieve the exclusive mode format is not considered an error, so from here on
14088     out, MA_SUCCESS is guaranteed to be returned.
14089     */
14090     #ifdef MA_WIN32_DESKTOP
14091     {
14092         ma_IPropertyStore *pProperties;
14093
14094         /*
14095         The first thing to do is get the format from PKEY_AudioEngine_DeviceFormat. This should give us a channel count we assume is
14096         correct which will simplify our searching.
14097         */
14098         hr = ma_IMMDevice_OpenPropertyStore((ma_IMMDevice*)pMMDevice, STGM_READ, &pProperties);
14099         if (SUCCEEDED(hr)) {
14100             PROPVARIANT var;
14101             ma_PropVariantInit(&var);
14102
14103             hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_AudioEngine_DeviceFormat, &var);
14104             if (SUCCEEDED(hr)) {
14105                 pWF = (WAVEFORMATEX*)var.blob.pBlobData;
14106
14107                 /*
14108                 In my testing, the format returned by PKEY_AudioEngine_DeviceFormat is suitable for exclusive mode so we check this format
14109                 first. If this fails, fall back to a search.
14110                 */
14111                 hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pWF, NULL);
14112                 if (SUCCEEDED(hr)) {
14113                     /* The format returned by PKEY_AudioEngine_DeviceFormat is supported. */
14114                     ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(pWF, ma_share_mode_exclusive, pInfo);
14115                 } else {
14116                     /*
14117                     The format returned by PKEY_AudioEngine_DeviceFormat is not supported, so fall back to a search. We assume the channel
14118                     count returned by MA_PKEY_AudioEngine_DeviceFormat is valid and correct. For simplicity we're only returning one format.
14119                     */
14120                     ma_uint32 channels = pInfo->minChannels;
14121                     ma_channel defaultChannelMap[MA_MAX_CHANNELS];
14122                     WAVEFORMATEXTENSIBLE wf;
14123                     ma_bool32 found;
14124                     ma_uint32 iFormat;
14125
14126                     /* Make sure we don't overflow the channel map. */
14127                     if (channels > MA_MAX_CHANNELS) {
14128                         channels = MA_MAX_CHANNELS;
14129                     }
14130
14131                     ma_get_standard_channel_map(ma_standard_channel_map_microsoft, channels, defaultChannelMap);
14132
14133                     MA_ZERO_OBJECT(&wf);
14134                     wf.Format.cbSize     = sizeof(wf);
14135                     wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
14136                     wf.Format.nChannels  = (WORD)channels;
14137                     wf.dwChannelMask     = ma_channel_map_to_channel_mask__win32(defaultChannelMap, channels);
14138
14139                     found = MA_FALSE;
14140                     for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); ++iFormat) {
14141                         ma_format format = g_maFormatPriorities[iFormat];
14142                         ma_uint32 iSampleRate;
14143
14144                         wf.Format.wBitsPerSample       = (WORD)(ma_get_bytes_per_sample(format)*8);
14145                         wf.Format.nBlockAlign          = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8);
14146                         wf.Format.nAvgBytesPerSec      = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
14147                         wf.Samples.wValidBitsPerSample = /*(format == ma_format_s24_32) ? 24 :*/ wf.Format.wBitsPerSample;
14148                         if (format == ma_format_f32) {
14149                             wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
14150                         } else {
14151                             wf.SubFormat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
14152                         }
14153
14154                         for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iSampleRate) {
14155                             wf.Format.nSamplesPerSec = g_maStandardSampleRatePriorities[iSampleRate];
14156
14157                             hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, (WAVEFORMATEX*)&wf, NULL);
14158                             if (SUCCEEDED(hr)) {
14159                                 ma_add_native_data_format_to_device_info_from_WAVEFORMATEX((WAVEFORMATEX*)&wf, ma_share_mode_exclusive, pInfo);
14160                                 found = MA_TRUE;
14161                                 break;
14162                             }
14163                         }
14164
14165                         if (found) {
14166                             break;
14167                         }
14168                     }
14169
14170                     ma_PropVariantClear(pContext, &var);
14171
14172                     if (!found) {
14173                         ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to find suitable device format for device info retrieval.", MA_FORMAT_NOT_SUPPORTED);
14174                     }
14175                 }
14176             } else {
14177                 ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to retrieve device format for device info retrieval.", ma_result_from_HRESULT(hr));
14178             }
14179
14180             ma_IPropertyStore_Release(pProperties);
14181         } else {
14182             ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "[WASAPI] Failed to open property store for device info retrieval.", ma_result_from_HRESULT(hr));
14183         }
14184     }
14185     #endif
14186
14187     return MA_SUCCESS;
14188 }
14189
14190 #ifdef MA_WIN32_DESKTOP
14191 static ma_EDataFlow ma_device_type_to_EDataFlow(ma_device_type deviceType)
14192 {
14193     if (deviceType == ma_device_type_playback) {
14194         return ma_eRender;
14195     } else if (deviceType == ma_device_type_capture) {
14196         return ma_eCapture;
14197     } else {
14198         MA_ASSERT(MA_FALSE);
14199         return ma_eRender; /* Should never hit this. */
14200     }
14201 }
14202
14203 static ma_result ma_context_create_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator** ppDeviceEnumerator)
14204 {
14205     HRESULT hr;
14206     ma_IMMDeviceEnumerator* pDeviceEnumerator;
14207
14208     MA_ASSERT(pContext           != NULL);
14209     MA_ASSERT(ppDeviceEnumerator != NULL);
14210
14211     *ppDeviceEnumerator = NULL; /* Safety. */
14212
14213     hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
14214     if (FAILED(hr)) {
14215         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr));
14216     }
14217
14218     *ppDeviceEnumerator = pDeviceEnumerator;
14219
14220     return MA_SUCCESS;
14221 }
14222
14223 static LPWSTR ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(ma_context* pContext, ma_IMMDeviceEnumerator* pDeviceEnumerator, ma_device_type deviceType)
14224 {
14225     HRESULT hr;
14226     ma_IMMDevice* pMMDefaultDevice = NULL;
14227     LPWSTR pDefaultDeviceID = NULL;
14228     ma_EDataFlow dataFlow;
14229     ma_ERole role;
14230
14231     MA_ASSERT(pContext          != NULL);
14232     MA_ASSERT(pDeviceEnumerator != NULL);
14233
14234     (void)pContext;
14235
14236     /* Grab the EDataFlow type from the device type. */
14237     dataFlow = ma_device_type_to_EDataFlow(deviceType);
14238
14239     /* The role is always eConsole, but we may make this configurable later. */
14240     role = ma_eConsole;
14241
14242     hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, dataFlow, role, &pMMDefaultDevice);
14243     if (FAILED(hr)) {
14244         return NULL;
14245     }
14246
14247     hr = ma_IMMDevice_GetId(pMMDefaultDevice, &pDefaultDeviceID);
14248
14249     ma_IMMDevice_Release(pMMDefaultDevice);
14250     pMMDefaultDevice = NULL;
14251
14252     if (FAILED(hr)) {
14253         return NULL;
14254     }
14255
14256     return pDefaultDeviceID;
14257 }
14258
14259 static LPWSTR ma_context_get_default_device_id__wasapi(ma_context* pContext, ma_device_type deviceType)    /* Free the returned pointer with ma_CoTaskMemFree() */
14260 {
14261     ma_result result;
14262     ma_IMMDeviceEnumerator* pDeviceEnumerator;
14263     LPWSTR pDefaultDeviceID = NULL;
14264
14265     MA_ASSERT(pContext != NULL);
14266
14267     result = ma_context_create_IMMDeviceEnumerator__wasapi(pContext, &pDeviceEnumerator);
14268     if (result != MA_SUCCESS) {
14269         return NULL;
14270     }
14271
14272     pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType);
14273
14274     ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
14275     return pDefaultDeviceID;
14276 }
14277
14278 static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_IMMDevice** ppMMDevice)
14279 {
14280     ma_IMMDeviceEnumerator* pDeviceEnumerator;
14281     HRESULT hr;
14282
14283     MA_ASSERT(pContext != NULL);
14284     MA_ASSERT(ppMMDevice != NULL);
14285
14286     hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
14287     if (FAILED(hr)) {
14288         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.", ma_result_from_HRESULT(hr));
14289     }
14290
14291     if (pDeviceID == NULL) {
14292         hr = ma_IMMDeviceEnumerator_GetDefaultAudioEndpoint(pDeviceEnumerator, (deviceType == ma_device_type_capture) ? ma_eCapture : ma_eRender, ma_eConsole, ppMMDevice);
14293     } else {
14294         hr = ma_IMMDeviceEnumerator_GetDevice(pDeviceEnumerator, pDeviceID->wasapi, ppMMDevice);
14295     }
14296
14297     ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
14298     if (FAILED(hr)) {
14299         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve IMMDevice.", ma_result_from_HRESULT(hr));
14300     }
14301
14302     return MA_SUCCESS;
14303 }
14304
14305 static ma_result ma_context_get_device_id_from_MMDevice__wasapi(ma_context* pContext, ma_IMMDevice* pMMDevice, ma_device_id* pDeviceID)
14306 {
14307     LPWSTR pDeviceIDString;
14308     HRESULT hr;
14309
14310     MA_ASSERT(pDeviceID != NULL);
14311
14312     hr = ma_IMMDevice_GetId(pMMDevice, &pDeviceIDString);
14313     if (SUCCEEDED(hr)) {
14314         size_t idlen = wcslen(pDeviceIDString);
14315         if (idlen+1 > ma_countof(pDeviceID->wasapi)) {
14316             ma_CoTaskMemFree(pContext, pDeviceIDString);
14317             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. */
14318             return MA_ERROR;
14319         }
14320
14321         MA_COPY_MEMORY(pDeviceID->wasapi, pDeviceIDString, idlen * sizeof(wchar_t));
14322         pDeviceID->wasapi[idlen] = '\0';
14323
14324         ma_CoTaskMemFree(pContext, pDeviceIDString);
14325
14326         return MA_SUCCESS;
14327     }
14328
14329     return MA_ERROR;
14330 }
14331
14332 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)
14333 {
14334     ma_result result;
14335     HRESULT hr;
14336
14337     MA_ASSERT(pContext != NULL);
14338     MA_ASSERT(pMMDevice != NULL);
14339     MA_ASSERT(pInfo != NULL);
14340
14341     /* ID. */
14342     result = ma_context_get_device_id_from_MMDevice__wasapi(pContext, pMMDevice, &pInfo->id);
14343     if (result == MA_SUCCESS) {
14344         if (pDefaultDeviceID != NULL) {
14345             if (wcscmp(pInfo->id.wasapi, pDefaultDeviceID) == 0) {
14346                 pInfo->isDefault = MA_TRUE;
14347             }
14348         }
14349     }
14350
14351     /* Description / Friendly Name */
14352     {
14353         ma_IPropertyStore *pProperties;
14354         hr = ma_IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pProperties);
14355         if (SUCCEEDED(hr)) {
14356             PROPVARIANT var;
14357
14358             ma_PropVariantInit(&var);
14359             hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &var);
14360             if (SUCCEEDED(hr)) {
14361                 WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, pInfo->name, sizeof(pInfo->name), 0, FALSE);
14362                 ma_PropVariantClear(pContext, &var);
14363             }
14364
14365             ma_IPropertyStore_Release(pProperties);
14366         }
14367     }
14368
14369     /* Format */
14370     if (!onlySimpleInfo) {
14371         ma_IAudioClient* pAudioClient;
14372         hr = ma_IMMDevice_Activate(pMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
14373         if (SUCCEEDED(hr)) {
14374             result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, pMMDevice, pAudioClient, pInfo);
14375
14376             ma_IAudioClient_Release(pAudioClient);
14377             return result;
14378         } else {
14379             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate audio client for device info retrieval.", ma_result_from_HRESULT(hr));
14380         }
14381     }
14382
14383     return MA_SUCCESS;
14384 }
14385
14386 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)
14387 {
14388     ma_result result = MA_SUCCESS;
14389     UINT deviceCount;
14390     HRESULT hr;
14391     ma_uint32 iDevice;
14392     LPWSTR pDefaultDeviceID = NULL;
14393     ma_IMMDeviceCollection* pDeviceCollection = NULL;
14394
14395     MA_ASSERT(pContext != NULL);
14396     MA_ASSERT(callback != NULL);
14397
14398     /* Grab the default device. We use this to know whether or not flag the returned device info as being the default. */
14399     pDefaultDeviceID = ma_context_get_default_device_id_from_IMMDeviceEnumerator__wasapi(pContext, pDeviceEnumerator, deviceType);
14400
14401     /* We need to enumerate the devices which returns a device collection. */
14402     hr = ma_IMMDeviceEnumerator_EnumAudioEndpoints(pDeviceEnumerator, ma_device_type_to_EDataFlow(deviceType), MA_MM_DEVICE_STATE_ACTIVE, &pDeviceCollection);
14403     if (SUCCEEDED(hr)) {
14404         hr = ma_IMMDeviceCollection_GetCount(pDeviceCollection, &deviceCount);
14405         if (FAILED(hr)) {
14406             result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to get device count.", ma_result_from_HRESULT(hr));
14407             goto done;
14408         }
14409
14410         for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
14411             ma_device_info deviceInfo;
14412             ma_IMMDevice* pMMDevice;
14413
14414             MA_ZERO_OBJECT(&deviceInfo);
14415
14416             hr = ma_IMMDeviceCollection_Item(pDeviceCollection, iDevice, &pMMDevice);
14417             if (SUCCEEDED(hr)) {
14418                 result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_TRUE, &deviceInfo);   /* MA_TRUE = onlySimpleInfo. */
14419
14420                 ma_IMMDevice_Release(pMMDevice);
14421                 if (result == MA_SUCCESS) {
14422                     ma_bool32 cbResult = callback(pContext, deviceType, &deviceInfo, pUserData);
14423                     if (cbResult == MA_FALSE) {
14424                         break;
14425                     }
14426                 }
14427             }
14428         }
14429     }
14430
14431 done:
14432     if (pDefaultDeviceID != NULL) {
14433         ma_CoTaskMemFree(pContext, pDefaultDeviceID);
14434         pDefaultDeviceID = NULL;
14435     }
14436
14437     if (pDeviceCollection != NULL) {
14438         ma_IMMDeviceCollection_Release(pDeviceCollection);
14439         pDeviceCollection = NULL;
14440     }
14441
14442     return result;
14443 }
14444
14445 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)
14446 {
14447     ma_result result;
14448     HRESULT hr;
14449
14450     MA_ASSERT(pContext != NULL);
14451     MA_ASSERT(ppAudioClient != NULL);
14452     MA_ASSERT(ppMMDevice != NULL);
14453
14454     result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, ppMMDevice);
14455     if (result != MA_SUCCESS) {
14456         return result;
14457     }
14458
14459     hr = ma_IMMDevice_Activate(*ppMMDevice, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)ppAudioClient);
14460     if (FAILED(hr)) {
14461         return ma_result_from_HRESULT(hr);
14462     }
14463
14464     return MA_SUCCESS;
14465 }
14466 #else
14467 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)
14468 {
14469     ma_IActivateAudioInterfaceAsyncOperation *pAsyncOp = NULL;
14470     ma_completion_handler_uwp completionHandler;
14471     IID iid;
14472     LPOLESTR iidStr;
14473     HRESULT hr;
14474     ma_result result;
14475     HRESULT activateResult;
14476     ma_IUnknown* pActivatedInterface;
14477
14478     MA_ASSERT(pContext != NULL);
14479     MA_ASSERT(ppAudioClient != NULL);
14480
14481     if (pDeviceID != NULL) {
14482         MA_COPY_MEMORY(&iid, pDeviceID->wasapi, sizeof(iid));
14483     } else {
14484         if (deviceType == ma_device_type_playback) {
14485             iid = MA_IID_DEVINTERFACE_AUDIO_RENDER;
14486         } else {
14487             iid = MA_IID_DEVINTERFACE_AUDIO_CAPTURE;
14488         }
14489     }
14490
14491 #if defined(__cplusplus)
14492     hr = StringFromIID(iid, &iidStr);
14493 #else
14494     hr = StringFromIID(&iid, &iidStr);
14495 #endif
14496     if (FAILED(hr)) {
14497         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to convert device IID to string for ActivateAudioInterfaceAsync(). Out of memory.", ma_result_from_HRESULT(hr));
14498     }
14499
14500     result = ma_completion_handler_uwp_init(&completionHandler);
14501     if (result != MA_SUCCESS) {
14502         ma_CoTaskMemFree(pContext, iidStr);
14503         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for waiting for ActivateAudioInterfaceAsync().", result);
14504     }
14505
14506 #if defined(__cplusplus)
14507     hr = ActivateAudioInterfaceAsync(iidStr, MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
14508 #else
14509     hr = ActivateAudioInterfaceAsync(iidStr, &MA_IID_IAudioClient, NULL, (IActivateAudioInterfaceCompletionHandler*)&completionHandler, (IActivateAudioInterfaceAsyncOperation**)&pAsyncOp);
14510 #endif
14511     if (FAILED(hr)) {
14512         ma_completion_handler_uwp_uninit(&completionHandler);
14513         ma_CoTaskMemFree(pContext, iidStr);
14514         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] ActivateAudioInterfaceAsync() failed.", ma_result_from_HRESULT(hr));
14515     }
14516
14517     ma_CoTaskMemFree(pContext, iidStr);
14518
14519     /* Wait for the async operation for finish. */
14520     ma_completion_handler_uwp_wait(&completionHandler);
14521     ma_completion_handler_uwp_uninit(&completionHandler);
14522
14523     hr = ma_IActivateAudioInterfaceAsyncOperation_GetActivateResult(pAsyncOp, &activateResult, &pActivatedInterface);
14524     ma_IActivateAudioInterfaceAsyncOperation_Release(pAsyncOp);
14525
14526     if (FAILED(hr) || FAILED(activateResult)) {
14527         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to activate device.", FAILED(hr) ? ma_result_from_HRESULT(hr) : ma_result_from_HRESULT(activateResult));
14528     }
14529
14530     /* Here is where we grab the IAudioClient interface. */
14531     hr = ma_IUnknown_QueryInterface(pActivatedInterface, &MA_IID_IAudioClient, (void**)ppAudioClient);
14532     if (FAILED(hr)) {
14533         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to query IAudioClient interface.", ma_result_from_HRESULT(hr));
14534     }
14535
14536     if (ppActivatedInterface) {
14537         *ppActivatedInterface = pActivatedInterface;
14538     } else {
14539         ma_IUnknown_Release(pActivatedInterface);
14540     }
14541
14542     return MA_SUCCESS;
14543 }
14544 #endif
14545
14546 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)
14547 {
14548 #ifdef MA_WIN32_DESKTOP
14549     return ma_context_get_IAudioClient_Desktop__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
14550 #else
14551     return ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, ppAudioClient, ppDeviceInterface);
14552 #endif
14553 }
14554
14555
14556 static ma_result ma_context_enumerate_devices__wasapi(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
14557 {
14558     /* Different enumeration for desktop and UWP. */
14559 #ifdef MA_WIN32_DESKTOP
14560     /* Desktop */
14561     HRESULT hr;
14562     ma_IMMDeviceEnumerator* pDeviceEnumerator;
14563
14564     hr = ma_CoCreateInstance(pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
14565     if (FAILED(hr)) {
14566         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr));
14567     }
14568
14569     ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_playback, callback, pUserData);
14570     ma_context_enumerate_devices_by_type__wasapi(pContext, pDeviceEnumerator, ma_device_type_capture,  callback, pUserData);
14571
14572     ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
14573 #else
14574     /*
14575     UWP
14576
14577     The MMDevice API is only supported on desktop applications. For now, while I'm still figuring out how to properly enumerate
14578     over devices without using MMDevice, I'm restricting devices to defaults.
14579
14580     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/
14581     */
14582     if (callback) {
14583         ma_bool32 cbResult = MA_TRUE;
14584
14585         /* Playback. */
14586         if (cbResult) {
14587             ma_device_info deviceInfo;
14588             MA_ZERO_OBJECT(&deviceInfo);
14589             ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
14590             deviceInfo.isDefault = MA_TRUE;
14591             cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
14592         }
14593
14594         /* Capture. */
14595         if (cbResult) {
14596             ma_device_info deviceInfo;
14597             MA_ZERO_OBJECT(&deviceInfo);
14598             ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
14599             deviceInfo.isDefault = MA_TRUE;
14600             cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
14601         }
14602     }
14603 #endif
14604
14605     return MA_SUCCESS;
14606 }
14607
14608 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)
14609 {
14610 #ifdef MA_WIN32_DESKTOP
14611     ma_result result;
14612     ma_IMMDevice* pMMDevice = NULL;
14613     LPWSTR pDefaultDeviceID = NULL;
14614
14615     result = ma_context_get_MMDevice__wasapi(pContext, deviceType, pDeviceID, &pMMDevice);
14616     if (result != MA_SUCCESS) {
14617         return result;
14618     }
14619
14620     /* We need the default device ID so we can set the isDefault flag in the device info. */
14621     pDefaultDeviceID = ma_context_get_default_device_id__wasapi(pContext, deviceType);
14622
14623     result = ma_context_get_device_info_from_MMDevice__wasapi(pContext, pMMDevice, pDefaultDeviceID, MA_FALSE, pDeviceInfo);   /* MA_FALSE = !onlySimpleInfo. */
14624
14625     if (pDefaultDeviceID != NULL) {
14626         ma_CoTaskMemFree(pContext, pDefaultDeviceID);
14627         pDefaultDeviceID = NULL;
14628     }
14629
14630     ma_IMMDevice_Release(pMMDevice);
14631
14632     return result;
14633 #else
14634     ma_IAudioClient* pAudioClient;
14635     ma_result result;
14636
14637     /* UWP currently only uses default devices. */
14638     if (deviceType == ma_device_type_playback) {
14639         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
14640     } else {
14641         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
14642     }
14643
14644     result = ma_context_get_IAudioClient_UWP__wasapi(pContext, deviceType, pDeviceID, &pAudioClient, NULL);
14645     if (result != MA_SUCCESS) {
14646         return result;
14647     }
14648
14649     result = ma_context_get_device_info_from_IAudioClient__wasapi(pContext, NULL, pAudioClient, pDeviceInfo);
14650
14651     pDeviceInfo->isDefault = MA_TRUE;  /* UWP only supports default devices. */
14652
14653     ma_IAudioClient_Release(pAudioClient);
14654     return result;
14655 #endif
14656 }
14657
14658 static ma_result ma_device_uninit__wasapi(ma_device* pDevice)
14659 {
14660     MA_ASSERT(pDevice != NULL);
14661
14662 #ifdef MA_WIN32_DESKTOP
14663     if (pDevice->wasapi.pDeviceEnumerator) {
14664         ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient);
14665         ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator);
14666     }
14667 #endif
14668
14669     if (pDevice->wasapi.pRenderClient) {
14670         ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
14671     }
14672     if (pDevice->wasapi.pCaptureClient) {
14673         ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
14674     }
14675
14676     if (pDevice->wasapi.pAudioClientPlayback) {
14677         ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
14678     }
14679     if (pDevice->wasapi.pAudioClientCapture) {
14680         ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
14681     }
14682
14683     if (pDevice->wasapi.hEventPlayback) {
14684         CloseHandle(pDevice->wasapi.hEventPlayback);
14685     }
14686     if (pDevice->wasapi.hEventCapture) {
14687         CloseHandle(pDevice->wasapi.hEventCapture);
14688     }
14689
14690     return MA_SUCCESS;
14691 }
14692
14693
14694 typedef struct
14695 {
14696     /* Input. */
14697     ma_format formatIn;
14698     ma_uint32 channelsIn;
14699     ma_uint32 sampleRateIn;
14700     ma_channel channelMapIn[MA_MAX_CHANNELS];
14701     ma_uint32 periodSizeInFramesIn;
14702     ma_uint32 periodSizeInMillisecondsIn;
14703     ma_uint32 periodsIn;
14704     ma_share_mode shareMode;
14705     ma_performance_profile performanceProfile;
14706     ma_bool32 noAutoConvertSRC;
14707     ma_bool32 noDefaultQualitySRC;
14708     ma_bool32 noHardwareOffloading;
14709
14710     /* Output. */
14711     ma_IAudioClient* pAudioClient;
14712     ma_IAudioRenderClient* pRenderClient;
14713     ma_IAudioCaptureClient* pCaptureClient;
14714     ma_format formatOut;
14715     ma_uint32 channelsOut;
14716     ma_uint32 sampleRateOut;
14717     ma_channel channelMapOut[MA_MAX_CHANNELS];
14718     ma_uint32 periodSizeInFramesOut;
14719     ma_uint32 periodsOut;
14720     ma_bool32 usingAudioClient3;
14721     char deviceName[256];
14722     ma_device_id id;
14723 } ma_device_init_internal_data__wasapi;
14724
14725 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)
14726 {
14727     HRESULT hr;
14728     ma_result result = MA_SUCCESS;
14729     const char* errorMsg = "";
14730     MA_AUDCLNT_SHAREMODE shareMode = MA_AUDCLNT_SHAREMODE_SHARED;
14731     DWORD streamFlags = 0;
14732     MA_REFERENCE_TIME periodDurationInMicroseconds;
14733     ma_bool32 wasInitializedUsingIAudioClient3 = MA_FALSE;
14734     WAVEFORMATEXTENSIBLE wf;
14735     ma_WASAPIDeviceInterface* pDeviceInterface = NULL;
14736     ma_IAudioClient2* pAudioClient2;
14737     ma_uint32 nativeSampleRate;
14738
14739     MA_ASSERT(pContext != NULL);
14740     MA_ASSERT(pData != NULL);
14741
14742     /* This function is only used to initialize one device type: either playback, capture or loopback. Never full-duplex. */
14743     if (deviceType == ma_device_type_duplex) {
14744         return MA_INVALID_ARGS;
14745     }
14746
14747     pData->pAudioClient = NULL;
14748     pData->pRenderClient = NULL;
14749     pData->pCaptureClient = NULL;
14750
14751     streamFlags = MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
14752     if (!pData->noAutoConvertSRC && pData->sampleRateIn != 0 && pData->shareMode != ma_share_mode_exclusive) {    /* <-- Exclusive streams must use the native sample rate. */
14753         streamFlags |= MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM;
14754     }
14755     if (!pData->noDefaultQualitySRC && pData->sampleRateIn != 0 && (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) != 0) {
14756         streamFlags |= MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
14757     }
14758     if (deviceType == ma_device_type_loopback) {
14759         streamFlags |= MA_AUDCLNT_STREAMFLAGS_LOOPBACK;
14760     }
14761
14762     result = ma_context_get_IAudioClient__wasapi(pContext, deviceType, pDeviceID, &pData->pAudioClient, &pDeviceInterface);
14763     if (result != MA_SUCCESS) {
14764         goto done;
14765     }
14766
14767     MA_ZERO_OBJECT(&wf);
14768
14769     /* Try enabling hardware offloading. */
14770     if (!pData->noHardwareOffloading) {
14771         hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient2, (void**)&pAudioClient2);
14772         if (SUCCEEDED(hr)) {
14773             BOOL isHardwareOffloadingSupported = 0;
14774             hr = ma_IAudioClient2_IsOffloadCapable(pAudioClient2, MA_AudioCategory_Other, &isHardwareOffloadingSupported);
14775             if (SUCCEEDED(hr) && isHardwareOffloadingSupported) {
14776                 ma_AudioClientProperties clientProperties;
14777                 MA_ZERO_OBJECT(&clientProperties);
14778                 clientProperties.cbSize = sizeof(clientProperties);
14779                 clientProperties.bIsOffload = 1;
14780                 clientProperties.eCategory = MA_AudioCategory_Other;
14781                 ma_IAudioClient2_SetClientProperties(pAudioClient2, &clientProperties);
14782             }
14783
14784             pAudioClient2->lpVtbl->Release(pAudioClient2);
14785         }
14786     }
14787
14788     /* 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. */
14789     result = MA_FORMAT_NOT_SUPPORTED;
14790     if (pData->shareMode == ma_share_mode_exclusive) {
14791     #ifdef MA_WIN32_DESKTOP
14792         /* In exclusive mode on desktop we always use the backend's native format. */
14793         ma_IPropertyStore* pStore = NULL;
14794         hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pStore);
14795         if (SUCCEEDED(hr)) {
14796             PROPVARIANT prop;
14797             ma_PropVariantInit(&prop);
14798             hr = ma_IPropertyStore_GetValue(pStore, &MA_PKEY_AudioEngine_DeviceFormat, &prop);
14799             if (SUCCEEDED(hr)) {
14800                 WAVEFORMATEX* pActualFormat = (WAVEFORMATEX*)prop.blob.pBlobData;
14801                 hr = ma_IAudioClient_IsFormatSupported((ma_IAudioClient*)pData->pAudioClient, MA_AUDCLNT_SHAREMODE_EXCLUSIVE, pActualFormat, NULL);
14802                 if (SUCCEEDED(hr)) {
14803                     MA_COPY_MEMORY(&wf, pActualFormat, sizeof(WAVEFORMATEXTENSIBLE));
14804                 }
14805
14806                 ma_PropVariantClear(pContext, &prop);
14807             }
14808
14809             ma_IPropertyStore_Release(pStore);
14810         }
14811     #else
14812         /*
14813         I do not know how to query the device's native format on UWP so for now I'm just disabling support for
14814         exclusive mode. The alternative is to enumerate over different formats and check IsFormatSupported()
14815         until you find one that works.
14816
14817         TODO: Add support for exclusive mode to UWP.
14818         */
14819         hr = S_FALSE;
14820     #endif
14821
14822         if (hr == S_OK) {
14823             shareMode = MA_AUDCLNT_SHAREMODE_EXCLUSIVE;
14824             result = MA_SUCCESS;
14825         } else {
14826             result = MA_SHARE_MODE_NOT_SUPPORTED;
14827         }
14828     } else {
14829         /* In shared mode we are always using the format reported by the operating system. */
14830         WAVEFORMATEXTENSIBLE* pNativeFormat = NULL;
14831         hr = ma_IAudioClient_GetMixFormat((ma_IAudioClient*)pData->pAudioClient, (WAVEFORMATEX**)&pNativeFormat);
14832         if (hr != S_OK) {
14833             result = MA_FORMAT_NOT_SUPPORTED;
14834         } else {
14835             MA_COPY_MEMORY(&wf, pNativeFormat, sizeof(wf));
14836             result = MA_SUCCESS;
14837         }
14838
14839         ma_CoTaskMemFree(pContext, pNativeFormat);
14840
14841         shareMode = MA_AUDCLNT_SHAREMODE_SHARED;
14842     }
14843
14844     /* Return an error if we still haven't found a format. */
14845     if (result != MA_SUCCESS) {
14846         errorMsg = "[WASAPI] Failed to find best device mix format.";
14847         goto done;
14848     }
14849
14850     /*
14851     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
14852     WASAPI to perform the sample rate conversion.
14853     */
14854     nativeSampleRate = wf.Format.nSamplesPerSec;
14855     if (streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) {
14856         wf.Format.nSamplesPerSec = (pData->sampleRateIn != 0) ? pData->sampleRateIn : MA_DEFAULT_SAMPLE_RATE;
14857         wf.Format.nAvgBytesPerSec = wf.Format.nSamplesPerSec * wf.Format.nBlockAlign;
14858     }
14859
14860     pData->formatOut = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)&wf);
14861     if (pData->formatOut == ma_format_unknown) {
14862         /*
14863         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
14864         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
14865         completeness we'll check for it and return MA_FORMAT_NOT_SUPPORTED.
14866         */
14867         if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) {
14868             result = MA_SHARE_MODE_NOT_SUPPORTED;
14869         } else {
14870             result = MA_FORMAT_NOT_SUPPORTED;
14871         }
14872
14873         errorMsg = "[WASAPI] Native format not supported.";
14874         goto done;
14875     }
14876
14877     pData->channelsOut = wf.Format.nChannels;
14878     pData->sampleRateOut = wf.Format.nSamplesPerSec;
14879
14880     /* Get the internal channel map based on the channel mask. */
14881     ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pData->channelsOut, pData->channelMapOut);
14882
14883     /* Period size. */
14884     pData->periodsOut = (pData->periodsIn != 0) ? pData->periodsIn : MA_DEFAULT_PERIODS;
14885     pData->periodSizeInFramesOut = pData->periodSizeInFramesIn;
14886     if (pData->periodSizeInFramesOut == 0) {
14887         if (pData->periodSizeInMillisecondsIn == 0) {
14888             if (pData->performanceProfile == ma_performance_profile_low_latency) {
14889                 pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, wf.Format.nSamplesPerSec);
14890             } else {
14891                 pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, wf.Format.nSamplesPerSec);
14892             }
14893         } else {
14894             pData->periodSizeInFramesOut = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, wf.Format.nSamplesPerSec);
14895         }
14896     }
14897
14898     periodDurationInMicroseconds = ((ma_uint64)pData->periodSizeInFramesOut * 1000 * 1000) / wf.Format.nSamplesPerSec;
14899
14900
14901     /* Slightly different initialization for shared and exclusive modes. We try exclusive mode first, and if it fails, fall back to shared mode. */
14902     if (shareMode == MA_AUDCLNT_SHAREMODE_EXCLUSIVE) {
14903         MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * 10;
14904
14905         /*
14906         If the periodicy is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing
14907         it and trying it again.
14908         */
14909         hr = E_FAIL;
14910         for (;;) {
14911             hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL);
14912             if (hr == MA_AUDCLNT_E_INVALID_DEVICE_PERIOD) {
14913                 if (bufferDuration > 500*10000) {
14914                     break;
14915                 } else {
14916                     if (bufferDuration == 0) {  /* <-- Just a sanity check to prevent an infinit loop. Should never happen, but it makes me feel better. */
14917                         break;
14918                     }
14919
14920                     bufferDuration = bufferDuration * 2;
14921                     continue;
14922                 }
14923             } else {
14924                 break;
14925             }
14926         }
14927
14928         if (hr == MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
14929             ma_uint32 bufferSizeInFrames;
14930             hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames);
14931             if (SUCCEEDED(hr)) {
14932                 bufferDuration = (MA_REFERENCE_TIME)((10000.0 * 1000 / wf.Format.nSamplesPerSec * bufferSizeInFrames) + 0.5);
14933
14934                 /* Unfortunately we need to release and re-acquire the audio client according to MSDN. Seems silly - why not just call IAudioClient_Initialize() again?! */
14935                 ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
14936
14937             #ifdef MA_WIN32_DESKTOP
14938                 hr = ma_IMMDevice_Activate(pDeviceInterface, &MA_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pData->pAudioClient);
14939             #else
14940                 hr = ma_IUnknown_QueryInterface(pDeviceInterface, &MA_IID_IAudioClient, (void**)&pData->pAudioClient);
14941             #endif
14942
14943                 if (SUCCEEDED(hr)) {
14944                     hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, bufferDuration, (WAVEFORMATEX*)&wf, NULL);
14945                 }
14946             }
14947         }
14948
14949         if (FAILED(hr)) {
14950             /* 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. */
14951             if (hr == E_ACCESSDENIED) {
14952                 errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Access denied.", result = MA_ACCESS_DENIED;
14953             } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) {
14954                 errorMsg = "[WASAPI] Failed to initialize device in exclusive mode. Device in use.", result = MA_BUSY;
14955             } else {
14956                 errorMsg = "[WASAPI] Failed to initialize device in exclusive mode."; result = ma_result_from_HRESULT(hr);
14957             }
14958             goto done;
14959         }
14960     }
14961
14962     if (shareMode == MA_AUDCLNT_SHAREMODE_SHARED) {
14963         /*
14964         Low latency shared mode via IAudioClient3.
14965
14966         NOTE
14967         ====
14968         Contrary to the documentation on MSDN (https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nf-audioclient-iaudioclient3-initializesharedaudiostream), the
14969         use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM and AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY with IAudioClient3_InitializeSharedAudioStream() absolutely does not work. Using
14970         any of these flags will result in HRESULT code 0x88890021. The other problem is that calling IAudioClient3_GetSharedModeEnginePeriod() with a sample rate different to
14971         that returned by IAudioClient_GetMixFormat() also results in an error. I'm therefore disabling low-latency shared mode with AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM.
14972         */
14973 #ifndef MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE
14974         if ((streamFlags & MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM) == 0 || nativeSampleRate == wf.Format.nSamplesPerSec) {
14975             ma_IAudioClient3* pAudioClient3 = NULL;
14976             hr = ma_IAudioClient_QueryInterface(pData->pAudioClient, &MA_IID_IAudioClient3, (void**)&pAudioClient3);
14977             if (SUCCEEDED(hr)) {
14978                 ma_uint32 defaultPeriodInFrames;
14979                 ma_uint32 fundamentalPeriodInFrames;
14980                 ma_uint32 minPeriodInFrames;
14981                 ma_uint32 maxPeriodInFrames;
14982                 hr = ma_IAudioClient3_GetSharedModeEnginePeriod(pAudioClient3, (WAVEFORMATEX*)&wf, &defaultPeriodInFrames, &fundamentalPeriodInFrames, &minPeriodInFrames, &maxPeriodInFrames);
14983                 if (SUCCEEDED(hr)) {
14984                     ma_uint32 desiredPeriodInFrames = pData->periodSizeInFramesOut;
14985                     ma_uint32 actualPeriodInFrames  = desiredPeriodInFrames;
14986
14987                     /* Make sure the period size is a multiple of fundamentalPeriodInFrames. */
14988                     actualPeriodInFrames = actualPeriodInFrames / fundamentalPeriodInFrames;
14989                     actualPeriodInFrames = actualPeriodInFrames * fundamentalPeriodInFrames;
14990
14991                     /* The period needs to be clamped between minPeriodInFrames and maxPeriodInFrames. */
14992                     actualPeriodInFrames = ma_clamp(actualPeriodInFrames, minPeriodInFrames, maxPeriodInFrames);
14993
14994                 #if defined(MA_DEBUG_OUTPUT)
14995                     printf("[WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=%d)\n", actualPeriodInFrames);
14996                     printf("    defaultPeriodInFrames=%d\n", defaultPeriodInFrames);
14997                     printf("    fundamentalPeriodInFrames=%d\n", fundamentalPeriodInFrames);
14998                     printf("    minPeriodInFrames=%d\n", minPeriodInFrames);
14999                     printf("    maxPeriodInFrames=%d\n", maxPeriodInFrames);
15000                 #endif
15001
15002                     /* If the client requested a largish buffer than we don't actually want to use low latency shared mode because it forces small buffers. */
15003                     if (actualPeriodInFrames >= desiredPeriodInFrames) {
15004                         /*
15005                         MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY must not be in the stream flags. If either of these are specified,
15006                         IAudioClient3_InitializeSharedAudioStream() will fail.
15007                         */
15008                         hr = ma_IAudioClient3_InitializeSharedAudioStream(pAudioClient3, streamFlags & ~(MA_AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | MA_AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY), actualPeriodInFrames, (WAVEFORMATEX*)&wf, NULL);
15009                         if (SUCCEEDED(hr)) {
15010                             wasInitializedUsingIAudioClient3 = MA_TRUE;
15011                             pData->periodSizeInFramesOut = actualPeriodInFrames;
15012                         #if defined(MA_DEBUG_OUTPUT)
15013                             printf("[WASAPI] Using IAudioClient3\n");
15014                             printf("    periodSizeInFramesOut=%d\n", pData->periodSizeInFramesOut);
15015                         #endif
15016                         } else {
15017                         #if defined(MA_DEBUG_OUTPUT)
15018                             printf("[WASAPI] IAudioClient3_InitializeSharedAudioStream failed. Falling back to IAudioClient.\n");
15019                         #endif
15020                         }
15021                     } else {
15022                     #if defined(MA_DEBUG_OUTPUT)
15023                         printf("[WASAPI] Not using IAudioClient3 because the desired period size is larger than the maximum supported by IAudioClient3.\n");
15024                     #endif
15025                     }
15026                 } else {
15027                 #if defined(MA_DEBUG_OUTPUT)
15028                     printf("[WASAPI] IAudioClient3_GetSharedModeEnginePeriod failed. Falling back to IAudioClient.\n");
15029                 #endif
15030                 }
15031
15032                 ma_IAudioClient3_Release(pAudioClient3);
15033                 pAudioClient3 = NULL;
15034             }
15035         }
15036 #else
15037     #if defined(MA_DEBUG_OUTPUT)
15038         printf("[WASAPI] Not using IAudioClient3 because MA_WASAPI_NO_LOW_LATENCY_SHARED_MODE is enabled.\n");
15039     #endif
15040 #endif
15041
15042         /* If we don't have an IAudioClient3 then we need to use the normal initialization routine. */
15043         if (!wasInitializedUsingIAudioClient3) {
15044             MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * pData->periodsOut * 10;   /* <-- Multiply by 10 for microseconds to 100-nanoseconds. */
15045             hr = ma_IAudioClient_Initialize((ma_IAudioClient*)pData->pAudioClient, shareMode, streamFlags, bufferDuration, 0, (WAVEFORMATEX*)&wf, NULL);
15046             if (FAILED(hr)) {
15047                 if (hr == E_ACCESSDENIED) {
15048                     errorMsg = "[WASAPI] Failed to initialize device. Access denied.", result = MA_ACCESS_DENIED;
15049                 } else if (hr == MA_AUDCLNT_E_DEVICE_IN_USE) {
15050                     errorMsg = "[WASAPI] Failed to initialize device. Device in use.", result = MA_BUSY;
15051                 } else {
15052                     errorMsg = "[WASAPI] Failed to initialize device.", result = ma_result_from_HRESULT(hr);
15053                 }
15054
15055                 goto done;
15056             }
15057         }
15058     }
15059
15060     if (!wasInitializedUsingIAudioClient3) {
15061         ma_uint32 bufferSizeInFrames;
15062         hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames);
15063         if (FAILED(hr)) {
15064             errorMsg = "[WASAPI] Failed to get audio client's actual buffer size.", result = ma_result_from_HRESULT(hr);
15065             goto done;
15066         }
15067
15068         pData->periodSizeInFramesOut = bufferSizeInFrames / pData->periodsOut;
15069     }
15070
15071     pData->usingAudioClient3 = wasInitializedUsingIAudioClient3;
15072
15073     
15074     if (deviceType == ma_device_type_playback) {
15075         result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pRenderClient);
15076     } else {
15077         result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pCaptureClient);
15078     }
15079
15080     /*if (FAILED(hr)) {*/
15081     if (result != MA_SUCCESS) {
15082         errorMsg = "[WASAPI] Failed to get audio client service.";
15083         goto done;
15084     }
15085
15086
15087     /* Grab the name of the device. */
15088     #ifdef MA_WIN32_DESKTOP
15089     {
15090         ma_IPropertyStore *pProperties;
15091         hr = ma_IMMDevice_OpenPropertyStore(pDeviceInterface, STGM_READ, &pProperties);
15092         if (SUCCEEDED(hr)) {
15093             PROPVARIANT varName;
15094             ma_PropVariantInit(&varName);
15095             hr = ma_IPropertyStore_GetValue(pProperties, &MA_PKEY_Device_FriendlyName, &varName);
15096             if (SUCCEEDED(hr)) {
15097                 WideCharToMultiByte(CP_UTF8, 0, varName.pwszVal, -1, pData->deviceName, sizeof(pData->deviceName), 0, FALSE);
15098                 ma_PropVariantClear(pContext, &varName);
15099             }
15100
15101             ma_IPropertyStore_Release(pProperties);
15102         }
15103     }
15104     #endif
15105
15106     /*
15107     For the WASAPI backend we need to know the actual IDs of the device in order to do automatic
15108     stream routing so that IDs can be compared and we can determine which device has been detached
15109     and whether or not it matches with our ma_device.
15110     */
15111     #ifdef MA_WIN32_DESKTOP
15112     {
15113         /* Desktop */
15114         ma_context_get_device_id_from_MMDevice__wasapi(pContext, pDeviceInterface, &pData->id);
15115     }
15116     #else
15117     {
15118         /* UWP */
15119         /* TODO: Implement me. Need to figure out how to get the ID of the default device. */
15120     }
15121     #endif
15122
15123 done:
15124     /* Clean up. */
15125 #ifdef MA_WIN32_DESKTOP
15126     if (pDeviceInterface != NULL) {
15127         ma_IMMDevice_Release(pDeviceInterface);
15128     }
15129 #else
15130     if (pDeviceInterface != NULL) {
15131         ma_IUnknown_Release(pDeviceInterface);
15132     }
15133 #endif
15134
15135     if (result != MA_SUCCESS) {
15136         if (pData->pRenderClient) {
15137             ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pData->pRenderClient);
15138             pData->pRenderClient = NULL;
15139         }
15140         if (pData->pCaptureClient) {
15141             ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pData->pCaptureClient);
15142             pData->pCaptureClient = NULL;
15143         }
15144         if (pData->pAudioClient) {
15145             ma_IAudioClient_Release((ma_IAudioClient*)pData->pAudioClient);
15146             pData->pAudioClient = NULL;
15147         }
15148
15149         if (errorMsg != NULL && errorMsg[0] != '\0') {
15150             ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, errorMsg, result);
15151         }
15152
15153         return result;
15154     } else {
15155         return MA_SUCCESS;
15156     }
15157 }
15158
15159 static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type deviceType)
15160 {
15161     ma_device_init_internal_data__wasapi data;
15162     ma_result result;
15163
15164     MA_ASSERT(pDevice != NULL);
15165
15166     /* We only re-initialize the playback or capture device. Never a full-duplex device. */
15167     if (deviceType == ma_device_type_duplex) {
15168         return MA_INVALID_ARGS;
15169     }
15170
15171
15172     /*
15173     Before reinitializing the device we need to free the previous audio clients.
15174
15175     There's a known memory leak here. We will be calling this from the routing change callback that
15176     is fired by WASAPI. If we attempt to release the IAudioClient we will deadlock. In my opinion
15177     this is a bug. I'm not sure what I need to do to handle this cleanly, but I think we'll probably
15178     need some system where we post an event, but delay the execution of it until the callback has
15179     returned. I'm not sure how to do this reliably, however. I have set up some infrastructure for
15180     a command thread which might be useful for this.
15181     */
15182     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
15183         if (pDevice->wasapi.pCaptureClient) {
15184             ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
15185             pDevice->wasapi.pCaptureClient = NULL;
15186         }
15187
15188         if (pDevice->wasapi.pAudioClientCapture) {
15189             /*ma_device_release_IAudioClient_service__wasapi(pDevice, ma_device_type_capture);*/
15190             pDevice->wasapi.pAudioClientCapture = NULL;
15191         }
15192     }
15193
15194     if (deviceType == ma_device_type_playback) {
15195         if (pDevice->wasapi.pRenderClient) {
15196             ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
15197             pDevice->wasapi.pRenderClient = NULL;
15198         }
15199
15200         if (pDevice->wasapi.pAudioClientPlayback) {
15201             /*ma_device_release_IAudioClient_service__wasapi(pDevice, ma_device_type_playback);*/
15202             pDevice->wasapi.pAudioClientPlayback = NULL;
15203         }
15204     }
15205
15206
15207     if (deviceType == ma_device_type_playback) {
15208         data.formatIn               = pDevice->playback.format;
15209         data.channelsIn             = pDevice->playback.channels;
15210         MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
15211         data.shareMode              = pDevice->playback.shareMode;
15212     } else {
15213         data.formatIn               = pDevice->capture.format;
15214         data.channelsIn             = pDevice->capture.channels;
15215         MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
15216         data.shareMode              = pDevice->capture.shareMode;
15217     }
15218
15219     data.sampleRateIn               = pDevice->sampleRate;
15220     data.periodSizeInFramesIn       = pDevice->wasapi.originalPeriodSizeInFrames;
15221     data.periodSizeInMillisecondsIn = pDevice->wasapi.originalPeriodSizeInMilliseconds;
15222     data.periodsIn                  = pDevice->wasapi.originalPeriods;
15223     data.performanceProfile         = pDevice->wasapi.originalPerformanceProfile;
15224     data.noAutoConvertSRC           = pDevice->wasapi.noAutoConvertSRC;
15225     data.noDefaultQualitySRC        = pDevice->wasapi.noDefaultQualitySRC;
15226     data.noHardwareOffloading       = pDevice->wasapi.noHardwareOffloading;
15227     result = ma_device_init_internal__wasapi(pDevice->pContext, deviceType, NULL, &data);
15228     if (result != MA_SUCCESS) {
15229         return result;
15230     }
15231
15232     /* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */
15233     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
15234         pDevice->wasapi.pAudioClientCapture         = data.pAudioClient;
15235         pDevice->wasapi.pCaptureClient              = data.pCaptureClient;
15236
15237         pDevice->capture.internalFormat             = data.formatOut;
15238         pDevice->capture.internalChannels           = data.channelsOut;
15239         pDevice->capture.internalSampleRate         = data.sampleRateOut;
15240         MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
15241         pDevice->capture.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
15242         pDevice->capture.internalPeriods            = data.periodsOut;
15243         ma_strcpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), data.deviceName);
15244
15245         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture,  pDevice->wasapi.hEventCapture);
15246
15247         pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
15248         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
15249
15250         /* We must always have a valid ID. */
15251         ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi);
15252     }
15253
15254     if (deviceType == ma_device_type_playback) {
15255         pDevice->wasapi.pAudioClientPlayback         = data.pAudioClient;
15256         pDevice->wasapi.pRenderClient                = data.pRenderClient;
15257
15258         pDevice->playback.internalFormat             = data.formatOut;
15259         pDevice->playback.internalChannels           = data.channelsOut;
15260         pDevice->playback.internalSampleRate         = data.sampleRateOut;
15261         MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
15262         pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
15263         pDevice->playback.internalPeriods            = data.periodsOut;
15264         ma_strcpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), data.deviceName);
15265
15266         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
15267
15268         pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
15269         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
15270
15271         /* We must always have a valid ID. */
15272         ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi);
15273     }
15274
15275     return MA_SUCCESS;
15276 }
15277
15278 static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
15279 {
15280     ma_result result = MA_SUCCESS;
15281
15282 #ifdef MA_WIN32_DESKTOP
15283     HRESULT hr;
15284     ma_IMMDeviceEnumerator* pDeviceEnumerator;
15285 #endif
15286
15287     MA_ASSERT(pDevice != NULL);
15288
15289     MA_ZERO_OBJECT(&pDevice->wasapi);
15290     pDevice->wasapi.noAutoConvertSRC     = pConfig->wasapi.noAutoConvertSRC;
15291     pDevice->wasapi.noDefaultQualitySRC  = pConfig->wasapi.noDefaultQualitySRC;
15292     pDevice->wasapi.noHardwareOffloading = pConfig->wasapi.noHardwareOffloading;
15293
15294     /* Exclusive mode is not allowed with loopback. */
15295     if (pConfig->deviceType == ma_device_type_loopback && pConfig->playback.shareMode == ma_share_mode_exclusive) {
15296         return MA_INVALID_DEVICE_CONFIG;
15297     }
15298
15299     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
15300         ma_device_init_internal_data__wasapi data;
15301         data.formatIn                   = pDescriptorCapture->format;
15302         data.channelsIn                 = pDescriptorCapture->channels;
15303         data.sampleRateIn               = pDescriptorCapture->sampleRate;
15304         MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap));
15305         data.periodSizeInFramesIn       = pDescriptorCapture->periodSizeInFrames;
15306         data.periodSizeInMillisecondsIn = pDescriptorCapture->periodSizeInMilliseconds;
15307         data.periodsIn                  = pDescriptorCapture->periodCount;
15308         data.shareMode                  = pDescriptorCapture->shareMode;
15309         data.performanceProfile         = pConfig->performanceProfile;
15310         data.noAutoConvertSRC           = pConfig->wasapi.noAutoConvertSRC;
15311         data.noDefaultQualitySRC        = pConfig->wasapi.noDefaultQualitySRC;
15312         data.noHardwareOffloading       = pConfig->wasapi.noHardwareOffloading;
15313
15314         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);
15315         if (result != MA_SUCCESS) {
15316             return result;
15317         }
15318
15319         pDevice->wasapi.pAudioClientCapture              = data.pAudioClient;
15320         pDevice->wasapi.pCaptureClient                   = data.pCaptureClient;
15321         pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds;
15322         pDevice->wasapi.originalPeriodSizeInFrames       = pDescriptorCapture->periodSizeInFrames;
15323         pDevice->wasapi.originalPeriods                  = pDescriptorCapture->periodCount;
15324         pDevice->wasapi.originalPerformanceProfile       = pConfig->performanceProfile;
15325
15326         /*
15327         The event for capture needs to be manual reset for the same reason as playback. We keep the initial state set to unsignaled,
15328         however, because we want to block until we actually have something for the first call to ma_device_read().
15329         */
15330         pDevice->wasapi.hEventCapture = CreateEventW(NULL, FALSE, FALSE, NULL);  /* Auto reset, unsignaled by default. */
15331         if (pDevice->wasapi.hEventCapture == NULL) {
15332             result = ma_result_from_GetLastError(GetLastError());
15333
15334             if (pDevice->wasapi.pCaptureClient != NULL) {
15335                 ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
15336                 pDevice->wasapi.pCaptureClient = NULL;
15337             }
15338             if (pDevice->wasapi.pAudioClientCapture != NULL) {
15339                 ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
15340                 pDevice->wasapi.pAudioClientCapture = NULL;
15341             }
15342
15343             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for capture.", result);
15344         }
15345         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, pDevice->wasapi.hEventCapture);
15346
15347         pDevice->wasapi.periodSizeInFramesCapture = data.periodSizeInFramesOut;
15348         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &pDevice->wasapi.actualPeriodSizeInFramesCapture);
15349
15350         /* We must always have a valid ID. */
15351         ma_wcscpy_s(pDevice->capture.id.wasapi, sizeof(pDevice->capture.id.wasapi), data.id.wasapi);
15352
15353         /* The descriptor needs to be updated with actual values. */
15354         pDescriptorCapture->format             = data.formatOut;
15355         pDescriptorCapture->channels           = data.channelsOut;
15356         pDescriptorCapture->sampleRate         = data.sampleRateOut;
15357         MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
15358         pDescriptorCapture->periodSizeInFrames = data.periodSizeInFramesOut;
15359         pDescriptorCapture->periodCount        = data.periodsOut;
15360     }
15361
15362     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
15363         ma_device_init_internal_data__wasapi data;
15364         data.formatIn                   = pDescriptorPlayback->format;
15365         data.channelsIn                 = pDescriptorPlayback->channels;
15366         data.sampleRateIn               = pDescriptorPlayback->sampleRate;
15367         MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap));
15368         data.periodSizeInFramesIn       = pDescriptorPlayback->periodSizeInFrames;
15369         data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds;
15370         data.periodsIn                  = pDescriptorPlayback->periodCount;
15371         data.shareMode                  = pDescriptorPlayback->shareMode;
15372         data.performanceProfile         = pConfig->performanceProfile;
15373         data.noAutoConvertSRC           = pConfig->wasapi.noAutoConvertSRC;
15374         data.noDefaultQualitySRC        = pConfig->wasapi.noDefaultQualitySRC;
15375         data.noHardwareOffloading       = pConfig->wasapi.noHardwareOffloading;
15376
15377         result = ma_device_init_internal__wasapi(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data);
15378         if (result != MA_SUCCESS) {
15379             if (pConfig->deviceType == ma_device_type_duplex) {
15380                 if (pDevice->wasapi.pCaptureClient != NULL) {
15381                     ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
15382                     pDevice->wasapi.pCaptureClient = NULL;
15383                 }
15384                 if (pDevice->wasapi.pAudioClientCapture != NULL) {
15385                     ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
15386                     pDevice->wasapi.pAudioClientCapture = NULL;
15387                 }
15388
15389                 CloseHandle(pDevice->wasapi.hEventCapture);
15390                 pDevice->wasapi.hEventCapture = NULL;
15391             }
15392             return result;
15393         }
15394
15395         pDevice->wasapi.pAudioClientPlayback             = data.pAudioClient;
15396         pDevice->wasapi.pRenderClient                    = data.pRenderClient;
15397         pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds;
15398         pDevice->wasapi.originalPeriodSizeInFrames       = pDescriptorPlayback->periodSizeInFrames;
15399         pDevice->wasapi.originalPeriods                  = pDescriptorPlayback->periodCount;
15400         pDevice->wasapi.originalPerformanceProfile       = pConfig->performanceProfile;
15401
15402         /*
15403         The event for playback is needs to be manual reset because we want to explicitly control the fact that it becomes signalled
15404         only after the whole available space has been filled, never before.
15405
15406         The playback event also needs to be initially set to a signaled state so that the first call to ma_device_write() is able
15407         to get passed WaitForMultipleObjects().
15408         */
15409         pDevice->wasapi.hEventPlayback = CreateEventW(NULL, FALSE, TRUE, NULL);  /* Auto reset, signaled by default. */
15410         if (pDevice->wasapi.hEventPlayback == NULL) {
15411             result = ma_result_from_GetLastError(GetLastError());
15412
15413             if (pConfig->deviceType == ma_device_type_duplex) {
15414                 if (pDevice->wasapi.pCaptureClient != NULL) {
15415                     ma_IAudioCaptureClient_Release((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient);
15416                     pDevice->wasapi.pCaptureClient = NULL;
15417                 }
15418                 if (pDevice->wasapi.pAudioClientCapture != NULL) {
15419                     ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
15420                     pDevice->wasapi.pAudioClientCapture = NULL;
15421                 }
15422
15423                 CloseHandle(pDevice->wasapi.hEventCapture);
15424                 pDevice->wasapi.hEventCapture = NULL;
15425             }
15426
15427             if (pDevice->wasapi.pRenderClient != NULL) {
15428                 ma_IAudioRenderClient_Release((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient);
15429                 pDevice->wasapi.pRenderClient = NULL;
15430             }
15431             if (pDevice->wasapi.pAudioClientPlayback != NULL) {
15432                 ma_IAudioClient_Release((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
15433                 pDevice->wasapi.pAudioClientPlayback = NULL;
15434             }
15435
15436             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create event for playback.", result);
15437         }
15438         ma_IAudioClient_SetEventHandle((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, pDevice->wasapi.hEventPlayback);
15439
15440         pDevice->wasapi.periodSizeInFramesPlayback = data.periodSizeInFramesOut;
15441         ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &pDevice->wasapi.actualPeriodSizeInFramesPlayback);
15442
15443         /* We must always have a valid ID. */
15444         ma_wcscpy_s(pDevice->playback.id.wasapi, sizeof(pDevice->playback.id.wasapi), data.id.wasapi);
15445
15446         /* The descriptor needs to be updated with actual values. */
15447         pDescriptorPlayback->format             = data.formatOut;
15448         pDescriptorPlayback->channels           = data.channelsOut;
15449         pDescriptorPlayback->sampleRate         = data.sampleRateOut;
15450         MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
15451         pDescriptorPlayback->periodSizeInFrames = data.periodSizeInFramesOut;
15452         pDescriptorPlayback->periodCount        = data.periodsOut;
15453     }
15454
15455     /*
15456     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
15457     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
15458     stop the device outright and let the application handle it.
15459     */
15460 #ifdef MA_WIN32_DESKTOP
15461     if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) {
15462         if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) {
15463             pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE;
15464         }
15465         if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) {
15466             pDevice->wasapi.allowPlaybackAutoStreamRouting = MA_TRUE;
15467         }
15468     }
15469
15470     hr = ma_CoCreateInstance(pDevice->pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
15471     if (FAILED(hr)) {
15472         ma_device_uninit__wasapi(pDevice);
15473         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.", ma_result_from_HRESULT(hr));
15474     }
15475
15476     pDevice->wasapi.notificationClient.lpVtbl  = (void*)&g_maNotificationCientVtbl;
15477     pDevice->wasapi.notificationClient.counter = 1;
15478     pDevice->wasapi.notificationClient.pDevice = pDevice;
15479
15480     hr = pDeviceEnumerator->lpVtbl->RegisterEndpointNotificationCallback(pDeviceEnumerator, &pDevice->wasapi.notificationClient);
15481     if (SUCCEEDED(hr)) {
15482         pDevice->wasapi.pDeviceEnumerator = (ma_ptr)pDeviceEnumerator;
15483     } else {
15484         /* Not the end of the world if we fail to register the notification callback. We just won't support automatic stream routing. */
15485         ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
15486     }
15487 #endif
15488
15489     c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture,  MA_FALSE);
15490     c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE);
15491
15492     return MA_SUCCESS;
15493 }
15494
15495 static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_IAudioClient* pAudioClient, ma_uint32* pFrameCount)
15496 {
15497     ma_uint32 paddingFramesCount;
15498     HRESULT hr;
15499     ma_share_mode shareMode;
15500
15501     MA_ASSERT(pDevice != NULL);
15502     MA_ASSERT(pFrameCount != NULL);
15503
15504     *pFrameCount = 0;
15505
15506     if ((ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientPlayback && (ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientCapture) {
15507         return MA_INVALID_OPERATION;
15508     }
15509
15510     /*
15511     I've had a report that GetCurrentPadding() is returning a frame count of 0 which is preventing
15512     higher level function calls from doing anything because it thinks nothing is available. I have
15513     taken a look at the documentation and it looks like this is unnecessary in exclusive mode.
15514
15515     From Microsoft's documentation:
15516
15517         For an exclusive-mode rendering or capture stream that was initialized with the
15518         AUDCLNT_STREAMFLAGS_EVENTCALLBACK flag, the client typically has no use for the padding
15519         value reported by GetCurrentPadding. Instead, the client accesses an entire buffer during
15520         each processing pass.
15521
15522     Considering this, I'm going to skip GetCurrentPadding() for exclusive mode and just report the
15523     entire buffer. This depends on the caller making sure they wait on the event handler.
15524     */
15525     shareMode = ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) ? pDevice->playback.shareMode : pDevice->capture.shareMode;
15526     if (shareMode == ma_share_mode_shared) {
15527         /* Shared mode. */
15528         hr = ma_IAudioClient_GetCurrentPadding(pAudioClient, &paddingFramesCount);
15529         if (FAILED(hr)) {
15530             return ma_result_from_HRESULT(hr);
15531         }
15532
15533         if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
15534             *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback - paddingFramesCount;
15535         } else {
15536             *pFrameCount = paddingFramesCount;
15537         }
15538     } else {
15539         /* Exclusive mode. */
15540         if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
15541             *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesPlayback;
15542         } else {
15543             *pFrameCount = pDevice->wasapi.actualPeriodSizeInFramesCapture;
15544         }
15545     }
15546
15547     return MA_SUCCESS;
15548 }
15549
15550
15551 static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType)
15552 {
15553     ma_result result;
15554
15555     if (deviceType == ma_device_type_duplex) {
15556         return MA_INVALID_ARGS;
15557     }
15558
15559 #ifdef MA_DEBUG_OUTPUT
15560     printf("=== CHANGING DEVICE ===\n");
15561 #endif
15562
15563     result = ma_device_reinit__wasapi(pDevice, deviceType);
15564     if (result != MA_SUCCESS) {
15565     #ifdef MA_DEBUG_OUTPUT
15566         printf("[WASAPI] Reinitializing device after route change failed.\n");
15567     #endif
15568         return result;
15569     }
15570
15571     ma_device__post_init_setup(pDevice, deviceType);
15572
15573     return MA_SUCCESS;
15574 }
15575
15576 static ma_result ma_device_start__wasapi(ma_device* pDevice)
15577 {
15578     HRESULT hr;
15579
15580     MA_ASSERT(pDevice != NULL);
15581
15582     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
15583         hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
15584         if (FAILED(hr)) {
15585             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal capture device.", ma_result_from_HRESULT(hr));
15586         }
15587
15588         c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_TRUE);
15589     }
15590
15591     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
15592         /* No need to do anything for playback as that'll be started automatically in the data loop. */
15593     }
15594
15595     return MA_SUCCESS;
15596 }
15597
15598 static ma_result ma_device_stop__wasapi(ma_device* pDevice)
15599 {
15600     ma_result result;
15601     HRESULT hr;
15602
15603     MA_ASSERT(pDevice != NULL);
15604
15605     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
15606         hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
15607         if (FAILED(hr)) {
15608             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device.", ma_result_from_HRESULT(hr));
15609         }
15610
15611         /* The audio client needs to be reset otherwise restarting will fail. */
15612         hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
15613         if (FAILED(hr)) {
15614             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal capture device.", ma_result_from_HRESULT(hr));
15615         }
15616
15617         c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture, MA_FALSE);
15618     }
15619
15620     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
15621         /*
15622         The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to
15623         the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played.
15624         */
15625         if (c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
15626             /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */
15627             DWORD waitTime = pDevice->wasapi.actualPeriodSizeInFramesPlayback / pDevice->playback.internalSampleRate;
15628
15629             if (pDevice->playback.shareMode == ma_share_mode_exclusive) {
15630                 WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime);
15631             } else {
15632                 ma_uint32 prevFramesAvaialablePlayback = (ma_uint32)-1;
15633                 ma_uint32 framesAvailablePlayback;
15634                 for (;;) {
15635                     result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
15636                     if (result != MA_SUCCESS) {
15637                         break;
15638                     }
15639
15640                     if (framesAvailablePlayback >= pDevice->wasapi.actualPeriodSizeInFramesPlayback) {
15641                         break;
15642                     }
15643
15644                     /*
15645                     Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames
15646                     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.
15647                     */
15648                     if (framesAvailablePlayback == prevFramesAvaialablePlayback) {
15649                         break;
15650                     }
15651                     prevFramesAvaialablePlayback = framesAvailablePlayback;
15652
15653                     WaitForSingleObject(pDevice->wasapi.hEventPlayback, waitTime);
15654                     ResetEvent(pDevice->wasapi.hEventPlayback); /* Manual reset. */
15655                 }
15656             }
15657         }
15658
15659         hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
15660         if (FAILED(hr)) {
15661             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal playback device.", ma_result_from_HRESULT(hr));
15662         }
15663
15664         /* The audio client needs to be reset otherwise restarting will fail. */
15665         hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
15666         if (FAILED(hr)) {
15667             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device.", ma_result_from_HRESULT(hr));
15668         }
15669
15670         c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE);
15671     }
15672
15673     return MA_SUCCESS;
15674 }
15675
15676
15677 #ifndef MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS
15678 #define MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS 5000
15679 #endif
15680
15681 static ma_result ma_device_data_loop__wasapi(ma_device* pDevice)
15682 {
15683     ma_result result;
15684     HRESULT hr;
15685     ma_bool32 exitLoop = MA_FALSE;
15686     ma_uint32 framesWrittenToPlaybackDevice = 0;
15687     ma_uint32 mappedDeviceBufferSizeInFramesCapture = 0;
15688     ma_uint32 mappedDeviceBufferSizeInFramesPlayback = 0;
15689     ma_uint32 mappedDeviceBufferFramesRemainingCapture = 0;
15690     ma_uint32 mappedDeviceBufferFramesRemainingPlayback = 0;
15691     BYTE* pMappedDeviceBufferCapture = NULL;
15692     BYTE* pMappedDeviceBufferPlayback = NULL;
15693     ma_uint32 bpfCaptureDevice = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
15694     ma_uint32 bpfPlaybackDevice = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
15695     ma_uint32 bpfCaptureClient = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
15696     ma_uint32 bpfPlaybackClient = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
15697     ma_uint8  inputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15698     ma_uint32 inputDataInClientFormatCap = 0;
15699     ma_uint8  outputDataInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
15700     ma_uint32 outputDataInClientFormatCap = 0;
15701     ma_uint32 outputDataInClientFormatCount = 0;
15702     ma_uint32 outputDataInClientFormatConsumed = 0;
15703     ma_uint32 periodSizeInFramesCapture = 0;
15704
15705     MA_ASSERT(pDevice != NULL);
15706
15707     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
15708         periodSizeInFramesCapture  = pDevice->capture.internalPeriodSizeInFrames;
15709         inputDataInClientFormatCap = sizeof(inputDataInClientFormat) / bpfCaptureClient;
15710     }
15711
15712     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
15713         outputDataInClientFormatCap = sizeof(outputDataInClientFormat) / bpfPlaybackClient;
15714     }
15715
15716     while (ma_device_get_state(pDevice) == MA_STATE_STARTED && !exitLoop) {
15717         switch (pDevice->type)
15718         {
15719             case ma_device_type_duplex:
15720             {
15721                 ma_uint32 framesAvailableCapture;
15722                 ma_uint32 framesAvailablePlayback;
15723                 DWORD flagsCapture;    /* Passed to IAudioCaptureClient_GetBuffer(). */
15724
15725                 /* The process is to map the playback buffer and fill it as quickly as possible from input data. */
15726                 if (pMappedDeviceBufferPlayback == NULL) {
15727                     result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
15728                     if (result != MA_SUCCESS) {
15729                         return result;
15730                     }
15731
15732                     /*printf("TRACE 1: framesAvailablePlayback=%d\n", framesAvailablePlayback);*/
15733
15734
15735                     /* In exclusive mode, the frame count needs to exactly match the value returned by GetCurrentPadding(). */
15736                     if (pDevice->playback.shareMode != ma_share_mode_exclusive) {
15737                         if (framesAvailablePlayback > pDevice->wasapi.periodSizeInFramesPlayback) {
15738                             framesAvailablePlayback = pDevice->wasapi.periodSizeInFramesPlayback;
15739                         }
15740                     }
15741
15742                     /* We're ready to map the playback device's buffer. We don't release this until it's been entirely filled. */
15743                     hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback);
15744                     if (FAILED(hr)) {
15745                         ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
15746                         exitLoop = MA_TRUE;
15747                         break;
15748                     }
15749
15750                     mappedDeviceBufferSizeInFramesPlayback    = framesAvailablePlayback;
15751                     mappedDeviceBufferFramesRemainingPlayback = framesAvailablePlayback;
15752                 }
15753
15754                 if (mappedDeviceBufferFramesRemainingPlayback > 0) {
15755                     /* At this point we should have a buffer available for output. We need to keep writing input samples to it. */
15756                     for (;;) {
15757                         /* Try grabbing some captured data if we haven't already got a mapped buffer. */
15758                         if (pMappedDeviceBufferCapture == NULL) {
15759                             if (pDevice->capture.shareMode == ma_share_mode_shared) {
15760                                 if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
15761                                     return MA_ERROR;   /* Wait failed. */
15762                                 }
15763                             }
15764
15765                             result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture);
15766                             if (result != MA_SUCCESS) {
15767                                 exitLoop = MA_TRUE;
15768                                 break;
15769                             }
15770
15771                             /*printf("TRACE 2: framesAvailableCapture=%d\n", framesAvailableCapture);*/
15772
15773                             /* Wait for more if nothing is available. */
15774                             if (framesAvailableCapture == 0) {
15775                                 /* In exclusive mode we waited at the top. */
15776                                 if (pDevice->capture.shareMode != ma_share_mode_shared) {
15777                                     if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
15778                                         return MA_ERROR;   /* Wait failed. */
15779                                     }
15780                                 }
15781
15782                                 continue;
15783                             }
15784
15785                             /* Getting here means there's data available for writing to the output device. */
15786                             mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
15787                             hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
15788                             if (FAILED(hr)) {
15789                                 ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
15790                                 exitLoop = MA_TRUE;
15791                                 break;
15792                             }
15793
15794
15795                             /* Overrun detection. */
15796                             if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
15797                                 /* Glitched. Probably due to an overrun. */
15798                             #ifdef MA_DEBUG_OUTPUT
15799                                 printf("[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
15800                             #endif
15801
15802                                 /*
15803                                 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
15804                                 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
15805                                 last period.
15806                                 */
15807                                 if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) {
15808                                 #ifdef MA_DEBUG_OUTPUT
15809                                     printf("[WASAPI] Synchronizing capture stream. ");
15810                                 #endif
15811                                     do
15812                                     {
15813                                         hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
15814                                         if (FAILED(hr)) {
15815                                             break;
15816                                         }
15817
15818                                         framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture;
15819
15820                                         if (framesAvailableCapture > 0) {
15821                                             mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
15822                                             hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
15823                                             if (FAILED(hr)) {
15824                                                 ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
15825                                                 exitLoop = MA_TRUE;
15826                                                 break;
15827                                             }
15828                                         } else {
15829                                             pMappedDeviceBufferCapture = NULL;
15830                                             mappedDeviceBufferSizeInFramesCapture = 0;
15831                                         }
15832                                     } while (framesAvailableCapture > periodSizeInFramesCapture);
15833                                 #ifdef MA_DEBUG_OUTPUT
15834                                     printf("framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
15835                                 #endif
15836                                 }
15837                             } else {
15838                             #ifdef MA_DEBUG_OUTPUT
15839                                 if (flagsCapture != 0) {
15840                                     printf("[WASAPI] Capture Flags: %ld\n", flagsCapture);
15841                                 }
15842                             #endif
15843                             }
15844
15845                             mappedDeviceBufferFramesRemainingCapture = mappedDeviceBufferSizeInFramesCapture;
15846                         }
15847
15848
15849                         /* 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. */
15850                         for (;;) {
15851                             BYTE* pRunningDeviceBufferCapture;
15852                             BYTE* pRunningDeviceBufferPlayback;
15853                             ma_uint32 framesToProcess;
15854                             ma_uint32 framesProcessed;
15855
15856                             pRunningDeviceBufferCapture  = pMappedDeviceBufferCapture  + ((mappedDeviceBufferSizeInFramesCapture  - mappedDeviceBufferFramesRemainingCapture ) * bpfCaptureDevice);
15857                             pRunningDeviceBufferPlayback = pMappedDeviceBufferPlayback + ((mappedDeviceBufferSizeInFramesPlayback - mappedDeviceBufferFramesRemainingPlayback) * bpfPlaybackDevice);
15858
15859                             /* There may be some data sitting in the converter that needs to be processed first. Once this is exhaused, run the data callback again. */
15860                             if (!pDevice->playback.converter.isPassthrough && outputDataInClientFormatConsumed < outputDataInClientFormatCount) {
15861                                 ma_uint64 convertedFrameCountClient = (outputDataInClientFormatCount - outputDataInClientFormatConsumed);
15862                                 ma_uint64 convertedFrameCountDevice = mappedDeviceBufferFramesRemainingPlayback;
15863                                 void* pConvertedFramesClient = outputDataInClientFormat + (outputDataInClientFormatConsumed * bpfPlaybackClient);
15864                                 void* pConvertedFramesDevice = pRunningDeviceBufferPlayback;
15865                                 result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesClient, &convertedFrameCountClient, pConvertedFramesDevice, &convertedFrameCountDevice);
15866                                 if (result != MA_SUCCESS) {
15867                                     break;
15868                                 }
15869
15870                                 outputDataInClientFormatConsumed          += (ma_uint32)convertedFrameCountClient;  /* Safe cast. */
15871                                 mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)convertedFrameCountDevice;  /* Safe cast. */
15872
15873                                 if (mappedDeviceBufferFramesRemainingPlayback == 0) {
15874                                     break;
15875                                 }
15876                             }
15877
15878                             /*
15879                             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
15880                             buffers directly to the callback.
15881                             */
15882                             if (pDevice->capture.converter.isPassthrough && pDevice->playback.converter.isPassthrough) {
15883                                 /* Optimal path. We can pass mapped pointers directly to the callback. */
15884                                 framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, mappedDeviceBufferFramesRemainingPlayback);
15885                                 framesProcessed = framesToProcess;
15886
15887                                 ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, pRunningDeviceBufferCapture, framesToProcess);
15888
15889                                 mappedDeviceBufferFramesRemainingCapture  -= framesProcessed;
15890                                 mappedDeviceBufferFramesRemainingPlayback -= framesProcessed;
15891
15892                                 if (mappedDeviceBufferFramesRemainingCapture == 0) {
15893                                     break;  /* Exhausted input data. */
15894                                 }
15895                                 if (mappedDeviceBufferFramesRemainingPlayback == 0) {
15896                                     break;  /* Exhausted output data. */
15897                                 }
15898                             } else if (pDevice->capture.converter.isPassthrough) {
15899                                 /* The input buffer is a passthrough, but the playback buffer requires a conversion. */
15900                                 framesToProcess = ma_min(mappedDeviceBufferFramesRemainingCapture, outputDataInClientFormatCap);
15901                                 framesProcessed = framesToProcess;
15902
15903                                 ma_device__on_data(pDevice, outputDataInClientFormat, pRunningDeviceBufferCapture, framesToProcess);
15904                                 outputDataInClientFormatCount    = framesProcessed;
15905                                 outputDataInClientFormatConsumed = 0;
15906
15907                                 mappedDeviceBufferFramesRemainingCapture -= framesProcessed;
15908                                 if (mappedDeviceBufferFramesRemainingCapture == 0) {
15909                                     break;  /* Exhausted input data. */
15910                                 }
15911                             } else if (pDevice->playback.converter.isPassthrough) {
15912                                 /* The input buffer requires conversion, the playback buffer is passthrough. */
15913                                 ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture;
15914                                 ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, mappedDeviceBufferFramesRemainingPlayback);
15915
15916                                 result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess);
15917                                 if (result != MA_SUCCESS) {
15918                                     break;
15919                                 }
15920
15921                                 if (capturedClientFramesToProcess == 0) {
15922                                     break;
15923                                 }
15924
15925                                 ma_device__on_data(pDevice, pRunningDeviceBufferPlayback, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess);   /* Safe cast. */
15926
15927                                 mappedDeviceBufferFramesRemainingCapture  -= (ma_uint32)capturedDeviceFramesToProcess;
15928                                 mappedDeviceBufferFramesRemainingPlayback -= (ma_uint32)capturedClientFramesToProcess;
15929                             } else {
15930                                 ma_uint64 capturedDeviceFramesToProcess = mappedDeviceBufferFramesRemainingCapture;
15931                                 ma_uint64 capturedClientFramesToProcess = ma_min(inputDataInClientFormatCap, outputDataInClientFormatCap);
15932
15933                                 result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningDeviceBufferCapture, &capturedDeviceFramesToProcess, inputDataInClientFormat, &capturedClientFramesToProcess);
15934                                 if (result != MA_SUCCESS) {
15935                                     break;
15936                                 }
15937
15938                                 if (capturedClientFramesToProcess == 0) {
15939                                     break;
15940                                 }
15941
15942                                 ma_device__on_data(pDevice, outputDataInClientFormat, inputDataInClientFormat, (ma_uint32)capturedClientFramesToProcess);
15943
15944                                 mappedDeviceBufferFramesRemainingCapture -= (ma_uint32)capturedDeviceFramesToProcess;
15945                                 outputDataInClientFormatCount             = (ma_uint32)capturedClientFramesToProcess;
15946                                 outputDataInClientFormatConsumed          = 0;
15947                             }
15948                         }
15949
15950
15951                         /* If at this point we've run out of capture data we need to release the buffer. */
15952                         if (mappedDeviceBufferFramesRemainingCapture == 0 && pMappedDeviceBufferCapture != NULL) {
15953                             hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
15954                             if (FAILED(hr)) {
15955                                 ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
15956                                 exitLoop = MA_TRUE;
15957                                 break;
15958                             }
15959
15960                             /*printf("TRACE: Released capture buffer\n");*/
15961
15962                             pMappedDeviceBufferCapture = NULL;
15963                             mappedDeviceBufferFramesRemainingCapture = 0;
15964                             mappedDeviceBufferSizeInFramesCapture    = 0;
15965                         }
15966
15967                         /* Get out of this loop if we're run out of room in the playback buffer. */
15968                         if (mappedDeviceBufferFramesRemainingPlayback == 0) {
15969                             break;
15970                         }
15971                     }
15972                 }
15973
15974
15975                 /* If at this point we've run out of data we need to release the buffer. */
15976                 if (mappedDeviceBufferFramesRemainingPlayback == 0 && pMappedDeviceBufferPlayback != NULL) {
15977                     hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0);
15978                     if (FAILED(hr)) {
15979                         ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
15980                         exitLoop = MA_TRUE;
15981                         break;
15982                     }
15983
15984                     /*printf("TRACE: Released playback buffer\n");*/
15985                     framesWrittenToPlaybackDevice += mappedDeviceBufferSizeInFramesPlayback;
15986
15987                     pMappedDeviceBufferPlayback = NULL;
15988                     mappedDeviceBufferFramesRemainingPlayback = 0;
15989                     mappedDeviceBufferSizeInFramesPlayback    = 0;
15990                 }
15991
15992                 if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
15993                     ma_uint32 startThreshold = pDevice->playback.internalPeriodSizeInFrames * 1;
15994
15995                     /* 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. */
15996                     if (startThreshold > pDevice->wasapi.actualPeriodSizeInFramesPlayback) {
15997                         startThreshold = pDevice->wasapi.actualPeriodSizeInFramesPlayback;
15998                     }
15999
16000                     if (pDevice->playback.shareMode == ma_share_mode_exclusive || framesWrittenToPlaybackDevice >= startThreshold) {
16001                         hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
16002                         if (FAILED(hr)) {
16003                             ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
16004                             ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture);
16005                             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr));
16006                         }
16007
16008                         c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
16009                     }
16010                 }
16011
16012                 /* Make sure the device has started before waiting. */
16013                 if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
16014                     return MA_ERROR;   /* Wait failed. */
16015                 }
16016             } break;
16017
16018
16019
16020             case ma_device_type_capture:
16021             case ma_device_type_loopback:
16022             {
16023                 ma_uint32 framesAvailableCapture;
16024                 DWORD flagsCapture;    /* Passed to IAudioCaptureClient_GetBuffer(). */
16025
16026                 /* Wait for data to become available first. */
16027                 if (WaitForSingleObject(pDevice->wasapi.hEventCapture, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
16028                     exitLoop = MA_TRUE;
16029                     break;   /* Wait failed. */
16030                 }
16031
16032                 /* 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. */
16033                 result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture, &framesAvailableCapture);
16034                 if (result != MA_SUCCESS) {
16035                     exitLoop = MA_TRUE;
16036                     break;
16037                 }
16038
16039                 if (framesAvailableCapture < pDevice->wasapi.periodSizeInFramesCapture) {
16040                     continue;   /* Nothing available. Keep waiting. */
16041                 }
16042
16043                 /* Map the data buffer in preparation for sending to the client. */
16044                 mappedDeviceBufferSizeInFramesCapture = framesAvailableCapture;
16045                 hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
16046                 if (FAILED(hr)) {
16047                     ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
16048                     exitLoop = MA_TRUE;
16049                     break;
16050                 }
16051
16052                 /* Overrun detection. */
16053                 if ((flagsCapture & MA_AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) != 0) {
16054                     /* Glitched. Probably due to an overrun. */
16055                 #ifdef MA_DEBUG_OUTPUT
16056                     printf("[WASAPI] Data discontinuity (possible overrun). framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
16057                 #endif
16058
16059                     /*
16060                     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
16061                     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
16062                     last period.
16063                     */
16064                     if (framesAvailableCapture >= pDevice->wasapi.actualPeriodSizeInFramesCapture) {
16065                     #ifdef MA_DEBUG_OUTPUT
16066                         printf("[WASAPI] Synchronizing capture stream. ");
16067                     #endif
16068                         do
16069                         {
16070                             hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
16071                             if (FAILED(hr)) {
16072                                 break;
16073                             }
16074
16075                             framesAvailableCapture -= mappedDeviceBufferSizeInFramesCapture;
16076
16077                             if (framesAvailableCapture > 0) {
16078                                 mappedDeviceBufferSizeInFramesCapture = ma_min(framesAvailableCapture, periodSizeInFramesCapture);
16079                                 hr = ma_IAudioCaptureClient_GetBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, (BYTE**)&pMappedDeviceBufferCapture, &mappedDeviceBufferSizeInFramesCapture, &flagsCapture, NULL, NULL);
16080                                 if (FAILED(hr)) {
16081                                     ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
16082                                     exitLoop = MA_TRUE;
16083                                     break;
16084                                 }
16085                             } else {
16086                                 pMappedDeviceBufferCapture = NULL;
16087                                 mappedDeviceBufferSizeInFramesCapture = 0;
16088                             }
16089                         } while (framesAvailableCapture > periodSizeInFramesCapture);
16090                     #ifdef MA_DEBUG_OUTPUT
16091                         printf("framesAvailableCapture=%d, mappedBufferSizeInFramesCapture=%d\n", framesAvailableCapture, mappedDeviceBufferSizeInFramesCapture);
16092                     #endif
16093                     }
16094                 } else {
16095                 #ifdef MA_DEBUG_OUTPUT
16096                     if (flagsCapture != 0) {
16097                         printf("[WASAPI] Capture Flags: %ld\n", flagsCapture);
16098                     }
16099                 #endif
16100                 }
16101
16102                 /* We should have a buffer at this point, but let's just do a sanity check anyway. */
16103                 if (mappedDeviceBufferSizeInFramesCapture > 0 && pMappedDeviceBufferCapture != NULL) {
16104                     ma_device__send_frames_to_client(pDevice, mappedDeviceBufferSizeInFramesCapture, pMappedDeviceBufferCapture);
16105
16106                     /* At this point we're done with the buffer. */
16107                     hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
16108                     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. */
16109                     mappedDeviceBufferSizeInFramesCapture = 0;
16110                     if (FAILED(hr)) {
16111                         ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
16112                         exitLoop = MA_TRUE;
16113                         break;
16114                     }
16115                 }
16116             } break;
16117
16118
16119
16120             case ma_device_type_playback:
16121             {
16122                 ma_uint32 framesAvailablePlayback;
16123
16124                 /* Check how much space is available. If this returns 0 we just keep waiting. */
16125                 result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback);
16126                 if (result != MA_SUCCESS) {
16127                     exitLoop = MA_TRUE;
16128                     break;
16129                 }
16130
16131                 if (framesAvailablePlayback >= pDevice->wasapi.periodSizeInFramesPlayback) {
16132                     /* Map a the data buffer in preparation for the callback. */
16133                     hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, &pMappedDeviceBufferPlayback);
16134                     if (FAILED(hr)) {
16135                         ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
16136                         exitLoop = MA_TRUE;
16137                         break;
16138                     }
16139
16140                     /* We should have a buffer at this point. */
16141                     ma_device__read_frames_from_client(pDevice, framesAvailablePlayback, pMappedDeviceBufferPlayback);
16142
16143                     /* At this point we're done writing to the device and we just need to release the buffer. */
16144                     hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailablePlayback, 0);
16145                     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. */
16146                     mappedDeviceBufferSizeInFramesPlayback = 0;
16147
16148                     if (FAILED(hr)) {
16149                         ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
16150                         exitLoop = MA_TRUE;
16151                         break;
16152                     }
16153
16154                     framesWrittenToPlaybackDevice += framesAvailablePlayback;
16155                 }
16156
16157                 if (!c89atomic_load_32(&pDevice->wasapi.isStartedPlayback)) {
16158                     hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback);
16159                     if (FAILED(hr)) {
16160                         ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device.", ma_result_from_HRESULT(hr));
16161                         exitLoop = MA_TRUE;
16162                         break;
16163                     }
16164
16165                     c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_TRUE);
16166                 }
16167
16168                 /* Make sure we don't wait on the event before we've started the device or we may end up deadlocking. */
16169                 if (WaitForSingleObject(pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) {
16170                     exitLoop = MA_TRUE;
16171                     break;   /* Wait failed. Probably timed out. */
16172                 }
16173             } break;
16174
16175             default: return MA_INVALID_ARGS;
16176         }
16177     }
16178
16179     /* Here is where the device needs to be stopped. */
16180     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
16181         /* Any mapped buffers need to be released. */
16182         if (pMappedDeviceBufferCapture != NULL) {
16183             hr = ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, mappedDeviceBufferSizeInFramesCapture);
16184         }
16185     }
16186
16187     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
16188         /* Any mapped buffers need to be released. */
16189         if (pMappedDeviceBufferPlayback != NULL) {
16190             hr = ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, mappedDeviceBufferSizeInFramesPlayback, 0);
16191         }
16192     }
16193
16194     return MA_SUCCESS;
16195 }
16196
16197 static ma_result ma_device_data_loop_wakeup__wasapi(ma_device* pDevice)
16198 {
16199     MA_ASSERT(pDevice != NULL);
16200
16201     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
16202         SetEvent((HANDLE)pDevice->wasapi.hEventCapture);
16203     }
16204
16205     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
16206         SetEvent((HANDLE)pDevice->wasapi.hEventPlayback);
16207     }
16208
16209     return MA_SUCCESS;
16210 }
16211
16212
16213 static ma_result ma_context_uninit__wasapi(ma_context* pContext)
16214 {
16215     MA_ASSERT(pContext != NULL);
16216     MA_ASSERT(pContext->backend == ma_backend_wasapi);
16217     
16218     if (pContext->wasapi.commandThread != NULL) {
16219         ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_QUIT__WASAPI);
16220         ma_context_post_command__wasapi(pContext, &cmd);
16221         ma_thread_wait(&pContext->wasapi.commandThread);
16222
16223         /* Only after the thread has been terminated can we uninitialize the sync objects for the command thread. */
16224         ma_semaphore_uninit(&pContext->wasapi.commandSem);
16225         ma_mutex_uninit(&pContext->wasapi.commandLock);
16226     }
16227
16228     return MA_SUCCESS;
16229 }
16230
16231 static ma_result ma_context_init__wasapi(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
16232 {
16233     ma_result result = MA_SUCCESS;
16234
16235     MA_ASSERT(pContext != NULL);
16236
16237     (void)pConfig;
16238
16239 #ifdef MA_WIN32_DESKTOP
16240     /*
16241     WASAPI is only supported in Vista SP1 and newer. The reason for SP1 and not the base version of Vista is that event-driven
16242     exclusive mode does not work until SP1.
16243
16244     Unfortunately older compilers don't define these functions so we need to dynamically load them in order to avoid a link error.
16245     */
16246     {
16247         ma_OSVERSIONINFOEXW osvi;
16248         ma_handle kernel32DLL;
16249         ma_PFNVerifyVersionInfoW _VerifyVersionInfoW;
16250         ma_PFNVerSetConditionMask _VerSetConditionMask;
16251
16252         kernel32DLL = ma_dlopen(pContext, "kernel32.dll");
16253         if (kernel32DLL == NULL) {
16254             return MA_NO_BACKEND;
16255         }
16256
16257         _VerifyVersionInfoW  = (ma_PFNVerifyVersionInfoW )ma_dlsym(pContext, kernel32DLL, "VerifyVersionInfoW");
16258         _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(pContext, kernel32DLL, "VerSetConditionMask");
16259         if (_VerifyVersionInfoW == NULL || _VerSetConditionMask == NULL) {
16260             ma_dlclose(pContext, kernel32DLL);
16261             return MA_NO_BACKEND;
16262         }
16263
16264         MA_ZERO_OBJECT(&osvi);
16265         osvi.dwOSVersionInfoSize = sizeof(osvi);
16266         osvi.dwMajorVersion = ((MA_WIN32_WINNT_VISTA >> 8) & 0xFF);
16267         osvi.dwMinorVersion = ((MA_WIN32_WINNT_VISTA >> 0) & 0xFF);
16268         osvi.wServicePackMajor = 1;
16269         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))) {
16270             result = MA_SUCCESS;
16271         } else {
16272             result = MA_NO_BACKEND;
16273         }
16274
16275         ma_dlclose(pContext, kernel32DLL);
16276     }
16277 #endif
16278
16279     if (result != MA_SUCCESS) {
16280         return result;
16281     }
16282
16283     MA_ZERO_OBJECT(&pContext->wasapi);
16284
16285     /*
16286     Annoyingly, WASAPI does not allow you to release an IAudioClient object from a different thread
16287     than the one that retrieved it with GetService(). This can result in a deadlock in two
16288     situations:
16289
16290         1) When calling ma_device_uninit() from a different thread to ma_device_init(); and
16291         2) When uninitializing and reinitializing the internal IAudioClient object in response to
16292            automatic stream routing.
16293
16294     We could define ma_device_uninit() such that it must be called on the same thread as
16295     ma_device_init(). We could also just not release the IAudioClient when performing automatic
16296     stream routing to avoid the deadlock. Neither of these are acceptable solutions in my view so
16297     we're going to have to work around this with a worker thread. This is not ideal, but I can't
16298     think of a better way to do this.
16299
16300     More information about this can be found here:
16301
16302         https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nn-audioclient-iaudiorenderclient
16303
16304     Note this section:
16305
16306         When releasing an IAudioRenderClient interface instance, the client must call the interface's
16307         Release method from the same thread as the call to IAudioClient::GetService that created the
16308         object.
16309     */
16310     {
16311         result = ma_mutex_init(&pContext->wasapi.commandLock);
16312         if (result != MA_SUCCESS) {
16313             return result;
16314         }
16315
16316         result = ma_semaphore_init(0, &pContext->wasapi.commandSem);
16317         if (result != MA_SUCCESS) {
16318             ma_mutex_uninit(&pContext->wasapi.commandLock);
16319             return result;
16320         }
16321
16322         result = ma_thread_create(&pContext->wasapi.commandThread, ma_thread_priority_normal, 0, ma_context_command_thread__wasapi, pContext);
16323         if (result != MA_SUCCESS) {
16324             ma_semaphore_uninit(&pContext->wasapi.commandSem);
16325             ma_mutex_uninit(&pContext->wasapi.commandLock);
16326             return result;
16327         }
16328     }
16329
16330
16331     pCallbacks->onContextInit             = ma_context_init__wasapi;
16332     pCallbacks->onContextUninit           = ma_context_uninit__wasapi;
16333     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__wasapi;
16334     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__wasapi;
16335     pCallbacks->onDeviceInit              = ma_device_init__wasapi;
16336     pCallbacks->onDeviceUninit            = ma_device_uninit__wasapi;
16337     pCallbacks->onDeviceStart             = ma_device_start__wasapi;
16338     pCallbacks->onDeviceStop              = ma_device_stop__wasapi;
16339     pCallbacks->onDeviceRead              = NULL;                   /* Not used. Reading is done manually in the audio thread. */
16340     pCallbacks->onDeviceWrite             = NULL;                   /* Not used. Writing is done manually in the audio thread. */
16341     pCallbacks->onDeviceDataLoop          = ma_device_data_loop__wasapi;
16342     pCallbacks->onDeviceDataLoopWakeup    = ma_device_data_loop_wakeup__wasapi;
16343
16344     return MA_SUCCESS;
16345 }
16346 #endif
16347
16348 /******************************************************************************
16349
16350 DirectSound Backend
16351
16352 ******************************************************************************/
16353 #ifdef MA_HAS_DSOUND
16354 /*#include <dsound.h>*/
16355
16356 /*static const GUID MA_GUID_IID_DirectSoundNotify = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}};*/
16357
16358 /* miniaudio only uses priority or exclusive modes. */
16359 #define MA_DSSCL_NORMAL                 1
16360 #define MA_DSSCL_PRIORITY               2
16361 #define MA_DSSCL_EXCLUSIVE              3
16362 #define MA_DSSCL_WRITEPRIMARY           4
16363
16364 #define MA_DSCAPS_PRIMARYMONO           0x00000001
16365 #define MA_DSCAPS_PRIMARYSTEREO         0x00000002
16366 #define MA_DSCAPS_PRIMARY8BIT           0x00000004
16367 #define MA_DSCAPS_PRIMARY16BIT          0x00000008
16368 #define MA_DSCAPS_CONTINUOUSRATE        0x00000010
16369 #define MA_DSCAPS_EMULDRIVER            0x00000020
16370 #define MA_DSCAPS_CERTIFIED             0x00000040
16371 #define MA_DSCAPS_SECONDARYMONO         0x00000100
16372 #define MA_DSCAPS_SECONDARYSTEREO       0x00000200
16373 #define MA_DSCAPS_SECONDARY8BIT         0x00000400
16374 #define MA_DSCAPS_SECONDARY16BIT        0x00000800
16375
16376 #define MA_DSBCAPS_PRIMARYBUFFER        0x00000001
16377 #define MA_DSBCAPS_STATIC               0x00000002
16378 #define MA_DSBCAPS_LOCHARDWARE          0x00000004
16379 #define MA_DSBCAPS_LOCSOFTWARE          0x00000008
16380 #define MA_DSBCAPS_CTRL3D               0x00000010
16381 #define MA_DSBCAPS_CTRLFREQUENCY        0x00000020
16382 #define MA_DSBCAPS_CTRLPAN              0x00000040
16383 #define MA_DSBCAPS_CTRLVOLUME           0x00000080
16384 #define MA_DSBCAPS_CTRLPOSITIONNOTIFY   0x00000100
16385 #define MA_DSBCAPS_CTRLFX               0x00000200
16386 #define MA_DSBCAPS_STICKYFOCUS          0x00004000
16387 #define MA_DSBCAPS_GLOBALFOCUS          0x00008000
16388 #define MA_DSBCAPS_GETCURRENTPOSITION2  0x00010000
16389 #define MA_DSBCAPS_MUTE3DATMAXDISTANCE  0x00020000
16390 #define MA_DSBCAPS_LOCDEFER             0x00040000
16391 #define MA_DSBCAPS_TRUEPLAYPOSITION     0x00080000
16392
16393 #define MA_DSBPLAY_LOOPING              0x00000001
16394 #define MA_DSBPLAY_LOCHARDWARE          0x00000002
16395 #define MA_DSBPLAY_LOCSOFTWARE          0x00000004
16396 #define MA_DSBPLAY_TERMINATEBY_TIME     0x00000008
16397 #define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010
16398 #define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020
16399
16400 #define MA_DSCBSTART_LOOPING            0x00000001
16401
16402 typedef struct
16403 {
16404     DWORD dwSize;
16405     DWORD dwFlags;
16406     DWORD dwBufferBytes;
16407     DWORD dwReserved;
16408     WAVEFORMATEX* lpwfxFormat;
16409     GUID guid3DAlgorithm;
16410 } MA_DSBUFFERDESC;
16411
16412 typedef struct
16413 {
16414     DWORD dwSize;
16415     DWORD dwFlags;
16416     DWORD dwBufferBytes;
16417     DWORD dwReserved;
16418     WAVEFORMATEX* lpwfxFormat;
16419     DWORD dwFXCount;
16420     void* lpDSCFXDesc;  /* <-- miniaudio doesn't use this, so set to void*. */
16421 } MA_DSCBUFFERDESC;
16422
16423 typedef struct
16424 {
16425     DWORD dwSize;
16426     DWORD dwFlags;
16427     DWORD dwMinSecondarySampleRate;
16428     DWORD dwMaxSecondarySampleRate;
16429     DWORD dwPrimaryBuffers;
16430     DWORD dwMaxHwMixingAllBuffers;
16431     DWORD dwMaxHwMixingStaticBuffers;
16432     DWORD dwMaxHwMixingStreamingBuffers;
16433     DWORD dwFreeHwMixingAllBuffers;
16434     DWORD dwFreeHwMixingStaticBuffers;
16435     DWORD dwFreeHwMixingStreamingBuffers;
16436     DWORD dwMaxHw3DAllBuffers;
16437     DWORD dwMaxHw3DStaticBuffers;
16438     DWORD dwMaxHw3DStreamingBuffers;
16439     DWORD dwFreeHw3DAllBuffers;
16440     DWORD dwFreeHw3DStaticBuffers;
16441     DWORD dwFreeHw3DStreamingBuffers;
16442     DWORD dwTotalHwMemBytes;
16443     DWORD dwFreeHwMemBytes;
16444     DWORD dwMaxContigFreeHwMemBytes;
16445     DWORD dwUnlockTransferRateHwBuffers;
16446     DWORD dwPlayCpuOverheadSwBuffers;
16447     DWORD dwReserved1;
16448     DWORD dwReserved2;
16449 } MA_DSCAPS;
16450
16451 typedef struct
16452 {
16453     DWORD dwSize;
16454     DWORD dwFlags;
16455     DWORD dwBufferBytes;
16456     DWORD dwUnlockTransferRate;
16457     DWORD dwPlayCpuOverhead;
16458 } MA_DSBCAPS;
16459
16460 typedef struct
16461 {
16462     DWORD dwSize;
16463     DWORD dwFlags;
16464     DWORD dwFormats;
16465     DWORD dwChannels;
16466 } MA_DSCCAPS;
16467
16468 typedef struct
16469 {
16470     DWORD dwSize;
16471     DWORD dwFlags;
16472     DWORD dwBufferBytes;
16473     DWORD dwReserved;
16474 } MA_DSCBCAPS;
16475
16476 typedef struct
16477 {
16478     DWORD  dwOffset;
16479     HANDLE hEventNotify;
16480 } MA_DSBPOSITIONNOTIFY;
16481
16482 typedef struct ma_IDirectSound              ma_IDirectSound;
16483 typedef struct ma_IDirectSoundBuffer        ma_IDirectSoundBuffer;
16484 typedef struct ma_IDirectSoundCapture       ma_IDirectSoundCapture;
16485 typedef struct ma_IDirectSoundCaptureBuffer ma_IDirectSoundCaptureBuffer;
16486 typedef struct ma_IDirectSoundNotify        ma_IDirectSoundNotify;
16487
16488
16489 /*
16490 COM objects. The way these work is that you have a vtable (a list of function pointers, kind of
16491 like how C++ works internally), and then you have a structure with a single member, which is a
16492 pointer to the vtable. The vtable is where the methods of the object are defined. Methods need
16493 to be in a specific order, and parent classes need to have their methods declared first.
16494 */
16495
16496 /* IDirectSound */
16497 typedef struct
16498 {
16499     /* IUnknown */
16500     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSound* pThis, const IID* const riid, void** ppObject);
16501     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSound* pThis);
16502     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSound* pThis);
16503
16504     /* IDirectSound */
16505     HRESULT (STDMETHODCALLTYPE * CreateSoundBuffer)   (ma_IDirectSound* pThis, const MA_DSBUFFERDESC* pDSBufferDesc, ma_IDirectSoundBuffer** ppDSBuffer, void* pUnkOuter);
16506     HRESULT (STDMETHODCALLTYPE * GetCaps)             (ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps);
16507     HRESULT (STDMETHODCALLTYPE * DuplicateSoundBuffer)(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate);
16508     HRESULT (STDMETHODCALLTYPE * SetCooperativeLevel) (ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel);
16509     HRESULT (STDMETHODCALLTYPE * Compact)             (ma_IDirectSound* pThis);
16510     HRESULT (STDMETHODCALLTYPE * GetSpeakerConfig)    (ma_IDirectSound* pThis, DWORD* pSpeakerConfig);
16511     HRESULT (STDMETHODCALLTYPE * SetSpeakerConfig)    (ma_IDirectSound* pThis, DWORD dwSpeakerConfig);
16512     HRESULT (STDMETHODCALLTYPE * Initialize)          (ma_IDirectSound* pThis, const GUID* pGuidDevice);
16513 } ma_IDirectSoundVtbl;
16514 struct ma_IDirectSound
16515 {
16516     ma_IDirectSoundVtbl* lpVtbl;
16517 };
16518 static MA_INLINE HRESULT ma_IDirectSound_QueryInterface(ma_IDirectSound* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
16519 static MA_INLINE ULONG   ma_IDirectSound_AddRef(ma_IDirectSound* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
16520 static MA_INLINE ULONG   ma_IDirectSound_Release(ma_IDirectSound* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
16521 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); }
16522 static MA_INLINE HRESULT ma_IDirectSound_GetCaps(ma_IDirectSound* pThis, MA_DSCAPS* pDSCaps)                            { return pThis->lpVtbl->GetCaps(pThis, pDSCaps); }
16523 static MA_INLINE HRESULT ma_IDirectSound_DuplicateSoundBuffer(ma_IDirectSound* pThis, ma_IDirectSoundBuffer* pDSBufferOriginal, ma_IDirectSoundBuffer** ppDSBufferDuplicate) { return pThis->lpVtbl->DuplicateSoundBuffer(pThis, pDSBufferOriginal, ppDSBufferDuplicate); }
16524 static MA_INLINE HRESULT ma_IDirectSound_SetCooperativeLevel(ma_IDirectSound* pThis, HWND hwnd, DWORD dwLevel)          { return pThis->lpVtbl->SetCooperativeLevel(pThis, hwnd, dwLevel); }
16525 static MA_INLINE HRESULT ma_IDirectSound_Compact(ma_IDirectSound* pThis)                                                { return pThis->lpVtbl->Compact(pThis); }
16526 static MA_INLINE HRESULT ma_IDirectSound_GetSpeakerConfig(ma_IDirectSound* pThis, DWORD* pSpeakerConfig)                { return pThis->lpVtbl->GetSpeakerConfig(pThis, pSpeakerConfig); }
16527 static MA_INLINE HRESULT ma_IDirectSound_SetSpeakerConfig(ma_IDirectSound* pThis, DWORD dwSpeakerConfig)                { return pThis->lpVtbl->SetSpeakerConfig(pThis, dwSpeakerConfig); }
16528 static MA_INLINE HRESULT ma_IDirectSound_Initialize(ma_IDirectSound* pThis, const GUID* pGuidDevice)                    { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); }
16529
16530
16531 /* IDirectSoundBuffer */
16532 typedef struct
16533 {
16534     /* IUnknown */
16535     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject);
16536     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundBuffer* pThis);
16537     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundBuffer* pThis);
16538
16539     /* IDirectSoundBuffer */
16540     HRESULT (STDMETHODCALLTYPE * GetCaps)           (ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps);
16541     HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor);
16542     HRESULT (STDMETHODCALLTYPE * GetFormat)         (ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten);
16543     HRESULT (STDMETHODCALLTYPE * GetVolume)         (ma_IDirectSoundBuffer* pThis, LONG* pVolume);
16544     HRESULT (STDMETHODCALLTYPE * GetPan)            (ma_IDirectSoundBuffer* pThis, LONG* pPan);
16545     HRESULT (STDMETHODCALLTYPE * GetFrequency)      (ma_IDirectSoundBuffer* pThis, DWORD* pFrequency);
16546     HRESULT (STDMETHODCALLTYPE * GetStatus)         (ma_IDirectSoundBuffer* pThis, DWORD* pStatus);
16547     HRESULT (STDMETHODCALLTYPE * Initialize)        (ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc);
16548     HRESULT (STDMETHODCALLTYPE * Lock)              (ma_IDirectSoundBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags);
16549     HRESULT (STDMETHODCALLTYPE * Play)              (ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags);
16550     HRESULT (STDMETHODCALLTYPE * SetCurrentPosition)(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition);
16551     HRESULT (STDMETHODCALLTYPE * SetFormat)         (ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat);
16552     HRESULT (STDMETHODCALLTYPE * SetVolume)         (ma_IDirectSoundBuffer* pThis, LONG volume);
16553     HRESULT (STDMETHODCALLTYPE * SetPan)            (ma_IDirectSoundBuffer* pThis, LONG pan);
16554     HRESULT (STDMETHODCALLTYPE * SetFrequency)      (ma_IDirectSoundBuffer* pThis, DWORD dwFrequency);
16555     HRESULT (STDMETHODCALLTYPE * Stop)              (ma_IDirectSoundBuffer* pThis);
16556     HRESULT (STDMETHODCALLTYPE * Unlock)            (ma_IDirectSoundBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2);
16557     HRESULT (STDMETHODCALLTYPE * Restore)           (ma_IDirectSoundBuffer* pThis);
16558 } ma_IDirectSoundBufferVtbl;
16559 struct ma_IDirectSoundBuffer
16560 {
16561     ma_IDirectSoundBufferVtbl* lpVtbl;
16562 };
16563 static MA_INLINE HRESULT ma_IDirectSoundBuffer_QueryInterface(ma_IDirectSoundBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
16564 static MA_INLINE ULONG   ma_IDirectSoundBuffer_AddRef(ma_IDirectSoundBuffer* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
16565 static MA_INLINE ULONG   ma_IDirectSoundBuffer_Release(ma_IDirectSoundBuffer* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
16566 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCaps(ma_IDirectSoundBuffer* pThis, MA_DSBCAPS* pDSBufferCaps)                     { return pThis->lpVtbl->GetCaps(pThis, pDSBufferCaps); }
16567 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD* pCurrentPlayCursor, DWORD* pCurrentWriteCursor) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCurrentPlayCursor, pCurrentWriteCursor); }
16568 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFormat(ma_IDirectSoundBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); }
16569 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetVolume(ma_IDirectSoundBuffer* pThis, LONG* pVolume)                               { return pThis->lpVtbl->GetVolume(pThis, pVolume); }
16570 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetPan(ma_IDirectSoundBuffer* pThis, LONG* pPan)                                     { return pThis->lpVtbl->GetPan(pThis, pPan); }
16571 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetFrequency(ma_IDirectSoundBuffer* pThis, DWORD* pFrequency)                        { return pThis->lpVtbl->GetFrequency(pThis, pFrequency); }
16572 static MA_INLINE HRESULT ma_IDirectSoundBuffer_GetStatus(ma_IDirectSoundBuffer* pThis, DWORD* pStatus)                              { return pThis->lpVtbl->GetStatus(pThis, pStatus); }
16573 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Initialize(ma_IDirectSoundBuffer* pThis, ma_IDirectSound* pDirectSound, const MA_DSBUFFERDESC* pDSBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSound, pDSBufferDesc); }
16574 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); }
16575 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Play(ma_IDirectSoundBuffer* pThis, DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags) { return pThis->lpVtbl->Play(pThis, dwReserved1, dwPriority, dwFlags); }
16576 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetCurrentPosition(ma_IDirectSoundBuffer* pThis, DWORD dwNewPosition)                { return pThis->lpVtbl->SetCurrentPosition(pThis, dwNewPosition); }
16577 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFormat(ma_IDirectSoundBuffer* pThis, const WAVEFORMATEX* pFormat)                 { return pThis->lpVtbl->SetFormat(pThis, pFormat); }
16578 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetVolume(ma_IDirectSoundBuffer* pThis, LONG volume)                                 { return pThis->lpVtbl->SetVolume(pThis, volume); }
16579 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetPan(ma_IDirectSoundBuffer* pThis, LONG pan)                                       { return pThis->lpVtbl->SetPan(pThis, pan); }
16580 static MA_INLINE HRESULT ma_IDirectSoundBuffer_SetFrequency(ma_IDirectSoundBuffer* pThis, DWORD dwFrequency)                        { return pThis->lpVtbl->SetFrequency(pThis, dwFrequency); }
16581 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Stop(ma_IDirectSoundBuffer* pThis)                                                   { return pThis->lpVtbl->Stop(pThis); }
16582 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); }
16583 static MA_INLINE HRESULT ma_IDirectSoundBuffer_Restore(ma_IDirectSoundBuffer* pThis)                                                { return pThis->lpVtbl->Restore(pThis); }
16584
16585
16586 /* IDirectSoundCapture */
16587 typedef struct
16588 {
16589     /* IUnknown */
16590     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject);
16591     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundCapture* pThis);
16592     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundCapture* pThis);
16593
16594     /* IDirectSoundCapture */
16595     HRESULT (STDMETHODCALLTYPE * CreateCaptureBuffer)(ma_IDirectSoundCapture* pThis, const MA_DSCBUFFERDESC* pDSCBufferDesc, ma_IDirectSoundCaptureBuffer** ppDSCBuffer, void* pUnkOuter);
16596     HRESULT (STDMETHODCALLTYPE * GetCaps)            (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps);
16597     HRESULT (STDMETHODCALLTYPE * Initialize)         (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice);
16598 } ma_IDirectSoundCaptureVtbl;
16599 struct ma_IDirectSoundCapture
16600 {
16601     ma_IDirectSoundCaptureVtbl* lpVtbl;
16602 };
16603 static MA_INLINE HRESULT ma_IDirectSoundCapture_QueryInterface(ma_IDirectSoundCapture* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
16604 static MA_INLINE ULONG   ma_IDirectSoundCapture_AddRef(ma_IDirectSoundCapture* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
16605 static MA_INLINE ULONG   ma_IDirectSoundCapture_Release(ma_IDirectSoundCapture* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
16606 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); }
16607 static MA_INLINE HRESULT ma_IDirectSoundCapture_GetCaps            (ma_IDirectSoundCapture* pThis, MA_DSCCAPS* pDSCCaps)              { return pThis->lpVtbl->GetCaps(pThis, pDSCCaps); }
16608 static MA_INLINE HRESULT ma_IDirectSoundCapture_Initialize         (ma_IDirectSoundCapture* pThis, const GUID* pGuidDevice)           { return pThis->lpVtbl->Initialize(pThis, pGuidDevice); }
16609
16610
16611 /* IDirectSoundCaptureBuffer */
16612 typedef struct
16613 {
16614     /* IUnknown */
16615     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject);
16616     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundCaptureBuffer* pThis);
16617     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundCaptureBuffer* pThis);
16618
16619     /* IDirectSoundCaptureBuffer */
16620     HRESULT (STDMETHODCALLTYPE * GetCaps)           (ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps);
16621     HRESULT (STDMETHODCALLTYPE * GetCurrentPosition)(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition);
16622     HRESULT (STDMETHODCALLTYPE * GetFormat)         (ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten);
16623     HRESULT (STDMETHODCALLTYPE * GetStatus)         (ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus);
16624     HRESULT (STDMETHODCALLTYPE * Initialize)        (ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc);
16625     HRESULT (STDMETHODCALLTYPE * Lock)              (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwOffset, DWORD dwBytes, void** ppAudioPtr1, DWORD* pAudioBytes1, void** ppAudioPtr2, DWORD* pAudioBytes2, DWORD dwFlags);
16626     HRESULT (STDMETHODCALLTYPE * Start)             (ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags);
16627     HRESULT (STDMETHODCALLTYPE * Stop)              (ma_IDirectSoundCaptureBuffer* pThis);
16628     HRESULT (STDMETHODCALLTYPE * Unlock)            (ma_IDirectSoundCaptureBuffer* pThis, void* pAudioPtr1, DWORD dwAudioBytes1, void* pAudioPtr2, DWORD dwAudioBytes2);
16629 } ma_IDirectSoundCaptureBufferVtbl;
16630 struct ma_IDirectSoundCaptureBuffer
16631 {
16632     ma_IDirectSoundCaptureBufferVtbl* lpVtbl;
16633 };
16634 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_QueryInterface(ma_IDirectSoundCaptureBuffer* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
16635 static MA_INLINE ULONG   ma_IDirectSoundCaptureBuffer_AddRef(ma_IDirectSoundCaptureBuffer* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
16636 static MA_INLINE ULONG   ma_IDirectSoundCaptureBuffer_Release(ma_IDirectSoundCaptureBuffer* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
16637 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCaps(ma_IDirectSoundCaptureBuffer* pThis, MA_DSCBCAPS* pDSCBCaps)                        { return pThis->lpVtbl->GetCaps(pThis, pDSCBCaps); }
16638 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetCurrentPosition(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pCapturePosition, DWORD* pReadPosition) { return pThis->lpVtbl->GetCurrentPosition(pThis, pCapturePosition, pReadPosition); }
16639 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetFormat(ma_IDirectSoundCaptureBuffer* pThis, WAVEFORMATEX* pFormat, DWORD dwSizeAllocated, DWORD* pSizeWritten) { return pThis->lpVtbl->GetFormat(pThis, pFormat, dwSizeAllocated, pSizeWritten); }
16640 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_GetStatus(ma_IDirectSoundCaptureBuffer* pThis, DWORD* pStatus)                              { return pThis->lpVtbl->GetStatus(pThis, pStatus); }
16641 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Initialize(ma_IDirectSoundCaptureBuffer* pThis, ma_IDirectSoundCapture* pDirectSoundCapture, const MA_DSCBUFFERDESC* pDSCBufferDesc) { return pThis->lpVtbl->Initialize(pThis, pDirectSoundCapture, pDSCBufferDesc); }
16642 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); }
16643 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Start(ma_IDirectSoundCaptureBuffer* pThis, DWORD dwFlags)                                   { return pThis->lpVtbl->Start(pThis, dwFlags); }
16644 static MA_INLINE HRESULT ma_IDirectSoundCaptureBuffer_Stop(ma_IDirectSoundCaptureBuffer* pThis)                                                   { return pThis->lpVtbl->Stop(pThis); }
16645 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); }
16646
16647
16648 /* IDirectSoundNotify */
16649 typedef struct
16650 {
16651     /* IUnknown */
16652     HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject);
16653     ULONG   (STDMETHODCALLTYPE * AddRef)        (ma_IDirectSoundNotify* pThis);
16654     ULONG   (STDMETHODCALLTYPE * Release)       (ma_IDirectSoundNotify* pThis);
16655
16656     /* IDirectSoundNotify */
16657     HRESULT (STDMETHODCALLTYPE * SetNotificationPositions)(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies);
16658 } ma_IDirectSoundNotifyVtbl;
16659 struct ma_IDirectSoundNotify
16660 {
16661     ma_IDirectSoundNotifyVtbl* lpVtbl;
16662 };
16663 static MA_INLINE HRESULT ma_IDirectSoundNotify_QueryInterface(ma_IDirectSoundNotify* pThis, const IID* const riid, void** ppObject) { return pThis->lpVtbl->QueryInterface(pThis, riid, ppObject); }
16664 static MA_INLINE ULONG   ma_IDirectSoundNotify_AddRef(ma_IDirectSoundNotify* pThis)                                                 { return pThis->lpVtbl->AddRef(pThis); }
16665 static MA_INLINE ULONG   ma_IDirectSoundNotify_Release(ma_IDirectSoundNotify* pThis)                                                { return pThis->lpVtbl->Release(pThis); }
16666 static MA_INLINE HRESULT ma_IDirectSoundNotify_SetNotificationPositions(ma_IDirectSoundNotify* pThis, DWORD dwPositionNotifies, const MA_DSBPOSITIONNOTIFY* pPositionNotifies) { return pThis->lpVtbl->SetNotificationPositions(pThis, dwPositionNotifies, pPositionNotifies); }
16667
16668
16669 typedef BOOL    (CALLBACK * ma_DSEnumCallbackAProc)             (LPGUID pDeviceGUID, LPCSTR pDeviceDescription, LPCSTR pModule, LPVOID pContext);
16670 typedef HRESULT (WINAPI   * ma_DirectSoundCreateProc)           (const GUID* pcGuidDevice, ma_IDirectSound** ppDS8, LPUNKNOWN pUnkOuter);
16671 typedef HRESULT (WINAPI   * ma_DirectSoundEnumerateAProc)       (ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext);
16672 typedef HRESULT (WINAPI   * ma_DirectSoundCaptureCreateProc)    (const GUID* pcGuidDevice, ma_IDirectSoundCapture** ppDSC8, LPUNKNOWN pUnkOuter);
16673 typedef HRESULT (WINAPI   * ma_DirectSoundCaptureEnumerateAProc)(ma_DSEnumCallbackAProc pDSEnumCallback, LPVOID pContext);
16674
16675 static ma_uint32 ma_get_best_sample_rate_within_range(ma_uint32 sampleRateMin, ma_uint32 sampleRateMax)
16676 {
16677     /* Normalize the range in case we were given something stupid. */
16678     if (sampleRateMin < (ma_uint32)ma_standard_sample_rate_min) {
16679         sampleRateMin = (ma_uint32)ma_standard_sample_rate_min;
16680     }
16681     if (sampleRateMax > (ma_uint32)ma_standard_sample_rate_max) {
16682         sampleRateMax = (ma_uint32)ma_standard_sample_rate_max;
16683     }
16684     if (sampleRateMin > sampleRateMax) {
16685         sampleRateMin = sampleRateMax;
16686     }
16687
16688     if (sampleRateMin == sampleRateMax) {
16689         return sampleRateMax;
16690     } else {
16691         size_t iStandardRate;
16692         for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
16693             ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
16694             if (standardRate >= sampleRateMin && standardRate <= sampleRateMax) {
16695                 return standardRate;
16696             }
16697         }
16698     }
16699
16700     /* Should never get here. */
16701     MA_ASSERT(MA_FALSE);
16702     return 0;
16703 }
16704
16705 /*
16706 Retrieves the channel count and channel map for the given speaker configuration. If the speaker configuration is unknown,
16707 the channel count and channel map will be left unmodified.
16708 */
16709 static void ma_get_channels_from_speaker_config__dsound(DWORD speakerConfig, WORD* pChannelsOut, DWORD* pChannelMapOut)
16710 {
16711     WORD  channels;
16712     DWORD channelMap;
16713
16714     channels = 0;
16715     if (pChannelsOut != NULL) {
16716         channels = *pChannelsOut;
16717     }
16718
16719     channelMap = 0;
16720     if (pChannelMapOut != NULL) {
16721         channelMap = *pChannelMapOut;
16722     }
16723
16724     /*
16725     The speaker configuration is a combination of speaker config and speaker geometry. The lower 8 bits is what we care about. The upper
16726     16 bits is for the geometry.
16727     */
16728     switch ((BYTE)(speakerConfig)) {
16729         case 1 /*DSSPEAKER_HEADPHONE*/:                          channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
16730         case 2 /*DSSPEAKER_MONO*/:                               channels = 1; channelMap = SPEAKER_FRONT_CENTER; break;
16731         case 3 /*DSSPEAKER_QUAD*/:                               channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
16732         case 4 /*DSSPEAKER_STEREO*/:                             channels = 2; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
16733         case 5 /*DSSPEAKER_SURROUND*/:                           channels = 4; channelMap = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER; break;
16734         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;
16735         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;
16736         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;
16737         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;
16738         default: break;
16739     }
16740
16741     if (pChannelsOut != NULL) {
16742         *pChannelsOut = channels;
16743     }
16744
16745     if (pChannelMapOut != NULL) {
16746         *pChannelMapOut = channelMap;
16747     }
16748 }
16749
16750
16751 static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSound** ppDirectSound)
16752 {
16753     ma_IDirectSound* pDirectSound;
16754     HWND hWnd;
16755     HRESULT hr;
16756
16757     MA_ASSERT(pContext != NULL);
16758     MA_ASSERT(ppDirectSound != NULL);
16759
16760     *ppDirectSound = NULL;
16761     pDirectSound = NULL;
16762
16763     if (FAILED(((ma_DirectSoundCreateProc)pContext->dsound.DirectSoundCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSound, NULL))) {
16764         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCreate() failed for playback device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
16765     }
16766
16767     /* The cooperative level must be set before doing anything else. */
16768     hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)();
16769     if (hWnd == NULL) {
16770         hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)();
16771     }
16772
16773     hr = ma_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == ma_share_mode_exclusive) ? MA_DSSCL_EXCLUSIVE : MA_DSSCL_PRIORITY);
16774     if (FAILED(hr)) {
16775         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_SetCooperateiveLevel() failed for playback device.", ma_result_from_HRESULT(hr));
16776     }
16777
16778     *ppDirectSound = pDirectSound;
16779     return MA_SUCCESS;
16780 }
16781
16782 static ma_result ma_context_create_IDirectSoundCapture__dsound(ma_context* pContext, ma_share_mode shareMode, const ma_device_id* pDeviceID, ma_IDirectSoundCapture** ppDirectSoundCapture)
16783 {
16784     ma_IDirectSoundCapture* pDirectSoundCapture;
16785     HRESULT hr;
16786
16787     MA_ASSERT(pContext != NULL);
16788     MA_ASSERT(ppDirectSoundCapture != NULL);
16789
16790     /* DirectSound does not support exclusive mode for capture. */
16791     if (shareMode == ma_share_mode_exclusive) {
16792         return MA_SHARE_MODE_NOT_SUPPORTED;
16793     }
16794
16795     *ppDirectSoundCapture = NULL;
16796     pDirectSoundCapture = NULL;
16797
16798     hr = ((ma_DirectSoundCaptureCreateProc)pContext->dsound.DirectSoundCaptureCreate)((pDeviceID == NULL) ? NULL : (const GUID*)pDeviceID->dsound, &pDirectSoundCapture, NULL);
16799     if (FAILED(hr)) {
16800         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] DirectSoundCaptureCreate() failed for capture device.", ma_result_from_HRESULT(hr));
16801     }
16802
16803     *ppDirectSoundCapture = pDirectSoundCapture;
16804     return MA_SUCCESS;
16805 }
16806
16807 static ma_result ma_context_get_format_info_for_IDirectSoundCapture__dsound(ma_context* pContext, ma_IDirectSoundCapture* pDirectSoundCapture, WORD* pChannels, WORD* pBitsPerSample, DWORD* pSampleRate)
16808 {
16809     HRESULT hr;
16810     MA_DSCCAPS caps;
16811     WORD bitsPerSample;
16812     DWORD sampleRate;
16813
16814     MA_ASSERT(pContext != NULL);
16815     MA_ASSERT(pDirectSoundCapture != NULL);
16816
16817     if (pChannels) {
16818         *pChannels = 0;
16819     }
16820     if (pBitsPerSample) {
16821         *pBitsPerSample = 0;
16822     }
16823     if (pSampleRate) {
16824         *pSampleRate = 0;
16825     }
16826
16827     MA_ZERO_OBJECT(&caps);
16828     caps.dwSize = sizeof(caps);
16829     hr = ma_IDirectSoundCapture_GetCaps(pDirectSoundCapture, &caps);
16830     if (FAILED(hr)) {
16831         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_GetCaps() failed for capture device.", ma_result_from_HRESULT(hr));
16832     }
16833
16834     if (pChannels) {
16835         *pChannels = (WORD)caps.dwChannels;
16836     }
16837
16838     /* 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. */
16839     bitsPerSample = 16;
16840     sampleRate = 48000;
16841
16842     if (caps.dwChannels == 1) {
16843         if ((caps.dwFormats & WAVE_FORMAT_48M16) != 0) {
16844             sampleRate = 48000;
16845         } else if ((caps.dwFormats & WAVE_FORMAT_44M16) != 0) {
16846             sampleRate = 44100;
16847         } else if ((caps.dwFormats & WAVE_FORMAT_2M16) != 0) {
16848             sampleRate = 22050;
16849         } else if ((caps.dwFormats & WAVE_FORMAT_1M16) != 0) {
16850             sampleRate = 11025;
16851         } else if ((caps.dwFormats & WAVE_FORMAT_96M16) != 0) {
16852             sampleRate = 96000;
16853         } else {
16854             bitsPerSample = 8;
16855             if ((caps.dwFormats & WAVE_FORMAT_48M08) != 0) {
16856                 sampleRate = 48000;
16857             } else if ((caps.dwFormats & WAVE_FORMAT_44M08) != 0) {
16858                 sampleRate = 44100;
16859             } else if ((caps.dwFormats & WAVE_FORMAT_2M08) != 0) {
16860                 sampleRate = 22050;
16861             } else if ((caps.dwFormats & WAVE_FORMAT_1M08) != 0) {
16862                 sampleRate = 11025;
16863             } else if ((caps.dwFormats & WAVE_FORMAT_96M08) != 0) {
16864                 sampleRate = 96000;
16865             } else {
16866                 bitsPerSample = 16;  /* Didn't find it. Just fall back to 16-bit. */
16867             }
16868         }
16869     } else if (caps.dwChannels == 2) {
16870         if ((caps.dwFormats & WAVE_FORMAT_48S16) != 0) {
16871             sampleRate = 48000;
16872         } else if ((caps.dwFormats & WAVE_FORMAT_44S16) != 0) {
16873             sampleRate = 44100;
16874         } else if ((caps.dwFormats & WAVE_FORMAT_2S16) != 0) {
16875             sampleRate = 22050;
16876         } else if ((caps.dwFormats & WAVE_FORMAT_1S16) != 0) {
16877             sampleRate = 11025;
16878         } else if ((caps.dwFormats & WAVE_FORMAT_96S16) != 0) {
16879             sampleRate = 96000;
16880         } else {
16881             bitsPerSample = 8;
16882             if ((caps.dwFormats & WAVE_FORMAT_48S08) != 0) {
16883                 sampleRate = 48000;
16884             } else if ((caps.dwFormats & WAVE_FORMAT_44S08) != 0) {
16885                 sampleRate = 44100;
16886             } else if ((caps.dwFormats & WAVE_FORMAT_2S08) != 0) {
16887                 sampleRate = 22050;
16888             } else if ((caps.dwFormats & WAVE_FORMAT_1S08) != 0) {
16889                 sampleRate = 11025;
16890             } else if ((caps.dwFormats & WAVE_FORMAT_96S08) != 0) {
16891                 sampleRate = 96000;
16892             } else {
16893                 bitsPerSample = 16;  /* Didn't find it. Just fall back to 16-bit. */
16894             }
16895         }
16896     }
16897
16898     if (pBitsPerSample) {
16899         *pBitsPerSample = bitsPerSample;
16900     }
16901     if (pSampleRate) {
16902         *pSampleRate = sampleRate;
16903     }
16904
16905     return MA_SUCCESS;
16906 }
16907
16908
16909 typedef struct
16910 {
16911     ma_context* pContext;
16912     ma_device_type deviceType;
16913     ma_enum_devices_callback_proc callback;
16914     void* pUserData;
16915     ma_bool32 terminated;
16916 } ma_context_enumerate_devices_callback_data__dsound;
16917
16918 static BOOL CALLBACK ma_context_enumerate_devices_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
16919 {
16920     ma_context_enumerate_devices_callback_data__dsound* pData = (ma_context_enumerate_devices_callback_data__dsound*)lpContext;
16921     ma_device_info deviceInfo;
16922
16923     (void)lpcstrModule;
16924
16925     MA_ZERO_OBJECT(&deviceInfo);
16926
16927     /* ID. */
16928     if (lpGuid != NULL) {
16929         MA_COPY_MEMORY(deviceInfo.id.dsound, lpGuid, 16);
16930     } else {
16931         MA_ZERO_MEMORY(deviceInfo.id.dsound, 16);
16932         deviceInfo.isDefault = MA_TRUE;
16933     }
16934
16935     /* Name / Description */
16936     ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), lpcstrDescription, (size_t)-1);
16937
16938
16939     /* Call the callback function, but make sure we stop enumerating if the callee requested so. */
16940     MA_ASSERT(pData != NULL);
16941     pData->terminated = !pData->callback(pData->pContext, pData->deviceType, &deviceInfo, pData->pUserData);
16942     if (pData->terminated) {
16943         return FALSE;   /* Stop enumeration. */
16944     } else {
16945         return TRUE;    /* Continue enumeration. */
16946     }
16947 }
16948
16949 static ma_result ma_context_enumerate_devices__dsound(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
16950 {
16951     ma_context_enumerate_devices_callback_data__dsound data;
16952
16953     MA_ASSERT(pContext != NULL);
16954     MA_ASSERT(callback != NULL);
16955
16956     data.pContext = pContext;
16957     data.callback = callback;
16958     data.pUserData = pUserData;
16959     data.terminated = MA_FALSE;
16960
16961     /* Playback. */
16962     if (!data.terminated) {
16963         data.deviceType = ma_device_type_playback;
16964         ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data);
16965     }
16966
16967     /* Capture. */
16968     if (!data.terminated) {
16969         data.deviceType = ma_device_type_capture;
16970         ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_enumerate_devices_callback__dsound, &data);
16971     }
16972
16973     return MA_SUCCESS;
16974 }
16975
16976
16977 typedef struct
16978 {
16979     const ma_device_id* pDeviceID;
16980     ma_device_info* pDeviceInfo;
16981     ma_bool32 found;
16982 } ma_context_get_device_info_callback_data__dsound;
16983
16984 static BOOL CALLBACK ma_context_get_device_info_callback__dsound(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
16985 {
16986     ma_context_get_device_info_callback_data__dsound* pData = (ma_context_get_device_info_callback_data__dsound*)lpContext;
16987     MA_ASSERT(pData != NULL);
16988
16989     if ((pData->pDeviceID == NULL || ma_is_guid_null(pData->pDeviceID->dsound)) && (lpGuid == NULL || ma_is_guid_null(lpGuid))) {
16990         /* Default device. */
16991         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1);
16992         pData->pDeviceInfo->isDefault = MA_TRUE;
16993         pData->found = MA_TRUE;
16994         return FALSE;   /* Stop enumeration. */
16995     } else {
16996         /* Not the default device. */
16997         if (lpGuid != NULL && pData->pDeviceID != NULL) {
16998             if (memcmp(pData->pDeviceID->dsound, lpGuid, sizeof(pData->pDeviceID->dsound)) == 0) {
16999                 ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), lpcstrDescription, (size_t)-1);
17000                 pData->found = MA_TRUE;
17001                 return FALSE;   /* Stop enumeration. */
17002             }
17003         }
17004     }
17005
17006     (void)lpcstrModule;
17007     return TRUE;
17008 }
17009
17010 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)
17011 {
17012     ma_result result;
17013     HRESULT hr;
17014
17015     if (pDeviceID != NULL) {
17016         ma_context_get_device_info_callback_data__dsound data;
17017
17018         /* ID. */
17019         MA_COPY_MEMORY(pDeviceInfo->id.dsound, pDeviceID->dsound, 16);
17020
17021         /* Name / Description. This is retrieved by enumerating over each device until we find that one that matches the input ID. */
17022         data.pDeviceID = pDeviceID;
17023         data.pDeviceInfo = pDeviceInfo;
17024         data.found = MA_FALSE;
17025         if (deviceType == ma_device_type_playback) {
17026             ((ma_DirectSoundEnumerateAProc)pContext->dsound.DirectSoundEnumerateA)(ma_context_get_device_info_callback__dsound, &data);
17027         } else {
17028             ((ma_DirectSoundCaptureEnumerateAProc)pContext->dsound.DirectSoundCaptureEnumerateA)(ma_context_get_device_info_callback__dsound, &data);
17029         }
17030
17031         if (!data.found) {
17032             return MA_NO_DEVICE;
17033         }
17034     } else {
17035         /* 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. */
17036
17037         /* ID */
17038         MA_ZERO_MEMORY(pDeviceInfo->id.dsound, 16);
17039
17040         /* Name / Description */
17041         if (deviceType == ma_device_type_playback) {
17042             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
17043         } else {
17044             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
17045         }
17046
17047         pDeviceInfo->isDefault = MA_TRUE;
17048     }
17049
17050     /* Retrieving detailed information is slightly different depending on the device type. */
17051     if (deviceType == ma_device_type_playback) {
17052         /* Playback. */
17053         ma_IDirectSound* pDirectSound;
17054         MA_DSCAPS caps;
17055         WORD channels;
17056
17057         result = ma_context_create_IDirectSound__dsound(pContext, ma_share_mode_shared, pDeviceID, &pDirectSound);
17058         if (result != MA_SUCCESS) {
17059             return result;
17060         }
17061
17062         MA_ZERO_OBJECT(&caps);
17063         caps.dwSize = sizeof(caps);
17064         hr = ma_IDirectSound_GetCaps(pDirectSound, &caps);
17065         if (FAILED(hr)) {
17066             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr));
17067         }
17068
17069
17070         /* Channels. Only a single channel count is reported for DirectSound. */
17071         if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) {
17072             /* It supports at least stereo, but could support more. */
17073             DWORD speakerConfig;
17074
17075             channels = 2;
17076
17077             /* Look at the speaker configuration to get a better idea on the channel count. */
17078             hr = ma_IDirectSound_GetSpeakerConfig(pDirectSound, &speakerConfig);
17079             if (SUCCEEDED(hr)) {
17080                 ma_get_channels_from_speaker_config__dsound(speakerConfig, &channels, NULL);
17081             }
17082         } else {
17083             /* It does not support stereo, which means we are stuck with mono. */
17084             channels = 1;
17085         }
17086
17087
17088         /*
17089         In DirectSound, our native formats are centered around sample rates. All formats are supported, and we're only reporting a single channel
17090         count. However, DirectSound can report a range of supported sample rates. We're only going to include standard rates known by miniaudio
17091         in order to keep the size of this within reason.
17092         */
17093         if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) {
17094             /* Multiple sample rates are supported. We'll report in order of our preferred sample rates. */
17095             size_t iStandardSampleRate;
17096             for (iStandardSampleRate = 0; iStandardSampleRate < ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate += 1) {
17097                 ma_uint32 sampleRate = g_maStandardSampleRatePriorities[iStandardSampleRate];
17098                 if (sampleRate >= caps.dwMinSecondarySampleRate && sampleRate <= caps.dwMaxSecondarySampleRate) {
17099                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = ma_format_unknown;
17100                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
17101                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
17102                     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
17103                     pDeviceInfo->nativeDataFormatCount += 1;
17104                 }
17105             }
17106         } else {
17107             /* Only a single sample rate is supported. */
17108             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = ma_format_unknown;
17109             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
17110             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = caps.dwMaxSecondarySampleRate;
17111             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
17112             pDeviceInfo->nativeDataFormatCount += 1;
17113         }
17114
17115         ma_IDirectSound_Release(pDirectSound);
17116     } else {
17117         /*
17118         Capture. This is a little different to playback due to the say the supported formats are reported. Technically capture
17119         devices can support a number of different formats, but for simplicity and consistency with ma_device_init() I'm just
17120         reporting the best format.
17121         */
17122         ma_IDirectSoundCapture* pDirectSoundCapture;
17123         WORD channels;
17124         WORD bitsPerSample;
17125         DWORD sampleRate;
17126
17127         result = ma_context_create_IDirectSoundCapture__dsound(pContext, ma_share_mode_shared, pDeviceID, &pDirectSoundCapture);
17128         if (result != MA_SUCCESS) {
17129             return result;
17130         }
17131
17132         result = ma_context_get_format_info_for_IDirectSoundCapture__dsound(pContext, pDirectSoundCapture, &channels, &bitsPerSample, &sampleRate);
17133         if (result != MA_SUCCESS) {
17134             ma_IDirectSoundCapture_Release(pDirectSoundCapture);
17135             return result;
17136         }
17137
17138         ma_IDirectSoundCapture_Release(pDirectSoundCapture);
17139
17140         /* The format is always an integer format and is based on the bits per sample. */
17141         if (bitsPerSample == 8) {
17142             pDeviceInfo->formats[0] = ma_format_u8;
17143         } else if (bitsPerSample == 16) {
17144             pDeviceInfo->formats[0] = ma_format_s16;
17145         } else if (bitsPerSample == 24) {
17146             pDeviceInfo->formats[0] = ma_format_s24;
17147         } else if (bitsPerSample == 32) {
17148             pDeviceInfo->formats[0] = ma_format_s32;
17149         } else {
17150             return MA_FORMAT_NOT_SUPPORTED;
17151         }
17152
17153         pDeviceInfo->nativeDataFormats[0].channels   = channels;
17154         pDeviceInfo->nativeDataFormats[0].sampleRate = sampleRate;
17155         pDeviceInfo->nativeDataFormats[0].flags      = 0;
17156         pDeviceInfo->nativeDataFormatCount = 1;
17157     }
17158
17159     return MA_SUCCESS;
17160 }
17161
17162
17163
17164 static ma_result ma_device_uninit__dsound(ma_device* pDevice)
17165 {
17166     MA_ASSERT(pDevice != NULL);
17167
17168     if (pDevice->dsound.pCaptureBuffer != NULL) {
17169         ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
17170     }
17171     if (pDevice->dsound.pCapture != NULL) {
17172         ma_IDirectSoundCapture_Release((ma_IDirectSoundCapture*)pDevice->dsound.pCapture);
17173     }
17174
17175     if (pDevice->dsound.pPlaybackBuffer != NULL) {
17176         ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
17177     }
17178     if (pDevice->dsound.pPlaybackPrimaryBuffer != NULL) {
17179         ma_IDirectSoundBuffer_Release((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer);
17180     }
17181     if (pDevice->dsound.pPlayback != NULL) {
17182         ma_IDirectSound_Release((ma_IDirectSound*)pDevice->dsound.pPlayback);
17183     }
17184
17185     return MA_SUCCESS;
17186 }
17187
17188 static ma_result ma_config_to_WAVEFORMATEXTENSIBLE(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, const ma_channel* pChannelMap, WAVEFORMATEXTENSIBLE* pWF)
17189 {
17190     GUID subformat;
17191
17192     if (format == ma_format_unknown) {
17193         format = MA_DEFAULT_FORMAT;
17194     }
17195
17196     if (channels == 0) {
17197         channels = MA_DEFAULT_CHANNELS;
17198     }
17199
17200     if (sampleRate == 0) {
17201         sampleRate = MA_DEFAULT_SAMPLE_RATE;
17202     }
17203
17204     switch (format)
17205     {
17206         case ma_format_u8:
17207         case ma_format_s16:
17208         case ma_format_s24:
17209         /*case ma_format_s24_32:*/
17210         case ma_format_s32:
17211         {
17212             subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
17213         } break;
17214
17215         case ma_format_f32:
17216         {
17217             subformat = MA_GUID_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
17218         } break;
17219
17220         default:
17221         return MA_FORMAT_NOT_SUPPORTED;
17222     }
17223
17224     MA_ZERO_OBJECT(pWF);
17225     pWF->Format.cbSize               = sizeof(*pWF);
17226     pWF->Format.wFormatTag           = WAVE_FORMAT_EXTENSIBLE;
17227     pWF->Format.nChannels            = (WORD)channels;
17228     pWF->Format.nSamplesPerSec       = (DWORD)sampleRate;
17229     pWF->Format.wBitsPerSample       = (WORD)(ma_get_bytes_per_sample(format)*8);
17230     pWF->Format.nBlockAlign          = (WORD)(pWF->Format.nChannels * pWF->Format.wBitsPerSample / 8);
17231     pWF->Format.nAvgBytesPerSec      = pWF->Format.nBlockAlign * pWF->Format.nSamplesPerSec;
17232     pWF->Samples.wValidBitsPerSample = pWF->Format.wBitsPerSample;
17233     pWF->dwChannelMask               = ma_channel_map_to_channel_mask__win32(pChannelMap, channels);
17234     pWF->SubFormat                   = subformat;
17235
17236     return MA_SUCCESS;
17237 }
17238
17239 static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__dsound(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
17240 {
17241     /* DirectSound has a minimum period size of 20ms. */
17242     ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(20, nativeSampleRate);
17243     ma_uint32 periodSizeInFrames;
17244
17245     periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile);
17246     if (periodSizeInFrames < minPeriodSizeInFrames) {
17247         periodSizeInFrames = minPeriodSizeInFrames;
17248     }
17249
17250     return periodSizeInFrames;
17251 }
17252
17253 static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
17254 {
17255     ma_result result;
17256     HRESULT hr;
17257
17258     MA_ASSERT(pDevice != NULL);
17259
17260     MA_ZERO_OBJECT(&pDevice->dsound);
17261
17262     if (pConfig->deviceType == ma_device_type_loopback) {
17263         return MA_DEVICE_TYPE_NOT_SUPPORTED;
17264     }
17265
17266     /*
17267     Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices. We need to initialize
17268     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
17269     full-duplex mode.
17270     */
17271     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
17272         WAVEFORMATEXTENSIBLE wf;
17273         MA_DSCBUFFERDESC descDS;
17274         ma_uint32 periodSizeInFrames;
17275         ma_uint32 periodCount;
17276         char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */
17277         WAVEFORMATEXTENSIBLE* pActualFormat;
17278
17279         result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, &wf);
17280         if (result != MA_SUCCESS) {
17281             return result;
17282         }
17283
17284         result = ma_context_create_IDirectSoundCapture__dsound(pDevice->pContext, pDescriptorCapture->shareMode, pDescriptorCapture->pDeviceID, (ma_IDirectSoundCapture**)&pDevice->dsound.pCapture);
17285         if (result != MA_SUCCESS) {
17286             ma_device_uninit__dsound(pDevice);
17287             return result;
17288         }
17289
17290         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);
17291         if (result != MA_SUCCESS) {
17292             ma_device_uninit__dsound(pDevice);
17293             return result;
17294         }
17295
17296         wf.Format.nBlockAlign          = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8);
17297         wf.Format.nAvgBytesPerSec      = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
17298         wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
17299         wf.SubFormat                   = MA_GUID_KSDATAFORMAT_SUBTYPE_PCM;
17300
17301         /* The size of the buffer must be a clean multiple of the period count. */
17302         periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorCapture, wf.Format.nSamplesPerSec, pConfig->performanceProfile);
17303         periodCount = (pDescriptorCapture->periodCount > 0) ? pDescriptorCapture->periodCount : MA_DEFAULT_PERIODS;
17304
17305         MA_ZERO_OBJECT(&descDS);
17306         descDS.dwSize        = sizeof(descDS);
17307         descDS.dwFlags       = 0;
17308         descDS.dwBufferBytes = periodSizeInFrames * periodCount * wf.Format.nBlockAlign;
17309         descDS.lpwfxFormat   = (WAVEFORMATEX*)&wf;
17310         hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL);
17311         if (FAILED(hr)) {
17312             ma_device_uninit__dsound(pDevice);
17313             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr));
17314         }
17315
17316         /* Get the _actual_ properties of the buffer. */
17317         pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
17318         hr = ma_IDirectSoundCaptureBuffer_GetFormat((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL);
17319         if (FAILED(hr)) {
17320             ma_device_uninit__dsound(pDevice);
17321             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the capture device's buffer.", ma_result_from_HRESULT(hr));
17322         }
17323
17324         /* We can now start setting the output data formats. */
17325         pDescriptorCapture->format     = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat);
17326         pDescriptorCapture->channels   = pActualFormat->Format.nChannels;
17327         pDescriptorCapture->sampleRate = pActualFormat->Format.nSamplesPerSec;
17328
17329         /* Get the native channel map based on the channel mask. */
17330         if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
17331             ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
17332         } else {
17333             ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
17334         }
17335
17336         /*
17337         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
17338         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.
17339         */
17340         if (periodSizeInFrames != (descDS.dwBufferBytes / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / periodCount)) {
17341             descDS.dwBufferBytes = periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * periodCount;
17342             ma_IDirectSoundCaptureBuffer_Release((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
17343
17344             hr = ma_IDirectSoundCapture_CreateCaptureBuffer((ma_IDirectSoundCapture*)pDevice->dsound.pCapture, &descDS, (ma_IDirectSoundCaptureBuffer**)&pDevice->dsound.pCaptureBuffer, NULL);
17345             if (FAILED(hr)) {
17346                 ma_device_uninit__dsound(pDevice);
17347                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Second attempt at IDirectSoundCapture_CreateCaptureBuffer() failed for capture device.", ma_result_from_HRESULT(hr));
17348             }
17349         }
17350
17351         /* DirectSound should give us a buffer exactly the size we asked for. */
17352         pDescriptorCapture->periodSizeInFrames = periodSizeInFrames;
17353         pDescriptorCapture->periodCount        = periodCount;
17354     }
17355
17356     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
17357         WAVEFORMATEXTENSIBLE wf;
17358         MA_DSBUFFERDESC descDSPrimary;
17359         MA_DSCAPS caps;
17360         char rawdata[1024]; /* <-- Ugly hack to avoid a malloc() due to a crappy DirectSound API. */
17361         WAVEFORMATEXTENSIBLE* pActualFormat;
17362         ma_uint32 periodSizeInFrames;
17363         ma_uint32 periodCount;
17364         MA_DSBUFFERDESC descDS;
17365
17366         result = ma_config_to_WAVEFORMATEXTENSIBLE(pDescriptorPlayback->format, pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, &wf);
17367         if (result != MA_SUCCESS) {
17368             return result;
17369         }
17370
17371         result = ma_context_create_IDirectSound__dsound(pDevice->pContext, pDescriptorPlayback->shareMode, pDescriptorPlayback->pDeviceID, (ma_IDirectSound**)&pDevice->dsound.pPlayback);
17372         if (result != MA_SUCCESS) {
17373             ma_device_uninit__dsound(pDevice);
17374             return result;
17375         }
17376
17377         MA_ZERO_OBJECT(&descDSPrimary);
17378         descDSPrimary.dwSize  = sizeof(MA_DSBUFFERDESC);
17379         descDSPrimary.dwFlags = MA_DSBCAPS_PRIMARYBUFFER | MA_DSBCAPS_CTRLVOLUME;
17380         hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDSPrimary, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackPrimaryBuffer, NULL);
17381         if (FAILED(hr)) {
17382             ma_device_uninit__dsound(pDevice);
17383             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's primary buffer.", ma_result_from_HRESULT(hr));
17384         }
17385
17386
17387         /* We may want to make some adjustments to the format if we are using defaults. */
17388         MA_ZERO_OBJECT(&caps);
17389         caps.dwSize = sizeof(caps);
17390         hr = ma_IDirectSound_GetCaps((ma_IDirectSound*)pDevice->dsound.pPlayback, &caps);
17391         if (FAILED(hr)) {
17392             ma_device_uninit__dsound(pDevice);
17393             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_GetCaps() failed for playback device.", ma_result_from_HRESULT(hr));
17394         }
17395
17396         if (pDescriptorPlayback->channels == 0) {
17397             if ((caps.dwFlags & MA_DSCAPS_PRIMARYSTEREO) != 0) {
17398                 DWORD speakerConfig;
17399
17400                 /* It supports at least stereo, but could support more. */
17401                 wf.Format.nChannels = 2;
17402
17403                 /* Look at the speaker configuration to get a better idea on the channel count. */
17404                 if (SUCCEEDED(ma_IDirectSound_GetSpeakerConfig((ma_IDirectSound*)pDevice->dsound.pPlayback, &speakerConfig))) {
17405                     ma_get_channels_from_speaker_config__dsound(speakerConfig, &wf.Format.nChannels, &wf.dwChannelMask);
17406                 }
17407             } else {
17408                 /* It does not support stereo, which means we are stuck with mono. */
17409                 wf.Format.nChannels = 1;
17410             }
17411         }
17412
17413         if (pDescriptorPlayback->sampleRate == 0) {
17414             /* We base the sample rate on the values returned by GetCaps(). */
17415             if ((caps.dwFlags & MA_DSCAPS_CONTINUOUSRATE) != 0) {
17416                 wf.Format.nSamplesPerSec = ma_get_best_sample_rate_within_range(caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate);
17417             } else {
17418                 wf.Format.nSamplesPerSec = caps.dwMaxSecondarySampleRate;
17419             }
17420         }
17421
17422         wf.Format.nBlockAlign     = (WORD)(wf.Format.nChannels * wf.Format.wBitsPerSample / 8);
17423         wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
17424
17425         /*
17426         From MSDN:
17427
17428         The method succeeds even if the hardware does not support the requested format; DirectSound sets the buffer to the closest
17429         supported format. To determine whether this has happened, an application can call the GetFormat method for the primary buffer
17430         and compare the result with the format that was requested with the SetFormat method.
17431         */
17432         hr = ma_IDirectSoundBuffer_SetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)&wf);
17433         if (FAILED(hr)) {
17434             ma_device_uninit__dsound(pDevice);
17435             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to set format of playback device's primary buffer.", ma_result_from_HRESULT(hr));
17436         }
17437
17438         /* Get the _actual_ properties of the buffer. */
17439         pActualFormat = (WAVEFORMATEXTENSIBLE*)rawdata;
17440         hr = ma_IDirectSoundBuffer_GetFormat((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackPrimaryBuffer, (WAVEFORMATEX*)pActualFormat, sizeof(rawdata), NULL);
17441         if (FAILED(hr)) {
17442             ma_device_uninit__dsound(pDevice);
17443             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to retrieve the actual format of the playback device's primary buffer.", ma_result_from_HRESULT(hr));
17444         }
17445
17446         /* We now have enough information to start setting some output properties. */
17447         pDescriptorPlayback->format     = ma_format_from_WAVEFORMATEX((WAVEFORMATEX*)pActualFormat);
17448         pDescriptorPlayback->channels   = pActualFormat->Format.nChannels;
17449         pDescriptorPlayback->sampleRate = pActualFormat->Format.nSamplesPerSec;
17450
17451         /* Get the internal channel map based on the channel mask. */
17452         if (pActualFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
17453             ma_channel_mask_to_channel_map__win32(pActualFormat->dwChannelMask, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
17454         } else {
17455             ma_channel_mask_to_channel_map__win32(wf.dwChannelMask, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
17456         }
17457
17458         /* The size of the buffer must be a clean multiple of the period count. */
17459         periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__dsound(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
17460         periodCount = (pDescriptorPlayback->periodCount > 0) ? pDescriptorPlayback->periodCount : MA_DEFAULT_PERIODS;
17461
17462         /*
17463         Meaning of dwFlags (from MSDN):
17464
17465         DSBCAPS_CTRLPOSITIONNOTIFY
17466           The buffer has position notification capability.
17467
17468         DSBCAPS_GLOBALFOCUS
17469           With this flag set, an application using DirectSound can continue to play its buffers if the user switches focus to
17470           another application, even if the new application uses DirectSound.
17471
17472         DSBCAPS_GETCURRENTPOSITION2
17473           In the first version of DirectSound, the play cursor was significantly ahead of the actual playing sound on emulated
17474           sound cards; it was directly behind the write cursor. Now, if the DSBCAPS_GETCURRENTPOSITION2 flag is specified, the
17475           application can get a more accurate play cursor.
17476         */
17477         MA_ZERO_OBJECT(&descDS);
17478         descDS.dwSize = sizeof(descDS);
17479         descDS.dwFlags = MA_DSBCAPS_CTRLPOSITIONNOTIFY | MA_DSBCAPS_GLOBALFOCUS | MA_DSBCAPS_GETCURRENTPOSITION2;
17480         descDS.dwBufferBytes = periodSizeInFrames * periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels);
17481         descDS.lpwfxFormat = (WAVEFORMATEX*)&wf;
17482         hr = ma_IDirectSound_CreateSoundBuffer((ma_IDirectSound*)pDevice->dsound.pPlayback, &descDS, (ma_IDirectSoundBuffer**)&pDevice->dsound.pPlaybackBuffer, NULL);
17483         if (FAILED(hr)) {
17484             ma_device_uninit__dsound(pDevice);
17485             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSound_CreateSoundBuffer() failed for playback device's secondary buffer.", ma_result_from_HRESULT(hr));
17486         }
17487
17488         /* DirectSound should give us a buffer exactly the size we asked for. */
17489         pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames;
17490         pDescriptorPlayback->periodCount        = periodCount;
17491     }
17492
17493     return MA_SUCCESS;
17494 }
17495
17496
17497 static ma_result ma_device_data_loop__dsound(ma_device* pDevice)
17498 {
17499     ma_result result = MA_SUCCESS;
17500     ma_uint32 bpfDeviceCapture  = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
17501     ma_uint32 bpfDevicePlayback = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
17502     HRESULT hr;
17503     DWORD lockOffsetInBytesCapture;
17504     DWORD lockSizeInBytesCapture;
17505     DWORD mappedSizeInBytesCapture;
17506     DWORD mappedDeviceFramesProcessedCapture;
17507     void* pMappedDeviceBufferCapture;
17508     DWORD lockOffsetInBytesPlayback;
17509     DWORD lockSizeInBytesPlayback;
17510     DWORD mappedSizeInBytesPlayback;
17511     void* pMappedDeviceBufferPlayback;
17512     DWORD prevReadCursorInBytesCapture = 0;
17513     DWORD prevPlayCursorInBytesPlayback = 0;
17514     ma_bool32 physicalPlayCursorLoopFlagPlayback = 0;
17515     DWORD virtualWriteCursorInBytesPlayback = 0;
17516     ma_bool32 virtualWriteCursorLoopFlagPlayback = 0;
17517     ma_bool32 isPlaybackDeviceStarted = MA_FALSE;
17518     ma_uint32 framesWrittenToPlaybackDevice = 0;   /* For knowing whether or not the playback device needs to be started. */
17519     ma_uint32 waitTimeInMilliseconds = 1;
17520
17521     MA_ASSERT(pDevice != NULL);
17522
17523     /* The first thing to do is start the capture device. The playback device is only started after the first period is written. */
17524     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
17525         if (FAILED(ma_IDirectSoundCaptureBuffer_Start((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, MA_DSCBSTART_LOOPING))) {
17526             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Start() failed.", MA_FAILED_TO_START_BACKEND_DEVICE);
17527         }
17528     }
17529
17530     while (ma_device_get_state(pDevice) == MA_STATE_STARTED) {
17531         switch (pDevice->type)
17532         {
17533             case ma_device_type_duplex:
17534             {
17535                 DWORD physicalCaptureCursorInBytes;
17536                 DWORD physicalReadCursorInBytes;
17537                 hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes);
17538                 if (FAILED(hr)) {
17539                     return ma_result_from_HRESULT(hr);
17540                 }
17541
17542                 /* If nothing is available we just sleep for a bit and return from this iteration. */
17543                 if (physicalReadCursorInBytes == prevReadCursorInBytesCapture) {
17544                     ma_sleep(waitTimeInMilliseconds);
17545                     continue; /* Nothing is available in the capture buffer. */
17546                 }
17547
17548                 /*
17549                 The current position has moved. We need to map all of the captured samples and write them to the playback device, making sure
17550                 we don't return until every frame has been copied over.
17551                 */
17552                 if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) {
17553                     /* The capture position has not looped. This is the simple case. */
17554                     lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
17555                     lockSizeInBytesCapture   = (physicalReadCursorInBytes - prevReadCursorInBytesCapture);
17556                 } else {
17557                     /*
17558                     The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything,
17559                     do it again from the start.
17560                     */
17561                     if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) {
17562                         /* Lock up to the end of the buffer. */
17563                         lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
17564                         lockSizeInBytesCapture   = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
17565                     } else {
17566                         /* Lock starting from the start of the buffer. */
17567                         lockOffsetInBytesCapture = 0;
17568                         lockSizeInBytesCapture   = physicalReadCursorInBytes;
17569                     }
17570                 }
17571
17572                 if (lockSizeInBytesCapture == 0) {
17573                     ma_sleep(waitTimeInMilliseconds);
17574                     continue; /* Nothing is available in the capture buffer. */
17575                 }
17576
17577                 hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
17578                 if (FAILED(hr)) {
17579                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
17580                 }
17581
17582
17583                 /* 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. */
17584                 mappedDeviceFramesProcessedCapture = 0;
17585
17586                 for (;;) {  /* Keep writing to the playback device. */
17587                     ma_uint8  inputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17588                     ma_uint32 inputFramesInClientFormatCap = sizeof(inputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels);
17589                     ma_uint8  outputFramesInClientFormat[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
17590                     ma_uint32 outputFramesInClientFormatCap = sizeof(outputFramesInClientFormat) / ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
17591                     ma_uint32 outputFramesInClientFormatCount;
17592                     ma_uint32 outputFramesInClientFormatConsumed = 0;
17593                     ma_uint64 clientCapturedFramesToProcess = ma_min(inputFramesInClientFormatCap, outputFramesInClientFormatCap);
17594                     ma_uint64 deviceCapturedFramesToProcess = (mappedSizeInBytesCapture / bpfDeviceCapture) - mappedDeviceFramesProcessedCapture;
17595                     void* pRunningMappedDeviceBufferCapture = ma_offset_ptr(pMappedDeviceBufferCapture, mappedDeviceFramesProcessedCapture * bpfDeviceCapture);
17596
17597                     result = ma_data_converter_process_pcm_frames(&pDevice->capture.converter, pRunningMappedDeviceBufferCapture, &deviceCapturedFramesToProcess, inputFramesInClientFormat, &clientCapturedFramesToProcess);
17598                     if (result != MA_SUCCESS) {
17599                         break;
17600                     }
17601
17602                     outputFramesInClientFormatCount     = (ma_uint32)clientCapturedFramesToProcess;
17603                     mappedDeviceFramesProcessedCapture += (ma_uint32)deviceCapturedFramesToProcess;
17604
17605                     ma_device__on_data(pDevice, outputFramesInClientFormat, inputFramesInClientFormat, (ma_uint32)clientCapturedFramesToProcess);
17606
17607                     /* 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. */
17608                     for (;;) {
17609                         ma_uint32 framesWrittenThisIteration;
17610                         DWORD physicalPlayCursorInBytes;
17611                         DWORD physicalWriteCursorInBytes;
17612                         DWORD availableBytesPlayback;
17613                         DWORD silentPaddingInBytes = 0; /* <-- Must be initialized to 0. */
17614
17615                         /* We need the physical play and write cursors. */
17616                         if (FAILED(ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes))) {
17617                             break;
17618                         }
17619
17620                         if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
17621                             physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
17622                         }
17623                         prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;
17624
17625                         /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
17626                         if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
17627                             /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
17628                             if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
17629                                 availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
17630                                 availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
17631                             } else {
17632                                 /* This is an error. */
17633                             #ifdef MA_DEBUG_OUTPUT
17634                                 printf("[DirectSound] (Duplex/Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
17635                             #endif
17636                                 availableBytesPlayback = 0;
17637                             }
17638                         } else {
17639                             /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
17640                             if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
17641                                 availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
17642                             } else {
17643                                 /* This is an error. */
17644                             #ifdef MA_DEBUG_OUTPUT
17645                                 printf("[DirectSound] (Duplex/Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
17646                             #endif
17647                                 availableBytesPlayback = 0;
17648                             }
17649                         }
17650
17651                     #ifdef MA_DEBUG_OUTPUT
17652                         /*printf("[DirectSound] (Duplex/Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
17653                     #endif
17654
17655                         /* If there's no room available for writing we need to wait for more. */
17656                         if (availableBytesPlayback == 0) {
17657                             /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
17658                             if (!isPlaybackDeviceStarted) {
17659                                 hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
17660                                 if (FAILED(hr)) {
17661                                     ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
17662                                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
17663                                 }
17664                                 isPlaybackDeviceStarted = MA_TRUE;
17665                             } else {
17666                                 ma_sleep(waitTimeInMilliseconds);
17667                                 continue;
17668                             }
17669                         }
17670
17671
17672                         /* 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. */
17673                         lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
17674                         if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
17675                             /* Same loop iteration. Go up to the end of the buffer. */
17676                             lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
17677                         } else {
17678                             /* Different loop iterations. Go up to the physical play cursor. */
17679                             lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
17680                         }
17681
17682                         hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
17683                         if (FAILED(hr)) {
17684                             result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
17685                             break;
17686                         }
17687
17688                         /*
17689                         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
17690                         endless glitching due to it constantly running out of data.
17691                         */
17692                         if (isPlaybackDeviceStarted) {
17693                             DWORD bytesQueuedForPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - availableBytesPlayback;
17694                             if (bytesQueuedForPlayback < (pDevice->playback.internalPeriodSizeInFrames*bpfDevicePlayback)) {
17695                                 silentPaddingInBytes   = (pDevice->playback.internalPeriodSizeInFrames*2*bpfDevicePlayback) - bytesQueuedForPlayback;
17696                                 if (silentPaddingInBytes > lockSizeInBytesPlayback) {
17697                                     silentPaddingInBytes = lockSizeInBytesPlayback;
17698                                 }
17699
17700                         #ifdef MA_DEBUG_OUTPUT
17701                                 printf("[DirectSound] (Duplex/Playback) Playback buffer starved. availableBytesPlayback=%ld, silentPaddingInBytes=%ld\n", availableBytesPlayback, silentPaddingInBytes);
17702                         #endif
17703                             }
17704                         }
17705
17706                         /* At this point we have a buffer for output. */
17707                         if (silentPaddingInBytes > 0) {
17708                             MA_ZERO_MEMORY(pMappedDeviceBufferPlayback, silentPaddingInBytes);
17709                             framesWrittenThisIteration = silentPaddingInBytes/bpfDevicePlayback;
17710                         } else {
17711                             ma_uint64 convertedFrameCountIn  = (outputFramesInClientFormatCount - outputFramesInClientFormatConsumed);
17712                             ma_uint64 convertedFrameCountOut = mappedSizeInBytesPlayback/bpfDevicePlayback;
17713                             void* pConvertedFramesIn  = ma_offset_ptr(outputFramesInClientFormat, outputFramesInClientFormatConsumed * bpfDevicePlayback);
17714                             void* pConvertedFramesOut = pMappedDeviceBufferPlayback;
17715
17716                             result = ma_data_converter_process_pcm_frames(&pDevice->playback.converter, pConvertedFramesIn, &convertedFrameCountIn, pConvertedFramesOut, &convertedFrameCountOut);
17717                             if (result != MA_SUCCESS) {
17718                                 break;
17719                             }
17720
17721                             outputFramesInClientFormatConsumed += (ma_uint32)convertedFrameCountOut;
17722                             framesWrittenThisIteration          = (ma_uint32)convertedFrameCountOut;
17723                         }
17724
17725
17726                         hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, framesWrittenThisIteration*bpfDevicePlayback, NULL, 0);
17727                         if (FAILED(hr)) {
17728                             result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
17729                             break;
17730                         }
17731
17732                         virtualWriteCursorInBytesPlayback += framesWrittenThisIteration*bpfDevicePlayback;
17733                         if ((virtualWriteCursorInBytesPlayback/bpfDevicePlayback) == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods) {
17734                             virtualWriteCursorInBytesPlayback  = 0;
17735                             virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
17736                         }
17737
17738                         /*
17739                         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
17740                         a bit of a buffer to prevent the playback buffer from getting starved.
17741                         */
17742                         framesWrittenToPlaybackDevice += framesWrittenThisIteration;
17743                         if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= (pDevice->playback.internalPeriodSizeInFrames*2)) {
17744                             hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
17745                             if (FAILED(hr)) {
17746                                 ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
17747                                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
17748                             }
17749                             isPlaybackDeviceStarted = MA_TRUE;
17750                         }
17751
17752                         if (framesWrittenThisIteration < mappedSizeInBytesPlayback/bpfDevicePlayback) {
17753                             break;  /* We're finished with the output data.*/
17754                         }
17755                     }
17756
17757                     if (clientCapturedFramesToProcess == 0) {
17758                         break;  /* We just consumed every input sample. */
17759                     }
17760                 }
17761
17762
17763                 /* At this point we're done with the mapped portion of the capture buffer. */
17764                 hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
17765                 if (FAILED(hr)) {
17766                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
17767                 }
17768                 prevReadCursorInBytesCapture = (lockOffsetInBytesCapture + mappedSizeInBytesCapture);
17769             } break;
17770
17771
17772
17773             case ma_device_type_capture:
17774             {
17775                 DWORD physicalCaptureCursorInBytes;
17776                 DWORD physicalReadCursorInBytes;
17777                 hr = ma_IDirectSoundCaptureBuffer_GetCurrentPosition((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, &physicalCaptureCursorInBytes, &physicalReadCursorInBytes);
17778                 if (FAILED(hr)) {
17779                     return MA_ERROR;
17780                 }
17781
17782                 /* If the previous capture position is the same as the current position we need to wait a bit longer. */
17783                 if (prevReadCursorInBytesCapture == physicalReadCursorInBytes) {
17784                     ma_sleep(waitTimeInMilliseconds);
17785                     continue;
17786                 }
17787
17788                 /* Getting here means we have capture data available. */
17789                 if (prevReadCursorInBytesCapture < physicalReadCursorInBytes) {
17790                     /* The capture position has not looped. This is the simple case. */
17791                     lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
17792                     lockSizeInBytesCapture   = (physicalReadCursorInBytes - prevReadCursorInBytesCapture);
17793                 } else {
17794                     /*
17795                     The capture position has looped. This is the more complex case. Map to the end of the buffer. If this does not return anything,
17796                     do it again from the start.
17797                     */
17798                     if (prevReadCursorInBytesCapture < pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) {
17799                         /* Lock up to the end of the buffer. */
17800                         lockOffsetInBytesCapture = prevReadCursorInBytesCapture;
17801                         lockSizeInBytesCapture   = (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture) - prevReadCursorInBytesCapture;
17802                     } else {
17803                         /* Lock starting from the start of the buffer. */
17804                         lockOffsetInBytesCapture = 0;
17805                         lockSizeInBytesCapture   = physicalReadCursorInBytes;
17806                     }
17807                 }
17808
17809             #ifdef MA_DEBUG_OUTPUT
17810                 /*printf("[DirectSound] (Capture) physicalCaptureCursorInBytes=%d, physicalReadCursorInBytes=%d\n", physicalCaptureCursorInBytes, physicalReadCursorInBytes);*/
17811                 /*printf("[DirectSound] (Capture) lockOffsetInBytesCapture=%d, lockSizeInBytesCapture=%d\n", lockOffsetInBytesCapture, lockSizeInBytesCapture);*/
17812             #endif
17813
17814                 if (lockSizeInBytesCapture < pDevice->capture.internalPeriodSizeInFrames) {
17815                     ma_sleep(waitTimeInMilliseconds);
17816                     continue; /* Nothing is available in the capture buffer. */
17817                 }
17818
17819                 hr = ma_IDirectSoundCaptureBuffer_Lock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, lockOffsetInBytesCapture, lockSizeInBytesCapture, &pMappedDeviceBufferCapture, &mappedSizeInBytesCapture, NULL, NULL, 0);
17820                 if (FAILED(hr)) {
17821                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from capture device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
17822                 }
17823
17824             #ifdef MA_DEBUG_OUTPUT
17825                 if (lockSizeInBytesCapture != mappedSizeInBytesCapture) {
17826                     printf("[DirectSound] (Capture) lockSizeInBytesCapture=%ld != mappedSizeInBytesCapture=%ld\n", lockSizeInBytesCapture, mappedSizeInBytesCapture);
17827                 }
17828             #endif
17829
17830                 ma_device__send_frames_to_client(pDevice, mappedSizeInBytesCapture/bpfDeviceCapture, pMappedDeviceBufferCapture);
17831
17832                 hr = ma_IDirectSoundCaptureBuffer_Unlock((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer, pMappedDeviceBufferCapture, mappedSizeInBytesCapture, NULL, 0);
17833                 if (FAILED(hr)) {
17834                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from capture device after reading from the device.", ma_result_from_HRESULT(hr));
17835                 }
17836                 prevReadCursorInBytesCapture = lockOffsetInBytesCapture + mappedSizeInBytesCapture;
17837
17838                 if (prevReadCursorInBytesCapture == (pDevice->capture.internalPeriodSizeInFrames*pDevice->capture.internalPeriods*bpfDeviceCapture)) {
17839                     prevReadCursorInBytesCapture = 0;
17840                 }
17841             } break;
17842
17843
17844
17845             case ma_device_type_playback:
17846             {
17847                 DWORD availableBytesPlayback;
17848                 DWORD physicalPlayCursorInBytes;
17849                 DWORD physicalWriteCursorInBytes;
17850                 hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
17851                 if (FAILED(hr)) {
17852                     break;
17853                 }
17854
17855                 if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
17856                     physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
17857                 }
17858                 prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;
17859
17860                 /* If there's any bytes available for writing we can do that now. The space between the virtual cursor position and play cursor. */
17861                 if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
17862                     /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
17863                     if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
17864                         availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
17865                         availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
17866                     } else {
17867                         /* This is an error. */
17868                     #ifdef MA_DEBUG_OUTPUT
17869                         printf("[DirectSound] (Playback) WARNING: Play cursor has moved in front of the write cursor (same loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
17870                     #endif
17871                         availableBytesPlayback = 0;
17872                     }
17873                 } else {
17874                     /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
17875                     if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
17876                         availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
17877                     } else {
17878                         /* This is an error. */
17879                     #ifdef MA_DEBUG_OUTPUT
17880                         printf("[DirectSound] (Playback) WARNING: Write cursor has moved behind the play cursor (different loop iterations). physicalPlayCursorInBytes=%ld, virtualWriteCursorInBytes=%ld.\n", physicalPlayCursorInBytes, virtualWriteCursorInBytesPlayback);
17881                     #endif
17882                         availableBytesPlayback = 0;
17883                     }
17884                 }
17885
17886             #ifdef MA_DEBUG_OUTPUT
17887                 /*printf("[DirectSound] (Playback) physicalPlayCursorInBytes=%d, availableBytesPlayback=%d\n", physicalPlayCursorInBytes, availableBytesPlayback);*/
17888             #endif
17889
17890                 /* If there's no room available for writing we need to wait for more. */
17891                 if (availableBytesPlayback < pDevice->playback.internalPeriodSizeInFrames) {
17892                     /* If we haven't started the device yet, this will never get beyond 0. In this case we need to get the device started. */
17893                     if (availableBytesPlayback == 0 && !isPlaybackDeviceStarted) {
17894                         hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
17895                         if (FAILED(hr)) {
17896                             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
17897                         }
17898                         isPlaybackDeviceStarted = MA_TRUE;
17899                     } else {
17900                         ma_sleep(waitTimeInMilliseconds);
17901                         continue;
17902                     }
17903                 }
17904
17905                 /* 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. */
17906                 lockOffsetInBytesPlayback = virtualWriteCursorInBytesPlayback;
17907                 if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
17908                     /* Same loop iteration. Go up to the end of the buffer. */
17909                     lockSizeInBytesPlayback = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
17910                 } else {
17911                     /* Different loop iterations. Go up to the physical play cursor. */
17912                     lockSizeInBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
17913                 }
17914
17915                 hr = ma_IDirectSoundBuffer_Lock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, lockOffsetInBytesPlayback, lockSizeInBytesPlayback, &pMappedDeviceBufferPlayback, &mappedSizeInBytesPlayback, NULL, NULL, 0);
17916                 if (FAILED(hr)) {
17917                     result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to map buffer from playback device in preparation for writing to the device.", ma_result_from_HRESULT(hr));
17918                     break;
17919                 }
17920
17921                 /* At this point we have a buffer for output. */
17922                 ma_device__read_frames_from_client(pDevice, (mappedSizeInBytesPlayback/bpfDevicePlayback), pMappedDeviceBufferPlayback);
17923
17924                 hr = ma_IDirectSoundBuffer_Unlock((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, pMappedDeviceBufferPlayback, mappedSizeInBytesPlayback, NULL, 0);
17925                 if (FAILED(hr)) {
17926                     result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] Failed to unlock internal buffer from playback device after writing to the device.", ma_result_from_HRESULT(hr));
17927                     break;
17928                 }
17929
17930                 virtualWriteCursorInBytesPlayback += mappedSizeInBytesPlayback;
17931                 if (virtualWriteCursorInBytesPlayback == pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) {
17932                     virtualWriteCursorInBytesPlayback  = 0;
17933                     virtualWriteCursorLoopFlagPlayback = !virtualWriteCursorLoopFlagPlayback;
17934                 }
17935
17936                 /*
17937                 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
17938                 a bit of a buffer to prevent the playback buffer from getting starved.
17939                 */
17940                 framesWrittenToPlaybackDevice += mappedSizeInBytesPlayback/bpfDevicePlayback;
17941                 if (!isPlaybackDeviceStarted && framesWrittenToPlaybackDevice >= pDevice->playback.internalPeriodSizeInFrames) {
17942                     hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING);
17943                     if (FAILED(hr)) {
17944                         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed.", ma_result_from_HRESULT(hr));
17945                     }
17946                     isPlaybackDeviceStarted = MA_TRUE;
17947                 }
17948             } break;
17949
17950
17951             default: return MA_INVALID_ARGS;   /* Invalid device type. */
17952         }
17953
17954         if (result != MA_SUCCESS) {
17955             return result;
17956         }
17957     }
17958
17959     /* Getting here means the device is being stopped. */
17960     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
17961         hr = ma_IDirectSoundCaptureBuffer_Stop((ma_IDirectSoundCaptureBuffer*)pDevice->dsound.pCaptureBuffer);
17962         if (FAILED(hr)) {
17963             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundCaptureBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
17964         }
17965     }
17966
17967     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
17968         /* 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. */
17969         if (isPlaybackDeviceStarted) {
17970             for (;;) {
17971                 DWORD availableBytesPlayback = 0;
17972                 DWORD physicalPlayCursorInBytes;
17973                 DWORD physicalWriteCursorInBytes;
17974                 hr = ma_IDirectSoundBuffer_GetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &physicalPlayCursorInBytes, &physicalWriteCursorInBytes);
17975                 if (FAILED(hr)) {
17976                     break;
17977                 }
17978
17979                 if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) {
17980                     physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback;
17981                 }
17982                 prevPlayCursorInBytesPlayback  = physicalPlayCursorInBytes;
17983
17984                 if (physicalPlayCursorLoopFlagPlayback == virtualWriteCursorLoopFlagPlayback) {
17985                     /* Same loop iteration. The available bytes wraps all the way around from the virtual write cursor to the physical play cursor. */
17986                     if (physicalPlayCursorInBytes <= virtualWriteCursorInBytesPlayback) {
17987                         availableBytesPlayback  = (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback) - virtualWriteCursorInBytesPlayback;
17988                         availableBytesPlayback += physicalPlayCursorInBytes;    /* Wrap around. */
17989                     } else {
17990                         break;
17991                     }
17992                 } else {
17993                     /* Different loop iterations. The available bytes only goes from the virtual write cursor to the physical play cursor. */
17994                     if (physicalPlayCursorInBytes >= virtualWriteCursorInBytesPlayback) {
17995                         availableBytesPlayback = physicalPlayCursorInBytes - virtualWriteCursorInBytesPlayback;
17996                     } else {
17997                         break;
17998                     }
17999                 }
18000
18001                 if (availableBytesPlayback >= (pDevice->playback.internalPeriodSizeInFrames*pDevice->playback.internalPeriods*bpfDevicePlayback)) {
18002                     break;
18003                 }
18004
18005                 ma_sleep(waitTimeInMilliseconds);
18006             }
18007         }
18008
18009         hr = ma_IDirectSoundBuffer_Stop((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer);
18010         if (FAILED(hr)) {
18011             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Stop() failed.", ma_result_from_HRESULT(hr));
18012         }
18013
18014         ma_IDirectSoundBuffer_SetCurrentPosition((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0);
18015     }
18016
18017     return MA_SUCCESS;
18018 }
18019
18020 static ma_result ma_context_uninit__dsound(ma_context* pContext)
18021 {
18022     MA_ASSERT(pContext != NULL);
18023     MA_ASSERT(pContext->backend == ma_backend_dsound);
18024
18025     ma_dlclose(pContext, pContext->dsound.hDSoundDLL);
18026
18027     return MA_SUCCESS;
18028 }
18029
18030 static ma_result ma_context_init__dsound(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
18031 {
18032     MA_ASSERT(pContext != NULL);
18033
18034     (void)pConfig;
18035
18036     pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll");
18037     if (pContext->dsound.hDSoundDLL == NULL) {
18038         return MA_API_NOT_FOUND;
18039     }
18040
18041     pContext->dsound.DirectSoundCreate            = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate");
18042     pContext->dsound.DirectSoundEnumerateA        = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA");
18043     pContext->dsound.DirectSoundCaptureCreate     = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate");
18044     pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA");
18045
18046     pCallbacks->onContextInit             = ma_context_init__dsound;
18047     pCallbacks->onContextUninit           = ma_context_uninit__dsound;
18048     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__dsound;
18049     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__dsound;
18050     pCallbacks->onDeviceInit              = ma_device_init__dsound;
18051     pCallbacks->onDeviceUninit            = ma_device_uninit__dsound;
18052     pCallbacks->onDeviceStart             = NULL;   /* Not used. Started in onDeviceDataLoop. */
18053     pCallbacks->onDeviceStop              = NULL;   /* Not used. Stopped in onDeviceDataLoop. */
18054     pCallbacks->onDeviceRead              = NULL;   /* Not used. Data is read directly in onDeviceDataLoop. */
18055     pCallbacks->onDeviceWrite             = NULL;   /* Not used. Data is written directly in onDeviceDataLoop. */
18056     pCallbacks->onDeviceDataLoop          = ma_device_data_loop__dsound;
18057
18058     return MA_SUCCESS;
18059 }
18060 #endif
18061
18062
18063
18064 /******************************************************************************
18065
18066 WinMM Backend
18067
18068 ******************************************************************************/
18069 #ifdef MA_HAS_WINMM
18070
18071 /*
18072 Some older compilers don't have WAVEOUTCAPS2A and WAVEINCAPS2A, so we'll need to write this ourselves. These structures
18073 are exactly the same as the older ones but they have a few GUIDs for manufacturer/product/name identification. I'm keeping
18074 the names the same as the Win32 library for consistency, but namespaced to avoid naming conflicts with the Win32 version.
18075 */
18076 typedef struct
18077 {
18078     WORD wMid;
18079     WORD wPid;
18080     MMVERSION vDriverVersion;
18081     CHAR szPname[MAXPNAMELEN];
18082     DWORD dwFormats;
18083     WORD wChannels;
18084     WORD wReserved1;
18085     DWORD dwSupport;
18086     GUID ManufacturerGuid;
18087     GUID ProductGuid;
18088     GUID NameGuid;
18089 } MA_WAVEOUTCAPS2A;
18090 typedef struct
18091 {
18092     WORD wMid;
18093     WORD wPid;
18094     MMVERSION vDriverVersion;
18095     CHAR szPname[MAXPNAMELEN];
18096     DWORD dwFormats;
18097     WORD wChannels;
18098     WORD wReserved1;
18099     GUID ManufacturerGuid;
18100     GUID ProductGuid;
18101     GUID NameGuid;
18102 } MA_WAVEINCAPS2A;
18103
18104 typedef UINT     (WINAPI * MA_PFN_waveOutGetNumDevs)(void);
18105 typedef MMRESULT (WINAPI * MA_PFN_waveOutGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEOUTCAPSA pwoc, UINT cbwoc);
18106 typedef MMRESULT (WINAPI * MA_PFN_waveOutOpen)(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
18107 typedef MMRESULT (WINAPI * MA_PFN_waveOutClose)(HWAVEOUT hwo);
18108 typedef MMRESULT (WINAPI * MA_PFN_waveOutPrepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
18109 typedef MMRESULT (WINAPI * MA_PFN_waveOutUnprepareHeader)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
18110 typedef MMRESULT (WINAPI * MA_PFN_waveOutWrite)(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);
18111 typedef MMRESULT (WINAPI * MA_PFN_waveOutReset)(HWAVEOUT hwo);
18112 typedef UINT     (WINAPI * MA_PFN_waveInGetNumDevs)(void);
18113 typedef MMRESULT (WINAPI * MA_PFN_waveInGetDevCapsA)(ma_uintptr uDeviceID, LPWAVEINCAPSA pwic, UINT cbwic);
18114 typedef MMRESULT (WINAPI * MA_PFN_waveInOpen)(LPHWAVEIN phwi, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen);
18115 typedef MMRESULT (WINAPI * MA_PFN_waveInClose)(HWAVEIN hwi);
18116 typedef MMRESULT (WINAPI * MA_PFN_waveInPrepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
18117 typedef MMRESULT (WINAPI * MA_PFN_waveInUnprepareHeader)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
18118 typedef MMRESULT (WINAPI * MA_PFN_waveInAddBuffer)(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);
18119 typedef MMRESULT (WINAPI * MA_PFN_waveInStart)(HWAVEIN hwi);
18120 typedef MMRESULT (WINAPI * MA_PFN_waveInReset)(HWAVEIN hwi);
18121
18122 static ma_result ma_result_from_MMRESULT(MMRESULT resultMM)
18123 {
18124     switch (resultMM) {
18125         case MMSYSERR_NOERROR:      return MA_SUCCESS;
18126         case MMSYSERR_BADDEVICEID:  return MA_INVALID_ARGS;
18127         case MMSYSERR_INVALHANDLE:  return MA_INVALID_ARGS;
18128         case MMSYSERR_NOMEM:        return MA_OUT_OF_MEMORY;
18129         case MMSYSERR_INVALFLAG:    return MA_INVALID_ARGS;
18130         case MMSYSERR_INVALPARAM:   return MA_INVALID_ARGS;
18131         case MMSYSERR_HANDLEBUSY:   return MA_BUSY;
18132         case MMSYSERR_ERROR:        return MA_ERROR;
18133         default:                    return MA_ERROR;
18134     }
18135 }
18136
18137 static char* ma_find_last_character(char* str, char ch)
18138 {
18139     char* last;
18140
18141     if (str == NULL) {
18142         return NULL;
18143     }
18144
18145     last = NULL;
18146     while (*str != '\0') {
18147         if (*str == ch) {
18148             last = str;
18149         }
18150
18151         str += 1;
18152     }
18153
18154     return last;
18155 }
18156
18157 static ma_uint32 ma_get_period_size_in_bytes(ma_uint32 periodSizeInFrames, ma_format format, ma_uint32 channels)
18158 {
18159     return periodSizeInFrames * ma_get_bytes_per_frame(format, channels);
18160 }
18161
18162
18163 /*
18164 Our own "WAVECAPS" structure that contains generic information shared between WAVEOUTCAPS2 and WAVEINCAPS2 so
18165 we can do things generically and typesafely. Names are being kept the same for consistency.
18166 */
18167 typedef struct
18168 {
18169     CHAR szPname[MAXPNAMELEN];
18170     DWORD dwFormats;
18171     WORD wChannels;
18172     GUID NameGuid;
18173 } MA_WAVECAPSA;
18174
18175 static ma_result ma_get_best_info_from_formats_flags__winmm(DWORD dwFormats, WORD channels, WORD* pBitsPerSample, DWORD* pSampleRate)
18176 {
18177     WORD bitsPerSample = 0;
18178     DWORD sampleRate = 0;
18179
18180     if (pBitsPerSample) {
18181         *pBitsPerSample = 0;
18182     }
18183     if (pSampleRate) {
18184         *pSampleRate = 0;
18185     }
18186
18187     if (channels == 1) {
18188         bitsPerSample = 16;
18189         if ((dwFormats & WAVE_FORMAT_48M16) != 0) {
18190             sampleRate = 48000;
18191         } else if ((dwFormats & WAVE_FORMAT_44M16) != 0) {
18192             sampleRate = 44100;
18193         } else if ((dwFormats & WAVE_FORMAT_2M16) != 0) {
18194             sampleRate = 22050;
18195         } else if ((dwFormats & WAVE_FORMAT_1M16) != 0) {
18196             sampleRate = 11025;
18197         } else if ((dwFormats & WAVE_FORMAT_96M16) != 0) {
18198             sampleRate = 96000;
18199         } else {
18200             bitsPerSample = 8;
18201             if ((dwFormats & WAVE_FORMAT_48M08) != 0) {
18202                 sampleRate = 48000;
18203             } else if ((dwFormats & WAVE_FORMAT_44M08) != 0) {
18204                 sampleRate = 44100;
18205             } else if ((dwFormats & WAVE_FORMAT_2M08) != 0) {
18206                 sampleRate = 22050;
18207             } else if ((dwFormats & WAVE_FORMAT_1M08) != 0) {
18208                 sampleRate = 11025;
18209             } else if ((dwFormats & WAVE_FORMAT_96M08) != 0) {
18210                 sampleRate = 96000;
18211             } else {
18212                 return MA_FORMAT_NOT_SUPPORTED;
18213             }
18214         }
18215     } else {
18216         bitsPerSample = 16;
18217         if ((dwFormats & WAVE_FORMAT_48S16) != 0) {
18218             sampleRate = 48000;
18219         } else if ((dwFormats & WAVE_FORMAT_44S16) != 0) {
18220             sampleRate = 44100;
18221         } else if ((dwFormats & WAVE_FORMAT_2S16) != 0) {
18222             sampleRate = 22050;
18223         } else if ((dwFormats & WAVE_FORMAT_1S16) != 0) {
18224             sampleRate = 11025;
18225         } else if ((dwFormats & WAVE_FORMAT_96S16) != 0) {
18226             sampleRate = 96000;
18227         } else {
18228             bitsPerSample = 8;
18229             if ((dwFormats & WAVE_FORMAT_48S08) != 0) {
18230                 sampleRate = 48000;
18231             } else if ((dwFormats & WAVE_FORMAT_44S08) != 0) {
18232                 sampleRate = 44100;
18233             } else if ((dwFormats & WAVE_FORMAT_2S08) != 0) {
18234                 sampleRate = 22050;
18235             } else if ((dwFormats & WAVE_FORMAT_1S08) != 0) {
18236                 sampleRate = 11025;
18237             } else if ((dwFormats & WAVE_FORMAT_96S08) != 0) {
18238                 sampleRate = 96000;
18239             } else {
18240                 return MA_FORMAT_NOT_SUPPORTED;
18241             }
18242         }
18243     }
18244
18245     if (pBitsPerSample) {
18246         *pBitsPerSample = bitsPerSample;
18247     }
18248     if (pSampleRate) {
18249         *pSampleRate = sampleRate;
18250     }
18251
18252     return MA_SUCCESS;
18253 }
18254
18255 static ma_result ma_formats_flags_to_WAVEFORMATEX__winmm(DWORD dwFormats, WORD channels, WAVEFORMATEX* pWF)
18256 {
18257     ma_result result;
18258
18259     MA_ASSERT(pWF != NULL);
18260
18261     MA_ZERO_OBJECT(pWF);
18262     pWF->cbSize     = sizeof(*pWF);
18263     pWF->wFormatTag = WAVE_FORMAT_PCM;
18264     pWF->nChannels  = (WORD)channels;
18265     if (pWF->nChannels > 2) {
18266         pWF->nChannels = 2;
18267     }
18268
18269     result = ma_get_best_info_from_formats_flags__winmm(dwFormats, channels, &pWF->wBitsPerSample, &pWF->nSamplesPerSec);
18270     if (result != MA_SUCCESS) {
18271         return result;
18272     }
18273
18274     pWF->nBlockAlign     = (WORD)(pWF->nChannels * pWF->wBitsPerSample / 8);
18275     pWF->nAvgBytesPerSec = pWF->nBlockAlign * pWF->nSamplesPerSec;
18276
18277     return MA_SUCCESS;
18278 }
18279
18280 static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, MA_WAVECAPSA* pCaps, ma_device_info* pDeviceInfo)
18281 {
18282     WORD bitsPerSample;
18283     DWORD sampleRate;
18284     ma_result result;
18285
18286     MA_ASSERT(pContext != NULL);
18287     MA_ASSERT(pCaps != NULL);
18288     MA_ASSERT(pDeviceInfo != NULL);
18289
18290     /*
18291     Name / Description
18292
18293     Unfortunately the name specified in WAVE(OUT/IN)CAPS2 is limited to 31 characters. This results in an unprofessional looking
18294     situation where the names of the devices are truncated. To help work around this, we need to look at the name GUID and try
18295     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.
18296     */
18297
18298     /* Set the default to begin with. */
18299     ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), pCaps->szPname, (size_t)-1);
18300
18301     /*
18302     Now try the registry. There's a few things to consider here:
18303     - The name GUID can be null, in which we case we just need to stick to the original 31 characters.
18304     - If the name GUID is not present in the registry we'll also need to stick to the original 31 characters.
18305     - I like consistency, so I want the returned device names to be consistent with those returned by WASAPI and DirectSound. The
18306       problem, however is that WASAPI and DirectSound use "<component> (<name>)" format (such as "Speakers (High Definition Audio)"),
18307       but WinMM does not specificy the component name. From my admittedly limited testing, I've notice the component name seems to
18308       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
18309       name, and then concatenate the name from the registry.
18310     */
18311     if (!ma_is_guid_null(&pCaps->NameGuid)) {
18312         wchar_t guidStrW[256];
18313         if (((MA_PFN_StringFromGUID2)pContext->win32.StringFromGUID2)(&pCaps->NameGuid, guidStrW, ma_countof(guidStrW)) > 0) {
18314             char guidStr[256];
18315             char keyStr[1024];
18316             HKEY hKey;
18317
18318             WideCharToMultiByte(CP_UTF8, 0, guidStrW, -1, guidStr, sizeof(guidStr), 0, FALSE);
18319
18320             ma_strcpy_s(keyStr, sizeof(keyStr), "SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\");
18321             ma_strcat_s(keyStr, sizeof(keyStr), guidStr);
18322
18323             if (((MA_PFN_RegOpenKeyExA)pContext->win32.RegOpenKeyExA)(HKEY_LOCAL_MACHINE, keyStr, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
18324                 BYTE nameFromReg[512];
18325                 DWORD nameFromRegSize = sizeof(nameFromReg);
18326                 result = ((MA_PFN_RegQueryValueExA)pContext->win32.RegQueryValueExA)(hKey, "Name", 0, NULL, (LPBYTE)nameFromReg, (LPDWORD)&nameFromRegSize);
18327                 ((MA_PFN_RegCloseKey)pContext->win32.RegCloseKey)(hKey);
18328
18329                 if (result == ERROR_SUCCESS) {
18330                     /* We have the value from the registry, so now we need to construct the name string. */
18331                     char name[1024];
18332                     if (ma_strcpy_s(name, sizeof(name), pDeviceInfo->name) == 0) {
18333                         char* nameBeg = ma_find_last_character(name, '(');
18334                         if (nameBeg != NULL) {
18335                             size_t leadingLen = (nameBeg - name);
18336                             ma_strncpy_s(nameBeg + 1, sizeof(name) - leadingLen, (const char*)nameFromReg, (size_t)-1);
18337
18338                             /* The closing ")", if it can fit. */
18339                             if (leadingLen + nameFromRegSize < sizeof(name)-1) {
18340                                 ma_strcat_s(name, sizeof(name), ")");
18341                             }
18342
18343                             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), name, (size_t)-1);
18344                         }
18345                     }
18346                 }
18347             }
18348         }
18349     }
18350
18351
18352     result = ma_get_best_info_from_formats_flags__winmm(pCaps->dwFormats, pCaps->wChannels, &bitsPerSample, &sampleRate);
18353     if (result != MA_SUCCESS) {
18354         return result;
18355     }
18356
18357     if (bitsPerSample == 8) {
18358         pDeviceInfo->nativeDataFormats[0].format = ma_format_u8;
18359     } else if (bitsPerSample == 16) {
18360         pDeviceInfo->nativeDataFormats[0].format = ma_format_s16;
18361     } else if (bitsPerSample == 24) {
18362         pDeviceInfo->nativeDataFormats[0].format = ma_format_s24;
18363     } else if (bitsPerSample == 32) {
18364         pDeviceInfo->nativeDataFormats[0].format = ma_format_s32;
18365     } else {
18366         return MA_FORMAT_NOT_SUPPORTED;
18367     }
18368     pDeviceInfo->nativeDataFormats[0].channels   = pCaps->wChannels;
18369     pDeviceInfo->nativeDataFormats[0].sampleRate = sampleRate;
18370     pDeviceInfo->nativeDataFormats[0].flags      = 0;
18371     pDeviceInfo->nativeDataFormatCount = 1;
18372
18373     return MA_SUCCESS;
18374 }
18375
18376 static ma_result ma_context_get_device_info_from_WAVEOUTCAPS2(ma_context* pContext, MA_WAVEOUTCAPS2A* pCaps, ma_device_info* pDeviceInfo)
18377 {
18378     MA_WAVECAPSA caps;
18379
18380     MA_ASSERT(pContext != NULL);
18381     MA_ASSERT(pCaps != NULL);
18382     MA_ASSERT(pDeviceInfo != NULL);
18383
18384     MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
18385     caps.dwFormats = pCaps->dwFormats;
18386     caps.wChannels = pCaps->wChannels;
18387     caps.NameGuid  = pCaps->NameGuid;
18388     return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
18389 }
18390
18391 static ma_result ma_context_get_device_info_from_WAVEINCAPS2(ma_context* pContext, MA_WAVEINCAPS2A* pCaps, ma_device_info* pDeviceInfo)
18392 {
18393     MA_WAVECAPSA caps;
18394
18395     MA_ASSERT(pContext != NULL);
18396     MA_ASSERT(pCaps != NULL);
18397     MA_ASSERT(pDeviceInfo != NULL);
18398
18399     MA_COPY_MEMORY(caps.szPname, pCaps->szPname, sizeof(caps.szPname));
18400     caps.dwFormats = pCaps->dwFormats;
18401     caps.wChannels = pCaps->wChannels;
18402     caps.NameGuid  = pCaps->NameGuid;
18403     return ma_context_get_device_info_from_WAVECAPS(pContext, &caps, pDeviceInfo);
18404 }
18405
18406
18407 static ma_result ma_context_enumerate_devices__winmm(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
18408 {
18409     UINT playbackDeviceCount;
18410     UINT captureDeviceCount;
18411     UINT iPlaybackDevice;
18412     UINT iCaptureDevice;
18413
18414     MA_ASSERT(pContext != NULL);
18415     MA_ASSERT(callback != NULL);
18416
18417     /* Playback. */
18418     playbackDeviceCount = ((MA_PFN_waveOutGetNumDevs)pContext->winmm.waveOutGetNumDevs)();
18419     for (iPlaybackDevice = 0; iPlaybackDevice < playbackDeviceCount; ++iPlaybackDevice) {
18420         MMRESULT result;
18421         MA_WAVEOUTCAPS2A caps;
18422
18423         MA_ZERO_OBJECT(&caps);
18424
18425         result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(iPlaybackDevice, (WAVEOUTCAPSA*)&caps, sizeof(caps));
18426         if (result == MMSYSERR_NOERROR) {
18427             ma_device_info deviceInfo;
18428
18429             MA_ZERO_OBJECT(&deviceInfo);
18430             deviceInfo.id.winmm = iPlaybackDevice;
18431
18432             /* The first enumerated device is the default device. */
18433             if (iPlaybackDevice == 0) {
18434                 deviceInfo.isDefault = MA_TRUE;
18435             }
18436
18437             if (ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) {
18438                 ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
18439                 if (cbResult == MA_FALSE) {
18440                     return MA_SUCCESS; /* Enumeration was stopped. */
18441                 }
18442             }
18443         }
18444     }
18445
18446     /* Capture. */
18447     captureDeviceCount = ((MA_PFN_waveInGetNumDevs)pContext->winmm.waveInGetNumDevs)();
18448     for (iCaptureDevice = 0; iCaptureDevice < captureDeviceCount; ++iCaptureDevice) {
18449         MMRESULT result;
18450         MA_WAVEINCAPS2A caps;
18451
18452         MA_ZERO_OBJECT(&caps);
18453
18454         result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(iCaptureDevice, (WAVEINCAPSA*)&caps, sizeof(caps));
18455         if (result == MMSYSERR_NOERROR) {
18456             ma_device_info deviceInfo;
18457
18458             MA_ZERO_OBJECT(&deviceInfo);
18459             deviceInfo.id.winmm = iCaptureDevice;
18460
18461             /* The first enumerated device is the default device. */
18462             if (iCaptureDevice == 0) {
18463                 deviceInfo.isDefault = MA_TRUE;
18464             }
18465
18466             if (ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, &deviceInfo) == MA_SUCCESS) {
18467                 ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
18468                 if (cbResult == MA_FALSE) {
18469                     return MA_SUCCESS; /* Enumeration was stopped. */
18470                 }
18471             }
18472         }
18473     }
18474
18475     return MA_SUCCESS;
18476 }
18477
18478 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)
18479 {
18480     UINT winMMDeviceID;
18481
18482     MA_ASSERT(pContext != NULL);
18483
18484     winMMDeviceID = 0;
18485     if (pDeviceID != NULL) {
18486         winMMDeviceID = (UINT)pDeviceID->winmm;
18487     }
18488
18489     pDeviceInfo->id.winmm = winMMDeviceID;
18490
18491     /* The first ID is the default device. */
18492     if (winMMDeviceID == 0) {
18493         pDeviceInfo->isDefault = MA_TRUE;
18494     }
18495
18496     if (deviceType == ma_device_type_playback) {
18497         MMRESULT result;
18498         MA_WAVEOUTCAPS2A caps;
18499
18500         MA_ZERO_OBJECT(&caps);
18501
18502         result = ((MA_PFN_waveOutGetDevCapsA)pContext->winmm.waveOutGetDevCapsA)(winMMDeviceID, (WAVEOUTCAPSA*)&caps, sizeof(caps));
18503         if (result == MMSYSERR_NOERROR) {
18504             return ma_context_get_device_info_from_WAVEOUTCAPS2(pContext, &caps, pDeviceInfo);
18505         }
18506     } else {
18507         MMRESULT result;
18508         MA_WAVEINCAPS2A caps;
18509
18510         MA_ZERO_OBJECT(&caps);
18511
18512         result = ((MA_PFN_waveInGetDevCapsA)pContext->winmm.waveInGetDevCapsA)(winMMDeviceID, (WAVEINCAPSA*)&caps, sizeof(caps));
18513         if (result == MMSYSERR_NOERROR) {
18514             return ma_context_get_device_info_from_WAVEINCAPS2(pContext, &caps, pDeviceInfo);
18515         }
18516     }
18517
18518     return MA_NO_DEVICE;
18519 }
18520
18521
18522 static ma_result ma_device_uninit__winmm(ma_device* pDevice)
18523 {
18524     MA_ASSERT(pDevice != NULL);
18525
18526     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
18527         ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
18528         CloseHandle((HANDLE)pDevice->winmm.hEventCapture);
18529     }
18530
18531     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
18532         ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
18533         ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
18534         CloseHandle((HANDLE)pDevice->winmm.hEventPlayback);
18535     }
18536
18537     ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
18538
18539     MA_ZERO_OBJECT(&pDevice->winmm);   /* Safety. */
18540
18541     return MA_SUCCESS;
18542 }
18543
18544 static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__winmm(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
18545 {
18546     /* WinMM has a minimum period size of 40ms. */
18547     ma_uint32 minPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(40, nativeSampleRate);
18548     ma_uint32 periodSizeInFrames;
18549
18550     periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, nativeSampleRate, performanceProfile);
18551     if (periodSizeInFrames < minPeriodSizeInFrames) {
18552         periodSizeInFrames = minPeriodSizeInFrames;
18553     }
18554
18555     return periodSizeInFrames;
18556 }
18557
18558 static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
18559 {
18560     const char* errorMsg = "";
18561     ma_result errorCode = MA_ERROR;
18562     ma_result result = MA_SUCCESS;
18563     ma_uint32 heapSize;
18564     UINT winMMDeviceIDPlayback = 0;
18565     UINT winMMDeviceIDCapture  = 0;
18566
18567     MA_ASSERT(pDevice != NULL);
18568
18569     MA_ZERO_OBJECT(&pDevice->winmm);
18570
18571     if (pConfig->deviceType == ma_device_type_loopback) {
18572         return MA_DEVICE_TYPE_NOT_SUPPORTED;
18573     }
18574
18575     /* No exlusive mode with WinMM. */
18576     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
18577         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
18578         return MA_SHARE_MODE_NOT_SUPPORTED;
18579     }
18580
18581     if (pDescriptorPlayback->pDeviceID != NULL) {
18582         winMMDeviceIDPlayback = (UINT)pDescriptorPlayback->pDeviceID->winmm;
18583     }
18584     if (pDescriptorCapture->pDeviceID != NULL) {
18585         winMMDeviceIDCapture = (UINT)pDescriptorCapture->pDeviceID->winmm;
18586     }
18587
18588     /* The capture device needs to be initialized first. */
18589     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
18590         WAVEINCAPSA caps;
18591         WAVEFORMATEX wf;
18592         MMRESULT resultMM;
18593
18594         /* We use an event to know when a new fragment needs to be enqueued. */
18595         pDevice->winmm.hEventCapture = (ma_handle)CreateEventW(NULL, TRUE, TRUE, NULL);
18596         if (pDevice->winmm.hEventCapture == NULL) {
18597             errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError());
18598             goto on_error;
18599         }
18600
18601         /* The format should be based on the device's actual format. */
18602         if (((MA_PFN_waveInGetDevCapsA)pDevice->pContext->winmm.waveInGetDevCapsA)(winMMDeviceIDCapture, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
18603             errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
18604             goto on_error;
18605         }
18606
18607         result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
18608         if (result != MA_SUCCESS) {
18609             errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
18610             goto on_error;
18611         }
18612
18613         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);
18614         if (resultMM != MMSYSERR_NOERROR) {
18615             errorMsg = "[WinMM] Failed to open capture device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
18616             goto on_error;
18617         }
18618
18619         pDescriptorCapture->format             = ma_format_from_WAVEFORMATEX(&wf);
18620         pDescriptorCapture->channels           = wf.nChannels;
18621         pDescriptorCapture->sampleRate         = wf.nSamplesPerSec;
18622         ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
18623         pDescriptorCapture->periodCount        = pDescriptorCapture->periodCount;
18624         pDescriptorCapture->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
18625     }
18626
18627     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
18628         WAVEOUTCAPSA caps;
18629         WAVEFORMATEX wf;
18630         MMRESULT resultMM;
18631
18632         /* We use an event to know when a new fragment needs to be enqueued. */
18633         pDevice->winmm.hEventPlayback = (ma_handle)CreateEvent(NULL, TRUE, TRUE, NULL);
18634         if (pDevice->winmm.hEventPlayback == NULL) {
18635             errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError());
18636             goto on_error;
18637         }
18638
18639         /* The format should be based on the device's actual format. */
18640         if (((MA_PFN_waveOutGetDevCapsA)pDevice->pContext->winmm.waveOutGetDevCapsA)(winMMDeviceIDPlayback, &caps, sizeof(caps)) != MMSYSERR_NOERROR) {
18641             errorMsg = "[WinMM] Failed to retrieve internal device caps.", errorCode = MA_FORMAT_NOT_SUPPORTED;
18642             goto on_error;
18643         }
18644
18645         result = ma_formats_flags_to_WAVEFORMATEX__winmm(caps.dwFormats, caps.wChannels, &wf);
18646         if (result != MA_SUCCESS) {
18647             errorMsg = "[WinMM] Could not find appropriate format for internal device.", errorCode = result;
18648             goto on_error;
18649         }
18650
18651         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);
18652         if (resultMM != MMSYSERR_NOERROR) {
18653             errorMsg = "[WinMM] Failed to open playback device.", errorCode = MA_FAILED_TO_OPEN_BACKEND_DEVICE;
18654             goto on_error;
18655         }
18656
18657         pDescriptorPlayback->format             = ma_format_from_WAVEFORMATEX(&wf);
18658         pDescriptorPlayback->channels           = wf.nChannels;
18659         pDescriptorPlayback->sampleRate         = wf.nSamplesPerSec;
18660         ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
18661         pDescriptorPlayback->periodCount        = pDescriptorPlayback->periodCount;
18662         pDescriptorPlayback->periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__winmm(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
18663     }
18664
18665     /*
18666     The heap allocated data is allocated like so:
18667
18668     [Capture WAVEHDRs][Playback WAVEHDRs][Capture Intermediary Buffer][Playback Intermediary Buffer]
18669     */
18670     heapSize = 0;
18671     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
18672         heapSize += sizeof(WAVEHDR)*pDescriptorCapture->periodCount + (pDescriptorCapture->periodSizeInFrames * pDescriptorCapture->periodCount * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels));
18673     }
18674     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
18675         heapSize += sizeof(WAVEHDR)*pDescriptorPlayback->periodCount + (pDescriptorPlayback->periodSizeInFrames * pDescriptorPlayback->periodCount * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels));
18676     }
18677
18678     pDevice->winmm._pHeapData = (ma_uint8*)ma__calloc_from_callbacks(heapSize, &pDevice->pContext->allocationCallbacks);
18679     if (pDevice->winmm._pHeapData == NULL) {
18680         errorMsg = "[WinMM] Failed to allocate memory for the intermediary buffer.", errorCode = MA_OUT_OF_MEMORY;
18681         goto on_error;
18682     }
18683
18684     MA_ZERO_MEMORY(pDevice->winmm._pHeapData, heapSize);
18685
18686     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
18687         ma_uint32 iPeriod;
18688
18689         if (pConfig->deviceType == ma_device_type_capture) {
18690             pDevice->winmm.pWAVEHDRCapture            = pDevice->winmm._pHeapData;
18691             pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount));
18692         } else {
18693             pDevice->winmm.pWAVEHDRCapture            = pDevice->winmm._pHeapData;
18694             pDevice->winmm.pIntermediaryBufferCapture = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount + pDescriptorPlayback->periodCount));
18695         }
18696
18697         /* Prepare headers. */
18698         for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) {
18699             ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->format, pDescriptorCapture->channels);
18700
18701             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].lpData         = (LPSTR)(pDevice->winmm.pIntermediaryBufferCapture + (periodSizeInBytes*iPeriod));
18702             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwBufferLength = periodSizeInBytes;
18703             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwFlags        = 0L;
18704             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwLoops        = 0L;
18705             ((MA_PFN_waveInPrepareHeader)pDevice->pContext->winmm.waveInPrepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
18706
18707             /*
18708             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
18709             it's unlocked and available for writing. A value of 1 means it's locked.
18710             */
18711             ((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod].dwUser = 0;
18712         }
18713     }
18714
18715     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
18716         ma_uint32 iPeriod;
18717
18718         if (pConfig->deviceType == ma_device_type_playback) {
18719             pDevice->winmm.pWAVEHDRPlayback            = pDevice->winmm._pHeapData;
18720             pDevice->winmm.pIntermediaryBufferPlayback = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*pDescriptorPlayback->periodCount);
18721         } else {
18722             pDevice->winmm.pWAVEHDRPlayback            = pDevice->winmm._pHeapData + (sizeof(WAVEHDR)*(pDescriptorCapture->periodCount));
18723             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));
18724         }
18725
18726         /* Prepare headers. */
18727         for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) {
18728             ma_uint32 periodSizeInBytes = ma_get_period_size_in_bytes(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->format, pDescriptorPlayback->channels);
18729
18730             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].lpData         = (LPSTR)(pDevice->winmm.pIntermediaryBufferPlayback + (periodSizeInBytes*iPeriod));
18731             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwBufferLength = periodSizeInBytes;
18732             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwFlags        = 0L;
18733             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwLoops        = 0L;
18734             ((MA_PFN_waveOutPrepareHeader)pDevice->pContext->winmm.waveOutPrepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
18735
18736             /*
18737             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
18738             it's unlocked and available for writing. A value of 1 means it's locked.
18739             */
18740             ((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod].dwUser = 0;
18741         }
18742     }
18743
18744     return MA_SUCCESS;
18745
18746 on_error:
18747     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
18748         if (pDevice->winmm.pWAVEHDRCapture != NULL) {
18749             ma_uint32 iPeriod;
18750             for (iPeriod = 0; iPeriod < pDescriptorCapture->periodCount; ++iPeriod) {
18751                 ((MA_PFN_waveInUnprepareHeader)pDevice->pContext->winmm.waveInUnprepareHeader)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((WAVEHDR*)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
18752             }
18753         }
18754
18755         ((MA_PFN_waveInClose)pDevice->pContext->winmm.waveInClose)((HWAVEIN)pDevice->winmm.hDeviceCapture);
18756     }
18757
18758     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
18759         if (pDevice->winmm.pWAVEHDRCapture != NULL) {
18760             ma_uint32 iPeriod;
18761             for (iPeriod = 0; iPeriod < pDescriptorPlayback->periodCount; ++iPeriod) {
18762                 ((MA_PFN_waveOutUnprepareHeader)pDevice->pContext->winmm.waveOutUnprepareHeader)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &((WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback)[iPeriod], sizeof(WAVEHDR));
18763             }
18764         }
18765
18766         ((MA_PFN_waveOutClose)pDevice->pContext->winmm.waveOutClose)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
18767     }
18768
18769     ma__free_from_callbacks(pDevice->winmm._pHeapData, &pDevice->pContext->allocationCallbacks);
18770     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, errorMsg, errorCode);
18771 }
18772
18773 static ma_result ma_device_start__winmm(ma_device* pDevice)
18774 {
18775     MA_ASSERT(pDevice != NULL);
18776
18777     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
18778         MMRESULT resultMM;
18779         WAVEHDR* pWAVEHDR;
18780         ma_uint32 iPeriod;
18781
18782         pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
18783
18784         /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
18785         ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
18786
18787         /* 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. */
18788         for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
18789             resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[iPeriod], sizeof(WAVEHDR));
18790             if (resultMM != MMSYSERR_NOERROR) {
18791                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to attach input buffers to capture device in preparation for capture.", ma_result_from_MMRESULT(resultMM));
18792             }
18793
18794             /* Make sure all of the buffers start out locked. We don't want to access them until the backend tells us we can. */
18795             pWAVEHDR[iPeriod].dwUser = 1;   /* 1 = locked. */
18796         }
18797
18798         /* Capture devices need to be explicitly started, unlike playback devices. */
18799         resultMM = ((MA_PFN_waveInStart)pDevice->pContext->winmm.waveInStart)((HWAVEIN)pDevice->winmm.hDeviceCapture);
18800         if (resultMM != MMSYSERR_NOERROR) {
18801             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", ma_result_from_MMRESULT(resultMM));
18802         }
18803     }
18804
18805     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
18806         /* Don't need to do anything for playback. It'll be started automatically in ma_device_start__winmm(). */
18807     }
18808
18809     return MA_SUCCESS;
18810 }
18811
18812 static ma_result ma_device_stop__winmm(ma_device* pDevice)
18813 {
18814     MMRESULT resultMM;
18815
18816     MA_ASSERT(pDevice != NULL);
18817
18818     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
18819         if (pDevice->winmm.hDeviceCapture == NULL) {
18820             return MA_INVALID_ARGS;
18821         }
18822
18823         resultMM = ((MA_PFN_waveInReset)pDevice->pContext->winmm.waveInReset)((HWAVEIN)pDevice->winmm.hDeviceCapture);
18824         if (resultMM != MMSYSERR_NOERROR) {
18825             ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset capture device.", ma_result_from_MMRESULT(resultMM));
18826         }
18827     }
18828
18829     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
18830         ma_uint32 iPeriod;
18831         WAVEHDR* pWAVEHDR;
18832
18833         if (pDevice->winmm.hDevicePlayback == NULL) {
18834             return MA_INVALID_ARGS;
18835         }
18836
18837         /* 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. */
18838         pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
18839         for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; iPeriod += 1) {
18840             if (pWAVEHDR[iPeriod].dwUser == 1) { /* 1 = locked. */
18841                 if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
18842                     break;  /* An error occurred so just abandon ship and stop the device without draining. */
18843                 }
18844
18845                 pWAVEHDR[iPeriod].dwUser = 0;
18846             }
18847         }
18848
18849         resultMM = ((MA_PFN_waveOutReset)pDevice->pContext->winmm.waveOutReset)((HWAVEOUT)pDevice->winmm.hDevicePlayback);
18850         if (resultMM != MMSYSERR_NOERROR) {
18851             ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] WARNING: Failed to reset playback device.", ma_result_from_MMRESULT(resultMM));
18852         }
18853     }
18854
18855     return MA_SUCCESS;
18856 }
18857
18858 static ma_result ma_device_write__winmm(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
18859 {
18860     ma_result result = MA_SUCCESS;
18861     MMRESULT resultMM;
18862     ma_uint32 totalFramesWritten;
18863     WAVEHDR* pWAVEHDR;
18864
18865     MA_ASSERT(pDevice != NULL);
18866     MA_ASSERT(pPCMFrames != NULL);
18867
18868     if (pFramesWritten != NULL) {
18869         *pFramesWritten = 0;
18870     }
18871
18872     pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRPlayback;
18873
18874     /* Keep processing as much data as possible. */
18875     totalFramesWritten = 0;
18876     while (totalFramesWritten < frameCount) {
18877         /* If the current header has some space available we need to write part of it. */
18878         if (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser == 0) { /* 0 = unlocked. */
18879             /*
18880             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
18881             write it out and move on to the next iteration.
18882             */
18883             ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
18884             ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedPlayback;
18885
18886             ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesWritten));
18887             const void* pSrc = ma_offset_ptr(pPCMFrames, totalFramesWritten*bpf);
18888             void* pDst = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].lpData, pDevice->winmm.headerFramesConsumedPlayback*bpf);
18889             MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf);
18890
18891             pDevice->winmm.headerFramesConsumedPlayback += framesToCopy;
18892             totalFramesWritten += framesToCopy;
18893
18894             /* If we've consumed the buffer entirely we need to write it out to the device. */
18895             if (pDevice->winmm.headerFramesConsumedPlayback == (pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwBufferLength/bpf)) {
18896                 pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 1;            /* 1 = locked. */
18897                 pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */
18898
18899                 /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
18900                 ResetEvent((HANDLE)pDevice->winmm.hEventPlayback);
18901
18902                 /* The device will be started here. */
18903                 resultMM = ((MA_PFN_waveOutWrite)pDevice->pContext->winmm.waveOutWrite)((HWAVEOUT)pDevice->winmm.hDevicePlayback, &pWAVEHDR[pDevice->winmm.iNextHeaderPlayback], sizeof(WAVEHDR));
18904                 if (resultMM != MMSYSERR_NOERROR) {
18905                     result = ma_result_from_MMRESULT(resultMM);
18906                     ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveOutWrite() failed.", result);
18907                     break;
18908                 }
18909
18910                 /* Make sure we move to the next header. */
18911                 pDevice->winmm.iNextHeaderPlayback = (pDevice->winmm.iNextHeaderPlayback + 1) % pDevice->playback.internalPeriods;
18912                 pDevice->winmm.headerFramesConsumedPlayback = 0;
18913             }
18914
18915             /* If at this point we have consumed the entire input buffer we can return. */
18916             MA_ASSERT(totalFramesWritten <= frameCount);
18917             if (totalFramesWritten == frameCount) {
18918                 break;
18919             }
18920
18921             /* Getting here means there's more to process. */
18922             continue;
18923         }
18924
18925         /* Getting here means there isn't enough room in the buffer and we need to wait for one to become available. */
18926         if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventPlayback, INFINITE) != WAIT_OBJECT_0) {
18927             result = MA_ERROR;
18928             break;
18929         }
18930
18931         /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */
18932         if ((pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwFlags & WHDR_DONE) != 0) {
18933             pWAVEHDR[pDevice->winmm.iNextHeaderPlayback].dwUser = 0;    /* 0 = unlocked (make it available for writing). */
18934             pDevice->winmm.headerFramesConsumedPlayback = 0;
18935         }
18936
18937         /* If the device has been stopped we need to break. */
18938         if (ma_device_get_state(pDevice) != MA_STATE_STARTED) {
18939             break;
18940         }
18941     }
18942
18943     if (pFramesWritten != NULL) {
18944         *pFramesWritten = totalFramesWritten;
18945     }
18946
18947     return result;
18948 }
18949
18950 static ma_result ma_device_read__winmm(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
18951 {
18952     ma_result result = MA_SUCCESS;
18953     MMRESULT resultMM;
18954     ma_uint32 totalFramesRead;
18955     WAVEHDR* pWAVEHDR;
18956
18957     MA_ASSERT(pDevice != NULL);
18958     MA_ASSERT(pPCMFrames != NULL);
18959
18960     if (pFramesRead != NULL) {
18961         *pFramesRead = 0;
18962     }
18963
18964     pWAVEHDR = (WAVEHDR*)pDevice->winmm.pWAVEHDRCapture;
18965
18966     /* Keep processing as much data as possible. */
18967     totalFramesRead = 0;
18968     while (totalFramesRead < frameCount) {
18969         /* If the current header has some space available we need to write part of it. */
18970         if (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser == 0) { /* 0 = unlocked. */
18971             /* The buffer is available for reading. If we fully consume it we need to add it back to the buffer. */
18972             ma_uint32 bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
18973             ma_uint32 framesRemainingInHeader = (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf) - pDevice->winmm.headerFramesConsumedCapture;
18974
18975             ma_uint32 framesToCopy = ma_min(framesRemainingInHeader, (frameCount - totalFramesRead));
18976             const void* pSrc = ma_offset_ptr(pWAVEHDR[pDevice->winmm.iNextHeaderCapture].lpData, pDevice->winmm.headerFramesConsumedCapture*bpf);
18977             void* pDst = ma_offset_ptr(pPCMFrames, totalFramesRead*bpf);
18978             MA_COPY_MEMORY(pDst, pSrc, framesToCopy*bpf);
18979
18980             pDevice->winmm.headerFramesConsumedCapture += framesToCopy;
18981             totalFramesRead += framesToCopy;
18982
18983             /* If we've consumed the buffer entirely we need to add it back to the device. */
18984             if (pDevice->winmm.headerFramesConsumedCapture == (pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwBufferLength/bpf)) {
18985                 pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 1;            /* 1 = locked. */
18986                 pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags &= ~WHDR_DONE; /* <-- Need to make sure the WHDR_DONE flag is unset. */
18987
18988                 /* Make sure the event is reset to a non-signaled state to ensure we don't prematurely return from WaitForSingleObject(). */
18989                 ResetEvent((HANDLE)pDevice->winmm.hEventCapture);
18990
18991                 /* The device will be started here. */
18992                 resultMM = ((MA_PFN_waveInAddBuffer)pDevice->pContext->winmm.waveInAddBuffer)((HWAVEIN)pDevice->winmm.hDeviceCapture, &((LPWAVEHDR)pDevice->winmm.pWAVEHDRCapture)[pDevice->winmm.iNextHeaderCapture], sizeof(WAVEHDR));
18993                 if (resultMM != MMSYSERR_NOERROR) {
18994                     result = ma_result_from_MMRESULT(resultMM);
18995                     ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[WinMM] waveInAddBuffer() failed.", result);
18996                     break;
18997                 }
18998
18999                 /* Make sure we move to the next header. */
19000                 pDevice->winmm.iNextHeaderCapture = (pDevice->winmm.iNextHeaderCapture + 1) % pDevice->capture.internalPeriods;
19001                 pDevice->winmm.headerFramesConsumedCapture = 0;
19002             }
19003
19004             /* If at this point we have filled the entire input buffer we can return. */
19005             MA_ASSERT(totalFramesRead <= frameCount);
19006             if (totalFramesRead == frameCount) {
19007                 break;
19008             }
19009
19010             /* Getting here means there's more to process. */
19011             continue;
19012         }
19013
19014         /* Getting here means there isn't enough any data left to send to the client which means we need to wait for more. */
19015         if (WaitForSingleObject((HANDLE)pDevice->winmm.hEventCapture, INFINITE) != WAIT_OBJECT_0) {
19016             result = MA_ERROR;
19017             break;
19018         }
19019
19020         /* Something happened. If the next buffer has been marked as done we need to reset a bit of state. */
19021         if ((pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwFlags & WHDR_DONE) != 0) {
19022             pWAVEHDR[pDevice->winmm.iNextHeaderCapture].dwUser = 0;    /* 0 = unlocked (make it available for reading). */
19023             pDevice->winmm.headerFramesConsumedCapture = 0;
19024         }
19025
19026         /* If the device has been stopped we need to break. */
19027         if (ma_device_get_state(pDevice) != MA_STATE_STARTED) {
19028             break;
19029         }
19030     }
19031
19032     if (pFramesRead != NULL) {
19033         *pFramesRead = totalFramesRead;
19034     }
19035
19036     return result;
19037 }
19038
19039 static ma_result ma_context_uninit__winmm(ma_context* pContext)
19040 {
19041     MA_ASSERT(pContext != NULL);
19042     MA_ASSERT(pContext->backend == ma_backend_winmm);
19043
19044     ma_dlclose(pContext, pContext->winmm.hWinMM);
19045     return MA_SUCCESS;
19046 }
19047
19048 static ma_result ma_context_init__winmm(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
19049 {
19050     MA_ASSERT(pContext != NULL);
19051
19052     (void)pConfig;
19053
19054     pContext->winmm.hWinMM = ma_dlopen(pContext, "winmm.dll");
19055     if (pContext->winmm.hWinMM == NULL) {
19056         return MA_NO_BACKEND;
19057     }
19058
19059     pContext->winmm.waveOutGetNumDevs      = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetNumDevs");
19060     pContext->winmm.waveOutGetDevCapsA     = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetDevCapsA");
19061     pContext->winmm.waveOutOpen            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutOpen");
19062     pContext->winmm.waveOutClose           = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutClose");
19063     pContext->winmm.waveOutPrepareHeader   = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutPrepareHeader");
19064     pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutUnprepareHeader");
19065     pContext->winmm.waveOutWrite           = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutWrite");
19066     pContext->winmm.waveOutReset           = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutReset");
19067     pContext->winmm.waveInGetNumDevs       = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetNumDevs");
19068     pContext->winmm.waveInGetDevCapsA      = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetDevCapsA");
19069     pContext->winmm.waveInOpen             = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInOpen");
19070     pContext->winmm.waveInClose            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInClose");
19071     pContext->winmm.waveInPrepareHeader    = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInPrepareHeader");
19072     pContext->winmm.waveInUnprepareHeader  = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInUnprepareHeader");
19073     pContext->winmm.waveInAddBuffer        = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInAddBuffer");
19074     pContext->winmm.waveInStart            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart");
19075     pContext->winmm.waveInReset            = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset");
19076
19077     pCallbacks->onContextInit             = ma_context_init__winmm;
19078     pCallbacks->onContextUninit           = ma_context_uninit__winmm;
19079     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__winmm;
19080     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__winmm;
19081     pCallbacks->onDeviceInit              = ma_device_init__winmm;
19082     pCallbacks->onDeviceUninit            = ma_device_uninit__winmm;
19083     pCallbacks->onDeviceStart             = ma_device_start__winmm;
19084     pCallbacks->onDeviceStop              = ma_device_stop__winmm;
19085     pCallbacks->onDeviceRead              = ma_device_read__winmm;
19086     pCallbacks->onDeviceWrite             = ma_device_write__winmm;
19087     pCallbacks->onDeviceDataLoop          = NULL;   /* This is a blocking read-write API, so this can be NULL since miniaudio will manage the audio thread for us. */
19088
19089     return MA_SUCCESS;
19090 }
19091 #endif
19092
19093
19094
19095
19096 /******************************************************************************
19097
19098 ALSA Backend
19099
19100 ******************************************************************************/
19101 #ifdef MA_HAS_ALSA
19102
19103 #ifdef MA_NO_RUNTIME_LINKING
19104
19105 /* asoundlib.h marks some functions with "inline" which isn't always supported. Need to emulate it. */
19106 #if !defined(__cplusplus)
19107     #if defined(__STRICT_ANSI__)
19108         #if !defined(inline)
19109             #define inline __inline__ __attribute__((always_inline))
19110             #define MA_INLINE_DEFINED
19111         #endif
19112     #endif
19113 #endif
19114 #include <alsa/asoundlib.h>
19115 #if defined(MA_INLINE_DEFINED)
19116     #undef inline
19117     #undef MA_INLINE_DEFINED
19118 #endif
19119
19120 typedef snd_pcm_uframes_t                       ma_snd_pcm_uframes_t;
19121 typedef snd_pcm_sframes_t                       ma_snd_pcm_sframes_t;
19122 typedef snd_pcm_stream_t                        ma_snd_pcm_stream_t;
19123 typedef snd_pcm_format_t                        ma_snd_pcm_format_t;
19124 typedef snd_pcm_access_t                        ma_snd_pcm_access_t;
19125 typedef snd_pcm_t                               ma_snd_pcm_t;
19126 typedef snd_pcm_hw_params_t                     ma_snd_pcm_hw_params_t;
19127 typedef snd_pcm_sw_params_t                     ma_snd_pcm_sw_params_t;
19128 typedef snd_pcm_format_mask_t                   ma_snd_pcm_format_mask_t;
19129 typedef snd_pcm_info_t                          ma_snd_pcm_info_t;
19130 typedef snd_pcm_channel_area_t                  ma_snd_pcm_channel_area_t;
19131 typedef snd_pcm_chmap_t                         ma_snd_pcm_chmap_t;
19132 typedef snd_pcm_state_t                         ma_snd_pcm_state_t;
19133
19134 /* snd_pcm_stream_t */
19135 #define MA_SND_PCM_STREAM_PLAYBACK              SND_PCM_STREAM_PLAYBACK
19136 #define MA_SND_PCM_STREAM_CAPTURE               SND_PCM_STREAM_CAPTURE
19137
19138 /* snd_pcm_format_t */
19139 #define MA_SND_PCM_FORMAT_UNKNOWN               SND_PCM_FORMAT_UNKNOWN
19140 #define MA_SND_PCM_FORMAT_U8                    SND_PCM_FORMAT_U8
19141 #define MA_SND_PCM_FORMAT_S16_LE                SND_PCM_FORMAT_S16_LE
19142 #define MA_SND_PCM_FORMAT_S16_BE                SND_PCM_FORMAT_S16_BE
19143 #define MA_SND_PCM_FORMAT_S24_LE                SND_PCM_FORMAT_S24_LE
19144 #define MA_SND_PCM_FORMAT_S24_BE                SND_PCM_FORMAT_S24_BE
19145 #define MA_SND_PCM_FORMAT_S32_LE                SND_PCM_FORMAT_S32_LE
19146 #define MA_SND_PCM_FORMAT_S32_BE                SND_PCM_FORMAT_S32_BE
19147 #define MA_SND_PCM_FORMAT_FLOAT_LE              SND_PCM_FORMAT_FLOAT_LE
19148 #define MA_SND_PCM_FORMAT_FLOAT_BE              SND_PCM_FORMAT_FLOAT_BE
19149 #define MA_SND_PCM_FORMAT_FLOAT64_LE            SND_PCM_FORMAT_FLOAT64_LE
19150 #define MA_SND_PCM_FORMAT_FLOAT64_BE            SND_PCM_FORMAT_FLOAT64_BE
19151 #define MA_SND_PCM_FORMAT_MU_LAW                SND_PCM_FORMAT_MU_LAW
19152 #define MA_SND_PCM_FORMAT_A_LAW                 SND_PCM_FORMAT_A_LAW
19153 #define MA_SND_PCM_FORMAT_S24_3LE               SND_PCM_FORMAT_S24_3LE
19154 #define MA_SND_PCM_FORMAT_S24_3BE               SND_PCM_FORMAT_S24_3BE
19155
19156 /* ma_snd_pcm_access_t */
19157 #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED      SND_PCM_ACCESS_MMAP_INTERLEAVED
19158 #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED   SND_PCM_ACCESS_MMAP_NONINTERLEAVED
19159 #define MA_SND_PCM_ACCESS_MMAP_COMPLEX          SND_PCM_ACCESS_MMAP_COMPLEX
19160 #define MA_SND_PCM_ACCESS_RW_INTERLEAVED        SND_PCM_ACCESS_RW_INTERLEAVED
19161 #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED     SND_PCM_ACCESS_RW_NONINTERLEAVED
19162
19163 /* Channel positions. */
19164 #define MA_SND_CHMAP_UNKNOWN                    SND_CHMAP_UNKNOWN
19165 #define MA_SND_CHMAP_NA                         SND_CHMAP_NA
19166 #define MA_SND_CHMAP_MONO                       SND_CHMAP_MONO
19167 #define MA_SND_CHMAP_FL                         SND_CHMAP_FL
19168 #define MA_SND_CHMAP_FR                         SND_CHMAP_FR
19169 #define MA_SND_CHMAP_RL                         SND_CHMAP_RL
19170 #define MA_SND_CHMAP_RR                         SND_CHMAP_RR
19171 #define MA_SND_CHMAP_FC                         SND_CHMAP_FC
19172 #define MA_SND_CHMAP_LFE                        SND_CHMAP_LFE
19173 #define MA_SND_CHMAP_SL                         SND_CHMAP_SL
19174 #define MA_SND_CHMAP_SR                         SND_CHMAP_SR
19175 #define MA_SND_CHMAP_RC                         SND_CHMAP_RC
19176 #define MA_SND_CHMAP_FLC                        SND_CHMAP_FLC
19177 #define MA_SND_CHMAP_FRC                        SND_CHMAP_FRC
19178 #define MA_SND_CHMAP_RLC                        SND_CHMAP_RLC
19179 #define MA_SND_CHMAP_RRC                        SND_CHMAP_RRC
19180 #define MA_SND_CHMAP_FLW                        SND_CHMAP_FLW
19181 #define MA_SND_CHMAP_FRW                        SND_CHMAP_FRW
19182 #define MA_SND_CHMAP_FLH                        SND_CHMAP_FLH
19183 #define MA_SND_CHMAP_FCH                        SND_CHMAP_FCH
19184 #define MA_SND_CHMAP_FRH                        SND_CHMAP_FRH
19185 #define MA_SND_CHMAP_TC                         SND_CHMAP_TC
19186 #define MA_SND_CHMAP_TFL                        SND_CHMAP_TFL
19187 #define MA_SND_CHMAP_TFR                        SND_CHMAP_TFR
19188 #define MA_SND_CHMAP_TFC                        SND_CHMAP_TFC
19189 #define MA_SND_CHMAP_TRL                        SND_CHMAP_TRL
19190 #define MA_SND_CHMAP_TRR                        SND_CHMAP_TRR
19191 #define MA_SND_CHMAP_TRC                        SND_CHMAP_TRC
19192 #define MA_SND_CHMAP_TFLC                       SND_CHMAP_TFLC
19193 #define MA_SND_CHMAP_TFRC                       SND_CHMAP_TFRC
19194 #define MA_SND_CHMAP_TSL                        SND_CHMAP_TSL
19195 #define MA_SND_CHMAP_TSR                        SND_CHMAP_TSR
19196 #define MA_SND_CHMAP_LLFE                       SND_CHMAP_LLFE
19197 #define MA_SND_CHMAP_RLFE                       SND_CHMAP_RLFE
19198 #define MA_SND_CHMAP_BC                         SND_CHMAP_BC
19199 #define MA_SND_CHMAP_BLC                        SND_CHMAP_BLC
19200 #define MA_SND_CHMAP_BRC                        SND_CHMAP_BRC
19201
19202 /* Open mode flags. */
19203 #define MA_SND_PCM_NO_AUTO_RESAMPLE             SND_PCM_NO_AUTO_RESAMPLE
19204 #define MA_SND_PCM_NO_AUTO_CHANNELS             SND_PCM_NO_AUTO_CHANNELS
19205 #define MA_SND_PCM_NO_AUTO_FORMAT               SND_PCM_NO_AUTO_FORMAT
19206 #else
19207 #include <errno.h>  /* For EPIPE, etc. */
19208 typedef unsigned long                           ma_snd_pcm_uframes_t;
19209 typedef long                                    ma_snd_pcm_sframes_t;
19210 typedef int                                     ma_snd_pcm_stream_t;
19211 typedef int                                     ma_snd_pcm_format_t;
19212 typedef int                                     ma_snd_pcm_access_t;
19213 typedef int                                     ma_snd_pcm_state_t;
19214 typedef struct ma_snd_pcm_t                     ma_snd_pcm_t;
19215 typedef struct ma_snd_pcm_hw_params_t           ma_snd_pcm_hw_params_t;
19216 typedef struct ma_snd_pcm_sw_params_t           ma_snd_pcm_sw_params_t;
19217 typedef struct ma_snd_pcm_format_mask_t         ma_snd_pcm_format_mask_t;
19218 typedef struct ma_snd_pcm_info_t                ma_snd_pcm_info_t;
19219 typedef struct
19220 {
19221     void* addr;
19222     unsigned int first;
19223     unsigned int step;
19224 } ma_snd_pcm_channel_area_t;
19225 typedef struct
19226 {
19227     unsigned int channels;
19228     unsigned int pos[1];
19229 } ma_snd_pcm_chmap_t;
19230
19231 /* snd_pcm_state_t */
19232 #define MA_SND_PCM_STATE_OPEN                  0
19233 #define MA_SND_PCM_STATE_SETUP                 1
19234 #define MA_SND_PCM_STATE_PREPARED              2
19235 #define MA_SND_PCM_STATE_RUNNING               3
19236 #define MA_SND_PCM_STATE_XRUN                  4
19237 #define MA_SND_PCM_STATE_DRAINING              5
19238 #define MA_SND_PCM_STATE_PAUSED                6
19239 #define MA_SND_PCM_STATE_SUSPENDED             7
19240 #define MA_SND_PCM_STATE_DISCONNECTED          8
19241
19242 /* snd_pcm_stream_t */
19243 #define MA_SND_PCM_STREAM_PLAYBACK             0
19244 #define MA_SND_PCM_STREAM_CAPTURE              1
19245
19246 /* snd_pcm_format_t */
19247 #define MA_SND_PCM_FORMAT_UNKNOWN              -1
19248 #define MA_SND_PCM_FORMAT_U8                   1
19249 #define MA_SND_PCM_FORMAT_S16_LE               2
19250 #define MA_SND_PCM_FORMAT_S16_BE               3
19251 #define MA_SND_PCM_FORMAT_S24_LE               6
19252 #define MA_SND_PCM_FORMAT_S24_BE               7
19253 #define MA_SND_PCM_FORMAT_S32_LE               10
19254 #define MA_SND_PCM_FORMAT_S32_BE               11
19255 #define MA_SND_PCM_FORMAT_FLOAT_LE             14
19256 #define MA_SND_PCM_FORMAT_FLOAT_BE             15
19257 #define MA_SND_PCM_FORMAT_FLOAT64_LE           16
19258 #define MA_SND_PCM_FORMAT_FLOAT64_BE           17
19259 #define MA_SND_PCM_FORMAT_MU_LAW               20
19260 #define MA_SND_PCM_FORMAT_A_LAW                21
19261 #define MA_SND_PCM_FORMAT_S24_3LE              32
19262 #define MA_SND_PCM_FORMAT_S24_3BE              33
19263
19264 /* snd_pcm_access_t */
19265 #define MA_SND_PCM_ACCESS_MMAP_INTERLEAVED     0
19266 #define MA_SND_PCM_ACCESS_MMAP_NONINTERLEAVED  1
19267 #define MA_SND_PCM_ACCESS_MMAP_COMPLEX         2
19268 #define MA_SND_PCM_ACCESS_RW_INTERLEAVED       3
19269 #define MA_SND_PCM_ACCESS_RW_NONINTERLEAVED    4
19270
19271 /* Channel positions. */
19272 #define MA_SND_CHMAP_UNKNOWN                   0
19273 #define MA_SND_CHMAP_NA                        1
19274 #define MA_SND_CHMAP_MONO                      2
19275 #define MA_SND_CHMAP_FL                        3
19276 #define MA_SND_CHMAP_FR                        4
19277 #define MA_SND_CHMAP_RL                        5
19278 #define MA_SND_CHMAP_RR                        6
19279 #define MA_SND_CHMAP_FC                        7
19280 #define MA_SND_CHMAP_LFE                       8
19281 #define MA_SND_CHMAP_SL                        9
19282 #define MA_SND_CHMAP_SR                        10
19283 #define MA_SND_CHMAP_RC                        11
19284 #define MA_SND_CHMAP_FLC                       12
19285 #define MA_SND_CHMAP_FRC                       13
19286 #define MA_SND_CHMAP_RLC                       14
19287 #define MA_SND_CHMAP_RRC                       15
19288 #define MA_SND_CHMAP_FLW                       16
19289 #define MA_SND_CHMAP_FRW                       17
19290 #define MA_SND_CHMAP_FLH                       18
19291 #define MA_SND_CHMAP_FCH                       19
19292 #define MA_SND_CHMAP_FRH                       20
19293 #define MA_SND_CHMAP_TC                        21
19294 #define MA_SND_CHMAP_TFL                       22
19295 #define MA_SND_CHMAP_TFR                       23
19296 #define MA_SND_CHMAP_TFC                       24
19297 #define MA_SND_CHMAP_TRL                       25
19298 #define MA_SND_CHMAP_TRR                       26
19299 #define MA_SND_CHMAP_TRC                       27
19300 #define MA_SND_CHMAP_TFLC                      28
19301 #define MA_SND_CHMAP_TFRC                      29
19302 #define MA_SND_CHMAP_TSL                       30
19303 #define MA_SND_CHMAP_TSR                       31
19304 #define MA_SND_CHMAP_LLFE                      32
19305 #define MA_SND_CHMAP_RLFE                      33
19306 #define MA_SND_CHMAP_BC                        34
19307 #define MA_SND_CHMAP_BLC                       35
19308 #define MA_SND_CHMAP_BRC                       36
19309
19310 /* Open mode flags. */
19311 #define MA_SND_PCM_NO_AUTO_RESAMPLE            0x00010000
19312 #define MA_SND_PCM_NO_AUTO_CHANNELS            0x00020000
19313 #define MA_SND_PCM_NO_AUTO_FORMAT              0x00040000
19314 #endif
19315
19316 typedef int                  (* ma_snd_pcm_open_proc)                          (ma_snd_pcm_t **pcm, const char *name, ma_snd_pcm_stream_t stream, int mode);
19317 typedef int                  (* ma_snd_pcm_close_proc)                         (ma_snd_pcm_t *pcm);
19318 typedef size_t               (* ma_snd_pcm_hw_params_sizeof_proc)              (void);
19319 typedef int                  (* ma_snd_pcm_hw_params_any_proc)                 (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
19320 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);
19321 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);
19322 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);
19323 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);
19324 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);
19325 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);
19326 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);
19327 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);
19328 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);
19329 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);
19330 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);
19331 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);
19332 typedef int                  (* ma_snd_pcm_hw_params_get_format_proc)          (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_format_t *format);
19333 typedef int                  (* ma_snd_pcm_hw_params_get_channels_proc)        (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
19334 typedef int                  (* ma_snd_pcm_hw_params_get_channels_min_proc)    (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
19335 typedef int                  (* ma_snd_pcm_hw_params_get_channels_max_proc)    (const ma_snd_pcm_hw_params_t *params, unsigned int *val);
19336 typedef int                  (* ma_snd_pcm_hw_params_get_rate_proc)            (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
19337 typedef int                  (* ma_snd_pcm_hw_params_get_rate_min_proc)        (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
19338 typedef int                  (* ma_snd_pcm_hw_params_get_rate_max_proc)        (const ma_snd_pcm_hw_params_t *params, unsigned int *rate, int *dir);
19339 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);
19340 typedef int                  (* ma_snd_pcm_hw_params_get_periods_proc)         (const ma_snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
19341 typedef int                  (* ma_snd_pcm_hw_params_get_access_proc)          (const ma_snd_pcm_hw_params_t *params, ma_snd_pcm_access_t *_access);
19342 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);
19343 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);
19344 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);
19345 typedef int                  (* ma_snd_pcm_hw_params_proc)                     (ma_snd_pcm_t *pcm, ma_snd_pcm_hw_params_t *params);
19346 typedef size_t               (* ma_snd_pcm_sw_params_sizeof_proc)              (void);
19347 typedef int                  (* ma_snd_pcm_sw_params_current_proc)             (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params);
19348 typedef int                  (* ma_snd_pcm_sw_params_get_boundary_proc)        (const ma_snd_pcm_sw_params_t *params, ma_snd_pcm_uframes_t* val);
19349 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);
19350 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);
19351 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);
19352 typedef int                  (* ma_snd_pcm_sw_params_proc)                     (ma_snd_pcm_t *pcm, ma_snd_pcm_sw_params_t *params);
19353 typedef size_t               (* ma_snd_pcm_format_mask_sizeof_proc)            (void);
19354 typedef int                  (* ma_snd_pcm_format_mask_test_proc)              (const ma_snd_pcm_format_mask_t *mask, ma_snd_pcm_format_t val);
19355 typedef ma_snd_pcm_chmap_t * (* ma_snd_pcm_get_chmap_proc)                     (ma_snd_pcm_t *pcm);
19356 typedef ma_snd_pcm_state_t   (* ma_snd_pcm_state_proc)                         (ma_snd_pcm_t *pcm);
19357 typedef int                  (* ma_snd_pcm_prepare_proc)                       (ma_snd_pcm_t *pcm);
19358 typedef int                  (* ma_snd_pcm_start_proc)                         (ma_snd_pcm_t *pcm);
19359 typedef int                  (* ma_snd_pcm_drop_proc)                          (ma_snd_pcm_t *pcm);
19360 typedef int                  (* ma_snd_pcm_drain_proc)                         (ma_snd_pcm_t *pcm);
19361 typedef int                  (* ma_snd_device_name_hint_proc)                  (int card, const char *iface, void ***hints);
19362 typedef char *               (* ma_snd_device_name_get_hint_proc)              (const void *hint, const char *id);
19363 typedef int                  (* ma_snd_card_get_index_proc)                    (const char *name);
19364 typedef int                  (* ma_snd_device_name_free_hint_proc)             (void **hints);
19365 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);
19366 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);
19367 typedef int                  (* ma_snd_pcm_recover_proc)                       (ma_snd_pcm_t *pcm, int err, int silent);
19368 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_readi_proc)                         (ma_snd_pcm_t *pcm, void *buffer, ma_snd_pcm_uframes_t size);
19369 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);
19370 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_proc)                         (ma_snd_pcm_t *pcm);
19371 typedef ma_snd_pcm_sframes_t (* ma_snd_pcm_avail_update_proc)                  (ma_snd_pcm_t *pcm);
19372 typedef int                  (* ma_snd_pcm_wait_proc)                          (ma_snd_pcm_t *pcm, int timeout);
19373 typedef int                  (* ma_snd_pcm_info_proc)                          (ma_snd_pcm_t *pcm, ma_snd_pcm_info_t* info);
19374 typedef size_t               (* ma_snd_pcm_info_sizeof_proc)                   (void);
19375 typedef const char*          (* ma_snd_pcm_info_get_name_proc)                 (const ma_snd_pcm_info_t* info);
19376 typedef int                  (* ma_snd_config_update_free_global_proc)         (void);
19377
19378 /* This array specifies each of the common devices that can be used for both playback and capture. */
19379 static const char* g_maCommonDeviceNamesALSA[] = {
19380     "default",
19381     "null",
19382     "pulse",
19383     "jack"
19384 };
19385
19386 /* This array allows us to blacklist specific playback devices. */
19387 static const char* g_maBlacklistedPlaybackDeviceNamesALSA[] = {
19388     ""
19389 };
19390
19391 /* This array allows us to blacklist specific capture devices. */
19392 static const char* g_maBlacklistedCaptureDeviceNamesALSA[] = {
19393     ""
19394 };
19395
19396
19397 static ma_snd_pcm_format_t ma_convert_ma_format_to_alsa_format(ma_format format)
19398 {
19399     ma_snd_pcm_format_t ALSAFormats[] = {
19400         MA_SND_PCM_FORMAT_UNKNOWN,     /* ma_format_unknown */
19401         MA_SND_PCM_FORMAT_U8,          /* ma_format_u8 */
19402         MA_SND_PCM_FORMAT_S16_LE,      /* ma_format_s16 */
19403         MA_SND_PCM_FORMAT_S24_3LE,     /* ma_format_s24 */
19404         MA_SND_PCM_FORMAT_S32_LE,      /* ma_format_s32 */
19405         MA_SND_PCM_FORMAT_FLOAT_LE     /* ma_format_f32 */
19406     };
19407
19408     if (ma_is_big_endian()) {
19409         ALSAFormats[0] = MA_SND_PCM_FORMAT_UNKNOWN;
19410         ALSAFormats[1] = MA_SND_PCM_FORMAT_U8;
19411         ALSAFormats[2] = MA_SND_PCM_FORMAT_S16_BE;
19412         ALSAFormats[3] = MA_SND_PCM_FORMAT_S24_3BE;
19413         ALSAFormats[4] = MA_SND_PCM_FORMAT_S32_BE;
19414         ALSAFormats[5] = MA_SND_PCM_FORMAT_FLOAT_BE;
19415     }
19416
19417     return ALSAFormats[format];
19418 }
19419
19420 static ma_format ma_format_from_alsa(ma_snd_pcm_format_t formatALSA)
19421 {
19422     if (ma_is_little_endian()) {
19423         switch (formatALSA) {
19424             case MA_SND_PCM_FORMAT_S16_LE:   return ma_format_s16;
19425             case MA_SND_PCM_FORMAT_S24_3LE:  return ma_format_s24;
19426             case MA_SND_PCM_FORMAT_S32_LE:   return ma_format_s32;
19427             case MA_SND_PCM_FORMAT_FLOAT_LE: return ma_format_f32;
19428             default: break;
19429         }
19430     } else {
19431         switch (formatALSA) {
19432             case MA_SND_PCM_FORMAT_S16_BE:   return ma_format_s16;
19433             case MA_SND_PCM_FORMAT_S24_3BE:  return ma_format_s24;
19434             case MA_SND_PCM_FORMAT_S32_BE:   return ma_format_s32;
19435             case MA_SND_PCM_FORMAT_FLOAT_BE: return ma_format_f32;
19436             default: break;
19437         }
19438     }
19439
19440     /* Endian agnostic. */
19441     switch (formatALSA) {
19442         case MA_SND_PCM_FORMAT_U8: return ma_format_u8;
19443         default: return ma_format_unknown;
19444     }
19445 }
19446
19447 static ma_channel ma_convert_alsa_channel_position_to_ma_channel(unsigned int alsaChannelPos)
19448 {
19449     switch (alsaChannelPos)
19450     {
19451         case MA_SND_CHMAP_MONO: return MA_CHANNEL_MONO;
19452         case MA_SND_CHMAP_FL:   return MA_CHANNEL_FRONT_LEFT;
19453         case MA_SND_CHMAP_FR:   return MA_CHANNEL_FRONT_RIGHT;
19454         case MA_SND_CHMAP_RL:   return MA_CHANNEL_BACK_LEFT;
19455         case MA_SND_CHMAP_RR:   return MA_CHANNEL_BACK_RIGHT;
19456         case MA_SND_CHMAP_FC:   return MA_CHANNEL_FRONT_CENTER;
19457         case MA_SND_CHMAP_LFE:  return MA_CHANNEL_LFE;
19458         case MA_SND_CHMAP_SL:   return MA_CHANNEL_SIDE_LEFT;
19459         case MA_SND_CHMAP_SR:   return MA_CHANNEL_SIDE_RIGHT;
19460         case MA_SND_CHMAP_RC:   return MA_CHANNEL_BACK_CENTER;
19461         case MA_SND_CHMAP_FLC:  return MA_CHANNEL_FRONT_LEFT_CENTER;
19462         case MA_SND_CHMAP_FRC:  return MA_CHANNEL_FRONT_RIGHT_CENTER;
19463         case MA_SND_CHMAP_RLC:  return 0;
19464         case MA_SND_CHMAP_RRC:  return 0;
19465         case MA_SND_CHMAP_FLW:  return 0;
19466         case MA_SND_CHMAP_FRW:  return 0;
19467         case MA_SND_CHMAP_FLH:  return 0;
19468         case MA_SND_CHMAP_FCH:  return 0;
19469         case MA_SND_CHMAP_FRH:  return 0;
19470         case MA_SND_CHMAP_TC:   return MA_CHANNEL_TOP_CENTER;
19471         case MA_SND_CHMAP_TFL:  return MA_CHANNEL_TOP_FRONT_LEFT;
19472         case MA_SND_CHMAP_TFR:  return MA_CHANNEL_TOP_FRONT_RIGHT;
19473         case MA_SND_CHMAP_TFC:  return MA_CHANNEL_TOP_FRONT_CENTER;
19474         case MA_SND_CHMAP_TRL:  return MA_CHANNEL_TOP_BACK_LEFT;
19475         case MA_SND_CHMAP_TRR:  return MA_CHANNEL_TOP_BACK_RIGHT;
19476         case MA_SND_CHMAP_TRC:  return MA_CHANNEL_TOP_BACK_CENTER;
19477         default: break;
19478     }
19479
19480     return 0;
19481 }
19482
19483 static ma_bool32 ma_is_common_device_name__alsa(const char* name)
19484 {
19485     size_t iName;
19486     for (iName = 0; iName < ma_countof(g_maCommonDeviceNamesALSA); ++iName) {
19487         if (ma_strcmp(name, g_maCommonDeviceNamesALSA[iName]) == 0) {
19488             return MA_TRUE;
19489         }
19490     }
19491
19492     return MA_FALSE;
19493 }
19494
19495
19496 static ma_bool32 ma_is_playback_device_blacklisted__alsa(const char* name)
19497 {
19498     size_t iName;
19499     for (iName = 0; iName < ma_countof(g_maBlacklistedPlaybackDeviceNamesALSA); ++iName) {
19500         if (ma_strcmp(name, g_maBlacklistedPlaybackDeviceNamesALSA[iName]) == 0) {
19501             return MA_TRUE;
19502         }
19503     }
19504
19505     return MA_FALSE;
19506 }
19507
19508 static ma_bool32 ma_is_capture_device_blacklisted__alsa(const char* name)
19509 {
19510     size_t iName;
19511     for (iName = 0; iName < ma_countof(g_maBlacklistedCaptureDeviceNamesALSA); ++iName) {
19512         if (ma_strcmp(name, g_maBlacklistedCaptureDeviceNamesALSA[iName]) == 0) {
19513             return MA_TRUE;
19514         }
19515     }
19516
19517     return MA_FALSE;
19518 }
19519
19520 static ma_bool32 ma_is_device_blacklisted__alsa(ma_device_type deviceType, const char* name)
19521 {
19522     if (deviceType == ma_device_type_playback) {
19523         return ma_is_playback_device_blacklisted__alsa(name);
19524     } else {
19525         return ma_is_capture_device_blacklisted__alsa(name);
19526     }
19527 }
19528
19529
19530 static const char* ma_find_char(const char* str, char c, int* index)
19531 {
19532     int i = 0;
19533     for (;;) {
19534         if (str[i] == '\0') {
19535             if (index) *index = -1;
19536             return NULL;
19537         }
19538
19539         if (str[i] == c) {
19540             if (index) *index = i;
19541             return str + i;
19542         }
19543
19544         i += 1;
19545     }
19546
19547     /* Should never get here, but treat it as though the character was not found to make me feel better inside. */
19548     if (index) *index = -1;
19549     return NULL;
19550 }
19551
19552 static ma_bool32 ma_is_device_name_in_hw_format__alsa(const char* hwid)
19553 {
19554     /* This function is just checking whether or not hwid is in "hw:%d,%d" format. */
19555
19556     int commaPos;
19557     const char* dev;
19558     int i;
19559
19560     if (hwid == NULL) {
19561         return MA_FALSE;
19562     }
19563
19564     if (hwid[0] != 'h' || hwid[1] != 'w' || hwid[2] != ':') {
19565         return MA_FALSE;
19566     }
19567
19568     hwid += 3;
19569
19570     dev = ma_find_char(hwid, ',', &commaPos);
19571     if (dev == NULL) {
19572         return MA_FALSE;
19573     } else {
19574         dev += 1;   /* Skip past the ",". */
19575     }
19576
19577     /* Check if the part between the ":" and the "," contains only numbers. If not, return false. */
19578     for (i = 0; i < commaPos; ++i) {
19579         if (hwid[i] < '0' || hwid[i] > '9') {
19580             return MA_FALSE;
19581         }
19582     }
19583
19584     /* Check if everything after the "," is numeric. If not, return false. */
19585     i = 0;
19586     while (dev[i] != '\0') {
19587         if (dev[i] < '0' || dev[i] > '9') {
19588             return MA_FALSE;
19589         }
19590         i += 1;
19591     }
19592
19593     return MA_TRUE;
19594 }
19595
19596 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. */
19597 {
19598     /* src should look something like this: "hw:CARD=I82801AAICH,DEV=0" */
19599
19600     int colonPos;
19601     int commaPos;
19602     char card[256];
19603     const char* dev;
19604     int cardIndex;
19605
19606     if (dst == NULL) {
19607         return -1;
19608     }
19609     if (dstSize < 7) {
19610         return -1;     /* Absolute minimum size of the output buffer is 7 bytes. */
19611     }
19612
19613     *dst = '\0';    /* Safety. */
19614     if (src == NULL) {
19615         return -1;
19616     }
19617
19618     /* If the input name is already in "hw:%d,%d" format, just return that verbatim. */
19619     if (ma_is_device_name_in_hw_format__alsa(src)) {
19620         return ma_strcpy_s(dst, dstSize, src);
19621     }
19622
19623     src = ma_find_char(src, ':', &colonPos);
19624     if (src == NULL) {
19625         return -1;  /* Couldn't find a colon */
19626     }
19627
19628     dev = ma_find_char(src, ',', &commaPos);
19629     if (dev == NULL) {
19630         dev = "0";
19631         ma_strncpy_s(card, sizeof(card), src+6, (size_t)-1);   /* +6 = ":CARD=" */
19632     } else {
19633         dev = dev + 5;  /* +5 = ",DEV=" */
19634         ma_strncpy_s(card, sizeof(card), src+6, commaPos-6);   /* +6 = ":CARD=" */
19635     }
19636
19637     cardIndex = ((ma_snd_card_get_index_proc)pContext->alsa.snd_card_get_index)(card);
19638     if (cardIndex < 0) {
19639         return -2;  /* Failed to retrieve the card index. */
19640     }
19641
19642     /*printf("TESTING: CARD=%s,DEV=%s\n", card, dev); */
19643
19644
19645     /* Construction. */
19646     dst[0] = 'h'; dst[1] = 'w'; dst[2] = ':';
19647     if (ma_itoa_s(cardIndex, dst+3, dstSize-3, 10) != 0) {
19648         return -3;
19649     }
19650     if (ma_strcat_s(dst, dstSize, ",") != 0) {
19651         return -3;
19652     }
19653     if (ma_strcat_s(dst, dstSize, dev) != 0) {
19654         return -3;
19655     }
19656
19657     return 0;
19658 }
19659
19660 static ma_bool32 ma_does_id_exist_in_list__alsa(ma_device_id* pUniqueIDs, ma_uint32 count, const char* pHWID)
19661 {
19662     ma_uint32 i;
19663
19664     MA_ASSERT(pHWID != NULL);
19665
19666     for (i = 0; i < count; ++i) {
19667         if (ma_strcmp(pUniqueIDs[i].alsa, pHWID) == 0) {
19668             return MA_TRUE;
19669         }
19670     }
19671
19672     return MA_FALSE;
19673 }
19674
19675
19676 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)
19677 {
19678     ma_snd_pcm_t* pPCM;
19679     ma_snd_pcm_stream_t stream;
19680
19681     MA_ASSERT(pContext != NULL);
19682     MA_ASSERT(ppPCM != NULL);
19683
19684     *ppPCM = NULL;
19685     pPCM = NULL;
19686
19687     stream = (deviceType == ma_device_type_playback) ? MA_SND_PCM_STREAM_PLAYBACK : MA_SND_PCM_STREAM_CAPTURE;
19688
19689     if (pDeviceID == NULL) {
19690         ma_bool32 isDeviceOpen;
19691         size_t i;
19692
19693         /*
19694         We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes
19695         me feel better to try as hard as we can get to get _something_ working.
19696         */
19697         const char* defaultDeviceNames[] = {
19698             "default",
19699             NULL,
19700             NULL,
19701             NULL,
19702             NULL,
19703             NULL,
19704             NULL
19705         };
19706
19707         if (shareMode == ma_share_mode_exclusive) {
19708             defaultDeviceNames[1] = "hw";
19709             defaultDeviceNames[2] = "hw:0";
19710             defaultDeviceNames[3] = "hw:0,0";
19711         } else {
19712             if (deviceType == ma_device_type_playback) {
19713                 defaultDeviceNames[1] = "dmix";
19714                 defaultDeviceNames[2] = "dmix:0";
19715                 defaultDeviceNames[3] = "dmix:0,0";
19716             } else {
19717                 defaultDeviceNames[1] = "dsnoop";
19718                 defaultDeviceNames[2] = "dsnoop:0";
19719                 defaultDeviceNames[3] = "dsnoop:0,0";
19720             }
19721             defaultDeviceNames[4] = "hw";
19722             defaultDeviceNames[5] = "hw:0";
19723             defaultDeviceNames[6] = "hw:0,0";
19724         }
19725
19726         isDeviceOpen = MA_FALSE;
19727         for (i = 0; i < ma_countof(defaultDeviceNames); ++i) {
19728             if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') {
19729                 if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, defaultDeviceNames[i], stream, openMode) == 0) {
19730                     isDeviceOpen = MA_TRUE;
19731                     break;
19732                 }
19733             }
19734         }
19735
19736         if (!isDeviceOpen) {
19737             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
19738         }
19739     } else {
19740         /*
19741         We're trying to open a specific device. There's a few things to consider here:
19742
19743         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
19744         an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it
19745         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").
19746         */
19747
19748         /* May end up needing to make small adjustments to the ID, so make a copy. */
19749         ma_device_id deviceID = *pDeviceID;
19750         int resultALSA = -ENODEV;
19751
19752         if (deviceID.alsa[0] != ':') {
19753             /* The ID is not in ":0,0" format. Use the ID exactly as-is. */
19754             resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, deviceID.alsa, stream, openMode);
19755         } else {
19756             char hwid[256];
19757
19758             /* The ID is in ":0,0" format. Try different plugins depending on the shared mode. */
19759             if (deviceID.alsa[1] == '\0') {
19760                 deviceID.alsa[0] = '\0';  /* An ID of ":" should be converted to "". */
19761             }
19762
19763             if (shareMode == ma_share_mode_shared) {
19764                 if (deviceType == ma_device_type_playback) {
19765                     ma_strcpy_s(hwid, sizeof(hwid), "dmix");
19766                 } else {
19767                     ma_strcpy_s(hwid, sizeof(hwid), "dsnoop");
19768                 }
19769
19770                 if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
19771                     resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
19772                 }
19773             }
19774
19775             /* 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. */
19776             if (resultALSA != 0) {
19777                 ma_strcpy_s(hwid, sizeof(hwid), "hw");
19778                 if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
19779                     resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
19780                 }
19781             }
19782         }
19783
19784         if (resultALSA < 0) {
19785             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.", ma_result_from_errno(-resultALSA));
19786         }
19787     }
19788
19789     *ppPCM = pPCM;
19790     return MA_SUCCESS;
19791 }
19792
19793
19794 static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
19795 {
19796     int resultALSA;
19797     ma_bool32 cbResult = MA_TRUE;
19798     char** ppDeviceHints;
19799     ma_device_id* pUniqueIDs = NULL;
19800     ma_uint32 uniqueIDCount = 0;
19801     char** ppNextDeviceHint;
19802
19803     MA_ASSERT(pContext != NULL);
19804     MA_ASSERT(callback != NULL);
19805
19806     ma_mutex_lock(&pContext->alsa.internalDeviceEnumLock);
19807
19808     resultALSA = ((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints);
19809     if (resultALSA < 0) {
19810         ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
19811         return ma_result_from_errno(-resultALSA);
19812     }
19813
19814     ppNextDeviceHint = ppDeviceHints;
19815     while (*ppNextDeviceHint != NULL) {
19816         char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
19817         char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
19818         char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
19819         ma_device_type deviceType = ma_device_type_playback;
19820         ma_bool32 stopEnumeration = MA_FALSE;
19821         char hwid[sizeof(pUniqueIDs->alsa)];
19822         ma_device_info deviceInfo;
19823
19824         if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) {
19825             deviceType = ma_device_type_playback;
19826         }
19827         if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) {
19828             deviceType = ma_device_type_capture;
19829         }
19830
19831         if (NAME != NULL) {
19832             if (pContext->alsa.useVerboseDeviceEnumeration) {
19833                 /* Verbose mode. Use the name exactly as-is. */
19834                 ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
19835             } else {
19836                 /* Simplified mode. Use ":%d,%d" format. */
19837                 if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
19838                     /*
19839                     At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
19840                     plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
19841                     initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
19842                     device type and sharing mode.
19843                     */
19844                     char* dst = hwid;
19845                     char* src = hwid+2;
19846                     while ((*dst++ = *src++));
19847                 } else {
19848                     /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */
19849                     ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
19850                 }
19851
19852                 if (ma_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) {
19853                     goto next_device;   /* The device has already been enumerated. Move on to the next one. */
19854                 } else {
19855                     /* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */
19856                     size_t oldCapacity = sizeof(*pUniqueIDs) *  uniqueIDCount;
19857                     size_t newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1);
19858                     ma_device_id* pNewUniqueIDs = (ma_device_id*)ma__realloc_from_callbacks(pUniqueIDs, newCapacity, oldCapacity, &pContext->allocationCallbacks);
19859                     if (pNewUniqueIDs == NULL) {
19860                         goto next_device;   /* Failed to allocate memory. */
19861                     }
19862
19863                     pUniqueIDs = pNewUniqueIDs;
19864                     MA_COPY_MEMORY(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid));
19865                     uniqueIDCount += 1;
19866                 }
19867             }
19868         } else {
19869             MA_ZERO_MEMORY(hwid, sizeof(hwid));
19870         }
19871
19872         MA_ZERO_OBJECT(&deviceInfo);
19873         ma_strncpy_s(deviceInfo.id.alsa, sizeof(deviceInfo.id.alsa), hwid, (size_t)-1);
19874
19875         /*
19876         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
19877         just use the name of "default" as the indicator.
19878         */
19879         if (ma_strcmp(deviceInfo.id.alsa, "default") == 0) {
19880             deviceInfo.isDefault = MA_TRUE;
19881         }
19882
19883
19884         /*
19885         DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose
19886         device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish
19887         between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the
19888         description.
19889
19890         The value in DESC seems to be split into two lines, with the first line being the name of the device and the
19891         second line being a description of the device. I don't like having the description be across two lines because
19892         it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line
19893         being put into parentheses. In simplified mode I'm just stripping the second line entirely.
19894         */
19895         if (DESC != NULL) {
19896             int lfPos;
19897             const char* line2 = ma_find_char(DESC, '\n', &lfPos);
19898             if (line2 != NULL) {
19899                 line2 += 1; /* Skip past the new-line character. */
19900
19901                 if (pContext->alsa.useVerboseDeviceEnumeration) {
19902                     /* Verbose mode. Put the second line in brackets. */
19903                     ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
19904                     ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), " (");
19905                     ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), line2);
19906                     ma_strcat_s (deviceInfo.name, sizeof(deviceInfo.name), ")");
19907                 } else {
19908                     /* Simplified mode. Strip the second line entirely. */
19909                     ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, lfPos);
19910                 }
19911             } else {
19912                 /* There's no second line. Just copy the whole description. */
19913                 ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), DESC, (size_t)-1);
19914             }
19915         }
19916
19917         if (!ma_is_device_blacklisted__alsa(deviceType, NAME)) {
19918             cbResult = callback(pContext, deviceType, &deviceInfo, pUserData);
19919         }
19920
19921         /*
19922         Some devices are both playback and capture, but they are only enumerated by ALSA once. We need to fire the callback
19923         again for the other device type in this case. We do this for known devices.
19924         */
19925         if (cbResult) {
19926             if (ma_is_common_device_name__alsa(NAME)) {
19927                 if (deviceType == ma_device_type_playback) {
19928                     if (!ma_is_capture_device_blacklisted__alsa(NAME)) {
19929                         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
19930                     }
19931                 } else {
19932                     if (!ma_is_playback_device_blacklisted__alsa(NAME)) {
19933                         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
19934                     }
19935                 }
19936             }
19937         }
19938
19939         if (cbResult == MA_FALSE) {
19940             stopEnumeration = MA_TRUE;
19941         }
19942
19943     next_device:
19944         free(NAME);
19945         free(DESC);
19946         free(IOID);
19947         ppNextDeviceHint += 1;
19948
19949         /* We need to stop enumeration if the callback returned false. */
19950         if (stopEnumeration) {
19951             break;
19952         }
19953     }
19954
19955     ma__free_from_callbacks(pUniqueIDs, &pContext->allocationCallbacks);
19956     ((ma_snd_device_name_free_hint_proc)pContext->alsa.snd_device_name_free_hint)((void**)ppDeviceHints);
19957
19958     ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
19959
19960     return MA_SUCCESS;
19961 }
19962
19963
19964 typedef struct
19965 {
19966     ma_device_type deviceType;
19967     const ma_device_id* pDeviceID;
19968     ma_share_mode shareMode;
19969     ma_device_info* pDeviceInfo;
19970     ma_bool32 foundDevice;
19971 } ma_context_get_device_info_enum_callback_data__alsa;
19972
19973 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)
19974 {
19975     ma_context_get_device_info_enum_callback_data__alsa* pData = (ma_context_get_device_info_enum_callback_data__alsa*)pUserData;
19976     MA_ASSERT(pData != NULL);
19977
19978     (void)pContext;
19979
19980     if (pData->pDeviceID == NULL && ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
19981         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
19982         pData->foundDevice = MA_TRUE;
19983     } else {
19984         if (pData->deviceType == deviceType && (pData->pDeviceID != NULL && ma_strcmp(pData->pDeviceID->alsa, pDeviceInfo->id.alsa) == 0)) {
19985             ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pDeviceInfo->name, (size_t)-1);
19986             pData->foundDevice = MA_TRUE;
19987         }
19988     }
19989
19990     /* Keep enumerating until we have found the device. */
19991     return !pData->foundDevice;
19992 }
19993
19994 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)
19995 {
19996     MA_ASSERT(pPCM        != NULL);
19997     MA_ASSERT(pHWParams   != NULL);
19998     MA_ASSERT(pDeviceInfo != NULL);
19999
20000     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) {
20001         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
20002         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
20003         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
20004         pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = flags;
20005         pDeviceInfo->nativeDataFormatCount += 1;
20006     }
20007 }
20008
20009 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)
20010 {
20011     ma_uint32 iSampleRate;
20012     unsigned int minSampleRate;
20013     unsigned int maxSampleRate;
20014     int sampleRateDir;  /* Not used. Just passed into snd_pcm_hw_params_get_rate_min/max(). */
20015
20016     /* There could be a range. */
20017     ((ma_snd_pcm_hw_params_get_rate_min_proc)pContext->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams, &minSampleRate, &sampleRateDir);
20018     ((ma_snd_pcm_hw_params_get_rate_max_proc)pContext->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams, &maxSampleRate, &sampleRateDir);
20019
20020     /* Make sure our sample rates are clamped to sane values. Stupid devices like "pulse" will reports rates like "1" which is ridiculus. */
20021     minSampleRate = ma_clamp(minSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max);
20022     maxSampleRate = ma_clamp(maxSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max);
20023
20024     for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); iSampleRate += 1) {
20025         ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iSampleRate];
20026
20027         if (standardSampleRate >= minSampleRate && standardSampleRate <= maxSampleRate) {
20028             ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, standardSampleRate, flags, pDeviceInfo);
20029         }
20030     }
20031
20032     /* Now make sure our min and max rates are included just in case they aren't in the range of our standard rates. */
20033     if (!ma_is_standard_sample_rate(minSampleRate)) {
20034         ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, minSampleRate, flags, pDeviceInfo);
20035     }
20036
20037     if (!ma_is_standard_sample_rate(maxSampleRate) && maxSampleRate != minSampleRate) {
20038         ma_context_test_rate_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, maxSampleRate, flags, pDeviceInfo);
20039     }
20040 }
20041
20042 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)
20043 {
20044     ma_context_get_device_info_enum_callback_data__alsa data;
20045     ma_result result;
20046     int resultALSA;
20047     ma_snd_pcm_t* pPCM;
20048     ma_snd_pcm_hw_params_t* pHWParams;
20049     ma_uint32 iFormat;
20050     ma_uint32 iChannel;
20051
20052     MA_ASSERT(pContext != NULL);
20053
20054     /* We just enumerate to find basic information about the device. */
20055     data.deviceType  = deviceType;
20056     data.pDeviceID   = pDeviceID;
20057     data.pDeviceInfo = pDeviceInfo;
20058     data.foundDevice = MA_FALSE;
20059     result = ma_context_enumerate_devices__alsa(pContext, ma_context_get_device_info_enum_callback__alsa, &data);
20060     if (result != MA_SUCCESS) {
20061         return result;
20062     }
20063
20064     if (!data.foundDevice) {
20065         return MA_NO_DEVICE;
20066     }
20067
20068     if (ma_strcmp(pDeviceInfo->id.alsa, "default") == 0) {
20069         pDeviceInfo->isDefault = MA_TRUE;
20070     }
20071
20072     /* For detailed info we need to open the device. */
20073     result = ma_context_open_pcm__alsa(pContext, ma_share_mode_shared, deviceType, pDeviceID, 0, &pPCM);
20074     if (result != MA_SUCCESS) {
20075         return result;
20076     }
20077
20078     /* We need to initialize a HW parameters object in order to know what formats are supported. */
20079     pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pContext->alsa.snd_pcm_hw_params_sizeof)(), &pContext->allocationCallbacks);
20080     if (pHWParams == NULL) {
20081         ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
20082         return MA_OUT_OF_MEMORY;
20083     }
20084
20085     resultALSA = ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
20086     if (resultALSA < 0) {
20087         ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
20088         ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
20089         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA));
20090     }
20091
20092     /*
20093     Some ALSA devices can support many permutations of formats, channels and rates. We only support
20094     a fixed number of permutations which means we need to employ some strategies to ensure the best
20095     combinations are returned. An example is the "pulse" device which can do it's own data conversion
20096     in software and as a result can support any combination of format, channels and rate.
20097
20098     We want to ensure the the first data formats are the best. We have a list of favored sample
20099     formats and sample rates, so these will be the basis of our iteration.
20100     */
20101     
20102     /* Formats. We just iterate over our standard formats and test them, making sure we reset the configuration space each iteration. */
20103     for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); iFormat += 1) {
20104         ma_format format = g_maFormatPriorities[iFormat];
20105
20106         /*
20107         For each format we need to make sure we reset the configuration space so we don't return
20108         channel counts and rates that aren't compatible with a format.
20109         */
20110         ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
20111
20112         /* Test the format first. If this fails it means the format is not supported and we can skip it. */
20113         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) {
20114             /* The format is supported. */
20115             unsigned int minChannels;
20116             unsigned int maxChannels;
20117
20118             /*
20119             The configuration space needs to be restricted to this format so we can get an accurate
20120             picture of which sample rates and channel counts are support with this format.
20121             */
20122             ((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));
20123
20124             /* Now we need to check for supported channels. */
20125             ((ma_snd_pcm_hw_params_get_channels_min_proc)pContext->alsa.snd_pcm_hw_params_get_channels_min)(pHWParams, &minChannels);
20126             ((ma_snd_pcm_hw_params_get_channels_max_proc)pContext->alsa.snd_pcm_hw_params_get_channels_max)(pHWParams, &maxChannels);
20127
20128             if (minChannels > MA_MAX_CHANNELS) {
20129                 continue;   /* Too many channels. */
20130             }
20131             if (maxChannels < MA_MIN_CHANNELS) {
20132                 continue;   /* Not enough channels. */
20133             }
20134
20135             /*
20136             Make sure the channel count is clamped. This is mainly intended for the max channels
20137             because some devices can report an unbound maximum.
20138             */
20139             minChannels = ma_clamp(minChannels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
20140             maxChannels = ma_clamp(maxChannels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
20141
20142             if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
20143                 /* 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. */
20144                 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. */
20145             } else {
20146                 /* The device only supports a specific set of channels. We need to iterate over all of them. */
20147                 for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
20148                     /* Test the channel before applying it to the configuration space. */
20149                     unsigned int channels = iChannel;
20150
20151                     /* Make sure our channel range is reset before testing again or else we'll always fail the test. */
20152                     ((ma_snd_pcm_hw_params_any_proc)pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
20153                     ((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));
20154
20155                     if (((ma_snd_pcm_hw_params_test_channels_proc)pContext->alsa.snd_pcm_hw_params_test_channels)(pPCM, pHWParams, channels) == 0) {
20156                         /* The channel count is supported. */
20157
20158                         /* The configuration space now needs to be restricted to the channel count before extracting the sample rate. */
20159                         ((ma_snd_pcm_hw_params_set_channels_proc)pContext->alsa.snd_pcm_hw_params_set_channels)(pPCM, pHWParams, channels);
20160
20161                         /* Only after the configuration space has been restricted to the specific channel count should we iterate over our sample rates. */
20162                         ma_context_iterate_rates_and_add_native_data_format__alsa(pContext, pPCM, pHWParams, format, channels, 0, pDeviceInfo);
20163                     } else {
20164                         /* The channel count is not supported. Skip. */
20165                     }
20166                 }
20167             }
20168         } else {
20169             /* The format is not supported. Skip. */
20170         }
20171     }
20172
20173     ma__free_from_callbacks(pHWParams, &pContext->allocationCallbacks);
20174
20175     ((ma_snd_pcm_close_proc)pContext->alsa.snd_pcm_close)(pPCM);
20176     return MA_SUCCESS;
20177 }
20178
20179 static ma_result ma_device_uninit__alsa(ma_device* pDevice)
20180 {
20181     MA_ASSERT(pDevice != NULL);
20182
20183     if ((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) {
20184         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
20185     }
20186
20187     if ((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) {
20188         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
20189     }
20190
20191     return MA_SUCCESS;
20192 }
20193
20194 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)
20195 {
20196     ma_result result;
20197     int resultALSA;
20198     ma_snd_pcm_t* pPCM;
20199     ma_bool32 isUsingMMap;
20200     ma_snd_pcm_format_t formatALSA;
20201     ma_format internalFormat;
20202     ma_uint32 internalChannels;
20203     ma_uint32 internalSampleRate;
20204     ma_channel internalChannelMap[MA_MAX_CHANNELS];
20205     ma_uint32 internalPeriodSizeInFrames;
20206     ma_uint32 internalPeriods;
20207     int openMode;
20208     ma_snd_pcm_hw_params_t* pHWParams;
20209     ma_snd_pcm_sw_params_t* pSWParams;
20210     ma_snd_pcm_uframes_t bufferBoundary;
20211
20212     MA_ASSERT(pConfig != NULL);
20213     MA_ASSERT(deviceType != ma_device_type_duplex); /* This function should only be called for playback _or_ capture, never duplex. */
20214     MA_ASSERT(pDevice != NULL);
20215
20216     formatALSA = ma_convert_ma_format_to_alsa_format(pDescriptor->format);
20217
20218     openMode = 0;
20219     if (pConfig->alsa.noAutoResample) {
20220         openMode |= MA_SND_PCM_NO_AUTO_RESAMPLE;
20221     }
20222     if (pConfig->alsa.noAutoChannels) {
20223         openMode |= MA_SND_PCM_NO_AUTO_CHANNELS;
20224     }
20225     if (pConfig->alsa.noAutoFormat) {
20226         openMode |= MA_SND_PCM_NO_AUTO_FORMAT;
20227     }
20228
20229     result = ma_context_open_pcm__alsa(pDevice->pContext, pDescriptor->shareMode, deviceType, pDescriptor->pDeviceID, openMode, &pPCM);
20230     if (result != MA_SUCCESS) {
20231         return result;
20232     }
20233
20234
20235     /* Hardware parameters. */
20236     pHWParams = (ma_snd_pcm_hw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_hw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_hw_params_sizeof)(), &pDevice->pContext->allocationCallbacks);
20237     if (pHWParams == NULL) {
20238         return MA_OUT_OF_MEMORY;
20239     }
20240
20241     resultALSA = ((ma_snd_pcm_hw_params_any_proc)pDevice->pContext->alsa.snd_pcm_hw_params_any)(pPCM, pHWParams);
20242     if (resultALSA < 0) {
20243         ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20244         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20245         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize hardware parameters. snd_pcm_hw_params_any() failed.", ma_result_from_errno(-resultALSA));
20246     }
20247
20248     /* MMAP Mode. Try using interleaved MMAP access. If this fails, fall back to standard readi/writei. */
20249     isUsingMMap = MA_FALSE;
20250 #if 0   /* NOTE: MMAP mode temporarily disabled. */
20251     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. */
20252         if (!pConfig->alsa.noMMap && ma_device__is_async(pDevice)) {
20253             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) {
20254                 pDevice->alsa.isUsingMMap = MA_TRUE;
20255             }
20256         }
20257     }
20258 #endif
20259
20260     if (!isUsingMMap) {
20261         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);
20262         if (resultALSA < 0) {
20263             ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20264             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20265             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set access mode to neither SND_PCM_ACCESS_MMAP_INTERLEAVED nor SND_PCM_ACCESS_RW_INTERLEAVED. snd_pcm_hw_params_set_access() failed.", ma_result_from_errno(-resultALSA));
20266         }
20267     }
20268
20269     /*
20270     Most important properties first. The documentation for OSS (yes, I know this is ALSA!) recommends format, channels, then sample rate. I can't
20271     find any documentation for ALSA specifically, so I'm going to copy the recommendation for OSS.
20272     */
20273
20274     /* Format. */
20275     {
20276         /*
20277         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
20278         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.
20279         */
20280         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) {
20281             /* We're either requesting the native format or the specified format is not supported. */
20282             size_t iFormat;
20283
20284             formatALSA = MA_SND_PCM_FORMAT_UNKNOWN;
20285             for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); ++iFormat) {
20286                 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) {
20287                     formatALSA = ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat]);
20288                     break;
20289                 }
20290             }
20291
20292             if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) {
20293                 ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20294                 ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20295                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.", MA_FORMAT_NOT_SUPPORTED);
20296             }
20297         }
20298
20299         resultALSA = ((ma_snd_pcm_hw_params_set_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA);
20300         if (resultALSA < 0) {
20301             ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20302             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20303             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.", ma_result_from_errno(-resultALSA));
20304         }
20305
20306         internalFormat = ma_format_from_alsa(formatALSA);
20307         if (internalFormat == ma_format_unknown) {
20308             ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20309             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20310             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
20311         }
20312     }
20313
20314     /* Channels. */
20315     {
20316         unsigned int channels = pDescriptor->channels;
20317         if (channels == 0) {
20318             channels = MA_DEFAULT_CHANNELS;
20319         }
20320
20321         resultALSA = ((ma_snd_pcm_hw_params_set_channels_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels);
20322         if (resultALSA < 0) {
20323             ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20324             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20325             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.", ma_result_from_errno(-resultALSA));
20326         }
20327
20328         internalChannels = (ma_uint32)channels;
20329     }
20330
20331     /* Sample Rate */
20332     {
20333         unsigned int sampleRate;
20334
20335         /*
20336         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
20337         problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable
20338         resampling.
20339
20340         To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a
20341         sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling
20342         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
20343         faster rate.
20344
20345         miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine
20346         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
20347         good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion.
20348
20349         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
20350         this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins.
20351         */
20352         ((ma_snd_pcm_hw_params_set_rate_resample_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM, pHWParams, 0);
20353
20354         sampleRate = pDescriptor->sampleRate;
20355         if (sampleRate == 0) {
20356             sampleRate = MA_DEFAULT_SAMPLE_RATE;
20357         }
20358
20359         resultALSA = ((ma_snd_pcm_hw_params_set_rate_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0);
20360         if (resultALSA < 0) {
20361             ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20362             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20363             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.", ma_result_from_errno(-resultALSA));
20364         }
20365
20366         internalSampleRate = (ma_uint32)sampleRate;
20367     }
20368
20369     /* Periods. */
20370     {
20371         ma_uint32 periods = pDescriptor->periodCount;
20372
20373         resultALSA = ((ma_snd_pcm_hw_params_set_periods_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL);
20374         if (resultALSA < 0) {
20375             ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20376             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20377             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.", ma_result_from_errno(-resultALSA));
20378         }
20379
20380         internalPeriods = periods;
20381     }
20382
20383     /* Buffer Size */
20384     {
20385         ma_snd_pcm_uframes_t actualBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile) * internalPeriods;
20386
20387         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);
20388         if (resultALSA < 0) {
20389             ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20390             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20391             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.", ma_result_from_errno(-resultALSA));
20392         }
20393
20394         internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods;
20395     }
20396
20397     /* Apply hardware parameters. */
20398     resultALSA = ((ma_snd_pcm_hw_params_proc)pDevice->pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams);
20399     if (resultALSA < 0) {
20400         ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20401         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20402         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set hardware parameters. snd_pcm_hw_params() failed.", ma_result_from_errno(-resultALSA));
20403     }
20404
20405     ma__free_from_callbacks(pHWParams, &pDevice->pContext->allocationCallbacks);
20406     pHWParams = NULL;
20407
20408
20409     /* Software parameters. */
20410     pSWParams = (ma_snd_pcm_sw_params_t*)ma__calloc_from_callbacks(((ma_snd_pcm_sw_params_sizeof_proc)pDevice->pContext->alsa.snd_pcm_sw_params_sizeof)(), &pDevice->pContext->allocationCallbacks);
20411     if (pSWParams == NULL) {
20412         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20413         return MA_OUT_OF_MEMORY;
20414     }
20415
20416     resultALSA = ((ma_snd_pcm_sw_params_current_proc)pDevice->pContext->alsa.snd_pcm_sw_params_current)(pPCM, pSWParams);
20417     if (resultALSA < 0) {
20418         ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks);
20419         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20420         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to initialize software parameters. snd_pcm_sw_params_current() failed.", ma_result_from_errno(-resultALSA));
20421     }
20422
20423     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));
20424     if (resultALSA < 0) {
20425         ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks);
20426         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20427         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_sw_params_set_avail_min() failed.", ma_result_from_errno(-resultALSA));
20428     }
20429
20430     resultALSA = ((ma_snd_pcm_sw_params_get_boundary_proc)pDevice->pContext->alsa.snd_pcm_sw_params_get_boundary)(pSWParams, &bufferBoundary);
20431     if (resultALSA < 0) {
20432         bufferBoundary = internalPeriodSizeInFrames * internalPeriods;
20433     }
20434
20435     /*printf("TRACE: bufferBoundary=%ld\n", bufferBoundary);*/
20436
20437     if (deviceType == ma_device_type_playback && !isUsingMMap) {   /* Only playback devices in writei/readi mode need a start threshold. */
20438         /*
20439         Subtle detail here with the start threshold. When in playback-only mode (no full-duplex) we can set the start threshold to
20440         the size of a period. But for full-duplex we need to set it such that it is at least two periods.
20441         */
20442         resultALSA = ((ma_snd_pcm_sw_params_set_start_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_start_threshold)(pPCM, pSWParams, internalPeriodSizeInFrames*2);
20443         if (resultALSA < 0) {
20444             ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks);
20445             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20446             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set start threshold for playback device. snd_pcm_sw_params_set_start_threshold() failed.", ma_result_from_errno(-resultALSA));
20447         }
20448
20449         resultALSA = ((ma_snd_pcm_sw_params_set_stop_threshold_proc)pDevice->pContext->alsa.snd_pcm_sw_params_set_stop_threshold)(pPCM, pSWParams, bufferBoundary);
20450         if (resultALSA < 0) { /* Set to boundary to loop instead of stop in the event of an xrun. */
20451             ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks);
20452             ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20453             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set stop threshold for playback device. snd_pcm_sw_params_set_stop_threshold() failed.", ma_result_from_errno(-resultALSA));
20454         }
20455     }
20456
20457     resultALSA = ((ma_snd_pcm_sw_params_proc)pDevice->pContext->alsa.snd_pcm_sw_params)(pPCM, pSWParams);
20458     if (resultALSA < 0) {
20459         ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks);
20460         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20461         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set software parameters. snd_pcm_sw_params() failed.", ma_result_from_errno(-resultALSA));
20462     }
20463
20464     ma__free_from_callbacks(pSWParams, &pDevice->pContext->allocationCallbacks);
20465     pSWParams = NULL;
20466
20467
20468     /* 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. */
20469     {
20470         ma_snd_pcm_chmap_t* pChmap = ((ma_snd_pcm_get_chmap_proc)pDevice->pContext->alsa.snd_pcm_get_chmap)(pPCM);
20471         if (pChmap != NULL) {
20472             ma_uint32 iChannel;
20473
20474             /* 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(). */
20475             if (pChmap->channels >= internalChannels) {
20476                 /* Drop excess channels. */
20477                 for (iChannel = 0; iChannel < internalChannels; ++iChannel) {
20478                     internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
20479                 }
20480             } else {
20481                 ma_uint32 i;
20482
20483                 /*
20484                 Excess channels use defaults. Do an initial fill with defaults, overwrite the first pChmap->channels, validate to ensure there are no duplicate
20485                 channels. If validation fails, fall back to defaults.
20486                 */
20487                 ma_bool32 isValid = MA_TRUE;
20488
20489                 /* Fill with defaults. */
20490                 ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
20491
20492                 /* Overwrite first pChmap->channels channels. */
20493                 for (iChannel = 0; iChannel < pChmap->channels; ++iChannel) {
20494                     internalChannelMap[iChannel] = ma_convert_alsa_channel_position_to_ma_channel(pChmap->pos[iChannel]);
20495                 }
20496
20497                 /* Validate. */
20498                 for (i = 0; i < internalChannels && isValid; ++i) {
20499                     ma_uint32 j;
20500                     for (j = i+1; j < internalChannels; ++j) {
20501                         if (internalChannelMap[i] == internalChannelMap[j]) {
20502                             isValid = MA_FALSE;
20503                             break;
20504                         }
20505                     }
20506                 }
20507
20508                 /* If our channel map is invalid, fall back to defaults. */
20509                 if (!isValid) {
20510                     ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
20511                 }
20512             }
20513
20514             free(pChmap);
20515             pChmap = NULL;
20516         } else {
20517             /* Could not retrieve the channel map. Fall back to a hard-coded assumption. */
20518             ma_get_standard_channel_map(ma_standard_channel_map_alsa, internalChannels, internalChannelMap);
20519         }
20520     }
20521
20522
20523     /* We're done. Prepare the device. */
20524     resultALSA = ((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)(pPCM);
20525     if (resultALSA < 0) {
20526         ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
20527         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to prepare device.", ma_result_from_errno(-resultALSA));
20528     }
20529
20530
20531     if (deviceType == ma_device_type_capture) {
20532         pDevice->alsa.pPCMCapture         = (ma_ptr)pPCM;
20533         pDevice->alsa.isUsingMMapCapture  = isUsingMMap;
20534     } else {
20535         pDevice->alsa.pPCMPlayback        = (ma_ptr)pPCM;
20536         pDevice->alsa.isUsingMMapPlayback = isUsingMMap;
20537     }
20538
20539     pDescriptor->format             = internalFormat;
20540     pDescriptor->channels           = internalChannels;
20541     pDescriptor->sampleRate         = internalSampleRate;
20542     ma_channel_map_copy(pDescriptor->channelMap, internalChannelMap, ma_min(internalChannels, MA_MAX_CHANNELS));
20543     pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames;
20544     pDescriptor->periodCount        = internalPeriods;
20545
20546     /*printf("format=%d; channels=%d; sampleRate=%d; periodSizeInFrames=%d; periodCount=%d\n", internalFormat, internalChannels, internalSampleRate, internalPeriodSizeInFrames, internalPeriods);*/
20547
20548     return MA_SUCCESS;
20549 }
20550
20551 static ma_result ma_device_init__alsa(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
20552 {
20553     MA_ASSERT(pDevice != NULL);
20554
20555     MA_ZERO_OBJECT(&pDevice->alsa);
20556
20557     if (pConfig->deviceType == ma_device_type_loopback) {
20558         return MA_DEVICE_TYPE_NOT_SUPPORTED;
20559     }
20560
20561     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
20562         ma_result result = ma_device_init_by_type__alsa(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
20563         if (result != MA_SUCCESS) {
20564             return result;
20565         }
20566     }
20567
20568     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
20569         ma_result result = ma_device_init_by_type__alsa(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
20570         if (result != MA_SUCCESS) {
20571             return result;
20572         }
20573     }
20574
20575     return MA_SUCCESS;
20576 }
20577
20578 static ma_result ma_device_start__alsa(ma_device* pDevice)
20579 {
20580     int resultALSA;
20581
20582     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
20583         resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
20584         if (resultALSA < 0) {
20585             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start capture device.", ma_result_from_errno(-resultALSA));
20586         }
20587     }
20588
20589     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20590         /* Don't need to do anything for playback because it'll be started automatically when enough data has been written. */
20591     }
20592
20593     return MA_SUCCESS;
20594 }
20595
20596 static ma_result ma_device_stop__alsa(ma_device* pDevice)
20597 {
20598     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
20599         ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
20600
20601         /* We need to prepare the device again, otherwise we won't be able to restart the device. */
20602         if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) {
20603     #ifdef MA_DEBUG_OUTPUT
20604             printf("[ALSA] Failed to prepare capture device after stopping.\n");
20605     #endif
20606         }
20607     }
20608
20609     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
20610         ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
20611
20612         /* We need to prepare the device again, otherwise we won't be able to restart the device. */
20613         if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) {
20614     #ifdef MA_DEBUG_OUTPUT
20615             printf("[ALSA] Failed to prepare playback device after stopping.\n");
20616     #endif
20617         }
20618     }
20619
20620     return MA_SUCCESS;
20621 }
20622
20623 static ma_result ma_device_read__alsa(ma_device* pDevice, void* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead)
20624 {
20625     ma_snd_pcm_sframes_t resultALSA;
20626
20627     MA_ASSERT(pDevice != NULL);
20628     MA_ASSERT(pFramesOut != NULL);
20629
20630     if (pFramesRead != NULL) {
20631         *pFramesRead = 0;
20632     }
20633
20634     for (;;) {
20635         resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pFramesOut, frameCount);
20636         if (resultALSA >= 0) {
20637             break;  /* Success. */
20638         } else {
20639             if (resultALSA == -EAGAIN) {
20640                 /*printf("TRACE: EGAIN (read)\n");*/
20641                 continue;   /* Try again. */
20642             } else if (resultALSA == -EPIPE) {
20643             #if defined(MA_DEBUG_OUTPUT)
20644                 printf("TRACE: EPIPE (read)\n");
20645             #endif
20646
20647                 /* Overrun. Recover and try again. If this fails we need to return an error. */
20648                 resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, resultALSA, MA_TRUE);
20649                 if (resultALSA < 0) {
20650                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after overrun.", ma_result_from_errno((int)-resultALSA));
20651                 }
20652
20653                 resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture);
20654                 if (resultALSA < 0) {
20655                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA));
20656                 }
20657
20658                 resultALSA = ((ma_snd_pcm_readi_proc)pDevice->pContext->alsa.snd_pcm_readi)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture, pFramesOut, frameCount);
20659                 if (resultALSA < 0) {
20660                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to read data from the internal device.", ma_result_from_errno((int)-resultALSA));
20661                 }
20662             }
20663         }
20664     }
20665
20666     if (pFramesRead != NULL) {
20667         *pFramesRead = resultALSA;
20668     }
20669
20670     return MA_SUCCESS;
20671 }
20672
20673 static ma_result ma_device_write__alsa(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
20674 {
20675     ma_snd_pcm_sframes_t resultALSA;
20676
20677     MA_ASSERT(pDevice != NULL);
20678     MA_ASSERT(pFrames != NULL);
20679
20680     if (pFramesWritten != NULL) {
20681         *pFramesWritten = 0;
20682     }
20683
20684     for (;;) {
20685         resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pFrames, frameCount);
20686         if (resultALSA >= 0) {
20687             break;  /* Success. */
20688         } else {
20689             if (resultALSA == -EAGAIN) {
20690                 /*printf("TRACE: EGAIN (write)\n");*/
20691                 continue;   /* Try again. */
20692             } else if (resultALSA == -EPIPE) {
20693             #if defined(MA_DEBUG_OUTPUT)
20694                 printf("TRACE: EPIPE (write)\n");
20695             #endif
20696
20697                 /* Underrun. Recover and try again. If this fails we need to return an error. */
20698                 resultALSA = ((ma_snd_pcm_recover_proc)pDevice->pContext->alsa.snd_pcm_recover)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, resultALSA, MA_TRUE);
20699                 if (resultALSA < 0) { /* MA_TRUE=silent (don't print anything on error). */
20700                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to recover device after underrun.", ma_result_from_errno((int)-resultALSA));
20701                 }
20702
20703                 /*
20704                 In my testing I have had a situation where writei() does not automatically restart the device even though I've set it
20705                 up as such in the software parameters. What will happen is writei() will block indefinitely even though the number of
20706                 frames is well beyond the auto-start threshold. To work around this I've needed to add an explicit start here. Not sure
20707                 if this is me just being stupid and not recovering the device properly, but this definitely feels like something isn't
20708                 quite right here.
20709                 */
20710                 resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback);
20711                 if (resultALSA < 0) {
20712                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start device after underrun.", ma_result_from_errno((int)-resultALSA));
20713                 }
20714
20715                 resultALSA = ((ma_snd_pcm_writei_proc)pDevice->pContext->alsa.snd_pcm_writei)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback, pFrames, frameCount);
20716                 if (resultALSA < 0) {
20717                     return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[ALSA] Failed to write data to device after underrun.", ma_result_from_errno((int)-resultALSA));
20718                 }
20719             }
20720         }
20721     }
20722
20723     if (pFramesWritten != NULL) {
20724         *pFramesWritten = resultALSA;
20725     }
20726
20727     return MA_SUCCESS;
20728 }
20729
20730 static ma_result ma_context_uninit__alsa(ma_context* pContext)
20731 {
20732     MA_ASSERT(pContext != NULL);
20733     MA_ASSERT(pContext->backend == ma_backend_alsa);
20734
20735     /* Clean up memory for memory leak checkers. */
20736     ((ma_snd_config_update_free_global_proc)pContext->alsa.snd_config_update_free_global)();
20737
20738 #ifndef MA_NO_RUNTIME_LINKING
20739     ma_dlclose(pContext, pContext->alsa.asoundSO);
20740 #endif
20741
20742     ma_mutex_uninit(&pContext->alsa.internalDeviceEnumLock);
20743
20744     return MA_SUCCESS;
20745 }
20746
20747 static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
20748 {
20749 #ifndef MA_NO_RUNTIME_LINKING
20750     const char* libasoundNames[] = {
20751         "libasound.so.2",
20752         "libasound.so"
20753     };
20754     size_t i;
20755
20756     for (i = 0; i < ma_countof(libasoundNames); ++i) {
20757         pContext->alsa.asoundSO = ma_dlopen(pContext, libasoundNames[i]);
20758         if (pContext->alsa.asoundSO != NULL) {
20759             break;
20760         }
20761     }
20762
20763     if (pContext->alsa.asoundSO == NULL) {
20764 #ifdef MA_DEBUG_OUTPUT
20765         printf("[ALSA] Failed to open shared object.\n");
20766 #endif
20767         return MA_NO_BACKEND;
20768     }
20769
20770     pContext->alsa.snd_pcm_open                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_open");
20771     pContext->alsa.snd_pcm_close                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_close");
20772     pContext->alsa.snd_pcm_hw_params_sizeof               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof");
20773     pContext->alsa.snd_pcm_hw_params_any                  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_any");
20774     pContext->alsa.snd_pcm_hw_params_set_format           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format");
20775     pContext->alsa.snd_pcm_hw_params_set_format_first     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first");
20776     pContext->alsa.snd_pcm_hw_params_get_format_mask      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask");
20777     pContext->alsa.snd_pcm_hw_params_set_channels         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels");
20778     pContext->alsa.snd_pcm_hw_params_set_channels_near    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near");
20779     pContext->alsa.snd_pcm_hw_params_set_channels_minmax  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_minmax");
20780     pContext->alsa.snd_pcm_hw_params_set_rate_resample    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample");
20781     pContext->alsa.snd_pcm_hw_params_set_rate             = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate");
20782     pContext->alsa.snd_pcm_hw_params_set_rate_near        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near");
20783     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");
20784     pContext->alsa.snd_pcm_hw_params_set_periods_near     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near");
20785     pContext->alsa.snd_pcm_hw_params_set_access           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access");
20786     pContext->alsa.snd_pcm_hw_params_get_format           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format");
20787     pContext->alsa.snd_pcm_hw_params_get_channels         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels");
20788     pContext->alsa.snd_pcm_hw_params_get_channels_min     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min");
20789     pContext->alsa.snd_pcm_hw_params_get_channels_max     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max");
20790     pContext->alsa.snd_pcm_hw_params_get_rate             = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate");
20791     pContext->alsa.snd_pcm_hw_params_get_rate_min         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min");
20792     pContext->alsa.snd_pcm_hw_params_get_rate_max         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max");
20793     pContext->alsa.snd_pcm_hw_params_get_buffer_size      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size");
20794     pContext->alsa.snd_pcm_hw_params_get_periods          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods");
20795     pContext->alsa.snd_pcm_hw_params_get_access           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access");
20796     pContext->alsa.snd_pcm_hw_params_test_format          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_format");
20797     pContext->alsa.snd_pcm_hw_params_test_channels        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_channels");
20798     pContext->alsa.snd_pcm_hw_params_test_rate            = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_test_rate");
20799     pContext->alsa.snd_pcm_hw_params                      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params");
20800     pContext->alsa.snd_pcm_sw_params_sizeof               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof");
20801     pContext->alsa.snd_pcm_sw_params_current              = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_current");
20802     pContext->alsa.snd_pcm_sw_params_get_boundary         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary");
20803     pContext->alsa.snd_pcm_sw_params_set_avail_min        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min");
20804     pContext->alsa.snd_pcm_sw_params_set_start_threshold  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold");
20805     pContext->alsa.snd_pcm_sw_params_set_stop_threshold   = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold");
20806     pContext->alsa.snd_pcm_sw_params                      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params");
20807     pContext->alsa.snd_pcm_format_mask_sizeof             = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof");
20808     pContext->alsa.snd_pcm_format_mask_test               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_test");
20809     pContext->alsa.snd_pcm_get_chmap                      = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_get_chmap");
20810     pContext->alsa.snd_pcm_state                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_state");
20811     pContext->alsa.snd_pcm_prepare                        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_prepare");
20812     pContext->alsa.snd_pcm_start                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_start");
20813     pContext->alsa.snd_pcm_drop                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drop");
20814     pContext->alsa.snd_pcm_drain                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drain");
20815     pContext->alsa.snd_device_name_hint                   = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_hint");
20816     pContext->alsa.snd_device_name_get_hint               = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_get_hint");
20817     pContext->alsa.snd_card_get_index                     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_card_get_index");
20818     pContext->alsa.snd_device_name_free_hint              = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_free_hint");
20819     pContext->alsa.snd_pcm_mmap_begin                     = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_begin");
20820     pContext->alsa.snd_pcm_mmap_commit                    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_commit");
20821     pContext->alsa.snd_pcm_recover                        = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_recover");
20822     pContext->alsa.snd_pcm_readi                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_readi");
20823     pContext->alsa.snd_pcm_writei                         = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_writei");
20824     pContext->alsa.snd_pcm_avail                          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail");
20825     pContext->alsa.snd_pcm_avail_update                   = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail_update");
20826     pContext->alsa.snd_pcm_wait                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_wait");
20827     pContext->alsa.snd_pcm_info                           = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info");
20828     pContext->alsa.snd_pcm_info_sizeof                    = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_sizeof");
20829     pContext->alsa.snd_pcm_info_get_name                  = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_get_name");
20830     pContext->alsa.snd_config_update_free_global          = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_config_update_free_global");
20831 #else
20832     /* The system below is just for type safety. */
20833     ma_snd_pcm_open_proc                           _snd_pcm_open                           = snd_pcm_open;
20834     ma_snd_pcm_close_proc                          _snd_pcm_close                          = snd_pcm_close;
20835     ma_snd_pcm_hw_params_sizeof_proc               _snd_pcm_hw_params_sizeof               = snd_pcm_hw_params_sizeof;
20836     ma_snd_pcm_hw_params_any_proc                  _snd_pcm_hw_params_any                  = snd_pcm_hw_params_any;
20837     ma_snd_pcm_hw_params_set_format_proc           _snd_pcm_hw_params_set_format           = snd_pcm_hw_params_set_format;
20838     ma_snd_pcm_hw_params_set_format_first_proc     _snd_pcm_hw_params_set_format_first     = snd_pcm_hw_params_set_format_first;
20839     ma_snd_pcm_hw_params_get_format_mask_proc      _snd_pcm_hw_params_get_format_mask      = snd_pcm_hw_params_get_format_mask;
20840     ma_snd_pcm_hw_params_set_channels_proc         _snd_pcm_hw_params_set_channels         = snd_pcm_hw_params_set_channels;
20841     ma_snd_pcm_hw_params_set_channels_near_proc    _snd_pcm_hw_params_set_channels_near    = snd_pcm_hw_params_set_channels_near;
20842     ma_snd_pcm_hw_params_set_rate_resample_proc    _snd_pcm_hw_params_set_rate_resample    = snd_pcm_hw_params_set_rate_resample;
20843     ma_snd_pcm_hw_params_set_rate_near             _snd_pcm_hw_params_set_rate             = snd_pcm_hw_params_set_rate;
20844     ma_snd_pcm_hw_params_set_rate_near_proc        _snd_pcm_hw_params_set_rate_near        = snd_pcm_hw_params_set_rate_near;
20845     ma_snd_pcm_hw_params_set_rate_minmax_proc      _snd_pcm_hw_params_set_rate_minmax      = snd_pcm_hw_params_set_rate_minmax;
20846     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;
20847     ma_snd_pcm_hw_params_set_periods_near_proc     _snd_pcm_hw_params_set_periods_near     = snd_pcm_hw_params_set_periods_near;
20848     ma_snd_pcm_hw_params_set_access_proc           _snd_pcm_hw_params_set_access           = snd_pcm_hw_params_set_access;
20849     ma_snd_pcm_hw_params_get_format_proc           _snd_pcm_hw_params_get_format           = snd_pcm_hw_params_get_format;
20850     ma_snd_pcm_hw_params_get_channels_proc         _snd_pcm_hw_params_get_channels         = snd_pcm_hw_params_get_channels;
20851     ma_snd_pcm_hw_params_get_channels_min_proc     _snd_pcm_hw_params_get_channels_min     = snd_pcm_hw_params_get_channels_min;
20852     ma_snd_pcm_hw_params_get_channels_max_proc     _snd_pcm_hw_params_get_channels_max     = snd_pcm_hw_params_get_channels_max;
20853     ma_snd_pcm_hw_params_get_rate_proc             _snd_pcm_hw_params_get_rate             = snd_pcm_hw_params_get_rate;
20854     ma_snd_pcm_hw_params_get_rate_min_proc         _snd_pcm_hw_params_get_rate_min         = snd_pcm_hw_params_get_rate_min;
20855     ma_snd_pcm_hw_params_get_rate_max_proc         _snd_pcm_hw_params_get_rate_max         = snd_pcm_hw_params_get_rate_max;
20856     ma_snd_pcm_hw_params_get_buffer_size_proc      _snd_pcm_hw_params_get_buffer_size      = snd_pcm_hw_params_get_buffer_size;
20857     ma_snd_pcm_hw_params_get_periods_proc          _snd_pcm_hw_params_get_periods          = snd_pcm_hw_params_get_periods;
20858     ma_snd_pcm_hw_params_get_access_proc           _snd_pcm_hw_params_get_access           = snd_pcm_hw_params_get_access;
20859     ma_snd_pcm_hw_params_test_format_proc          _snd_pcm_hw_params_test_format          = snd_pcm_hw_params_test_format;
20860     ma_snd_pcm_hw_params_test_channels_proc        _snd_pcm_hw_params_test_channels        = snd_pcm_hw_params_test_channels;
20861     ma_snd_pcm_hw_params_test_rate_proc            _snd_pcm_hw_params_test_rate            = snd_pcm_hw_params_test_rate;
20862     ma_snd_pcm_hw_params_proc                      _snd_pcm_hw_params                      = snd_pcm_hw_params;
20863     ma_snd_pcm_sw_params_sizeof_proc               _snd_pcm_sw_params_sizeof               = snd_pcm_sw_params_sizeof;
20864     ma_snd_pcm_sw_params_current_proc              _snd_pcm_sw_params_current              = snd_pcm_sw_params_current;
20865     ma_snd_pcm_sw_params_get_boundary_proc         _snd_pcm_sw_params_get_boundary         = snd_pcm_sw_params_get_boundary;
20866     ma_snd_pcm_sw_params_set_avail_min_proc        _snd_pcm_sw_params_set_avail_min        = snd_pcm_sw_params_set_avail_min;
20867     ma_snd_pcm_sw_params_set_start_threshold_proc  _snd_pcm_sw_params_set_start_threshold  = snd_pcm_sw_params_set_start_threshold;
20868     ma_snd_pcm_sw_params_set_stop_threshold_proc   _snd_pcm_sw_params_set_stop_threshold   = snd_pcm_sw_params_set_stop_threshold;
20869     ma_snd_pcm_sw_params_proc                      _snd_pcm_sw_params                      = snd_pcm_sw_params;
20870     ma_snd_pcm_format_mask_sizeof_proc             _snd_pcm_format_mask_sizeof             = snd_pcm_format_mask_sizeof;
20871     ma_snd_pcm_format_mask_test_proc               _snd_pcm_format_mask_test               = snd_pcm_format_mask_test;
20872     ma_snd_pcm_get_chmap_proc                      _snd_pcm_get_chmap                      = snd_pcm_get_chmap;
20873     ma_snd_pcm_state_proc                          _snd_pcm_state                          = snd_pcm_state;
20874     ma_snd_pcm_prepare_proc                        _snd_pcm_prepare                        = snd_pcm_prepare;
20875     ma_snd_pcm_start_proc                          _snd_pcm_start                          = snd_pcm_start;
20876     ma_snd_pcm_drop_proc                           _snd_pcm_drop                           = snd_pcm_drop;
20877     ma_snd_pcm_drain_proc                          _snd_pcm_drain                          = snd_pcm_drain;
20878     ma_snd_device_name_hint_proc                   _snd_device_name_hint                   = snd_device_name_hint;
20879     ma_snd_device_name_get_hint_proc               _snd_device_name_get_hint               = snd_device_name_get_hint;
20880     ma_snd_card_get_index_proc                     _snd_card_get_index                     = snd_card_get_index;
20881     ma_snd_device_name_free_hint_proc              _snd_device_name_free_hint              = snd_device_name_free_hint;
20882     ma_snd_pcm_mmap_begin_proc                     _snd_pcm_mmap_begin                     = snd_pcm_mmap_begin;
20883     ma_snd_pcm_mmap_commit_proc                    _snd_pcm_mmap_commit                    = snd_pcm_mmap_commit;
20884     ma_snd_pcm_recover_proc                        _snd_pcm_recover                        = snd_pcm_recover;
20885     ma_snd_pcm_readi_proc                          _snd_pcm_readi                          = snd_pcm_readi;
20886     ma_snd_pcm_writei_proc                         _snd_pcm_writei                         = snd_pcm_writei;
20887     ma_snd_pcm_avail_proc                          _snd_pcm_avail                          = snd_pcm_avail;
20888     ma_snd_pcm_avail_update_proc                   _snd_pcm_avail_update                   = snd_pcm_avail_update;
20889     ma_snd_pcm_wait_proc                           _snd_pcm_wait                           = snd_pcm_wait;
20890     ma_snd_pcm_info_proc                           _snd_pcm_info                           = snd_pcm_info;
20891     ma_snd_pcm_info_sizeof_proc                    _snd_pcm_info_sizeof                    = snd_pcm_info_sizeof;
20892     ma_snd_pcm_info_get_name_proc                  _snd_pcm_info_get_name                  = snd_pcm_info_get_name;
20893     ma_snd_config_update_free_global_proc          _snd_config_update_free_global          = snd_config_update_free_global;
20894
20895     pContext->alsa.snd_pcm_open                           = (ma_proc)_snd_pcm_open;
20896     pContext->alsa.snd_pcm_close                          = (ma_proc)_snd_pcm_close;
20897     pContext->alsa.snd_pcm_hw_params_sizeof               = (ma_proc)_snd_pcm_hw_params_sizeof;
20898     pContext->alsa.snd_pcm_hw_params_any                  = (ma_proc)_snd_pcm_hw_params_any;
20899     pContext->alsa.snd_pcm_hw_params_set_format           = (ma_proc)_snd_pcm_hw_params_set_format;
20900     pContext->alsa.snd_pcm_hw_params_set_format_first     = (ma_proc)_snd_pcm_hw_params_set_format_first;
20901     pContext->alsa.snd_pcm_hw_params_get_format_mask      = (ma_proc)_snd_pcm_hw_params_get_format_mask;
20902     pContext->alsa.snd_pcm_hw_params_set_channels         = (ma_proc)_snd_pcm_hw_params_set_channels;
20903     pContext->alsa.snd_pcm_hw_params_set_channels_near    = (ma_proc)_snd_pcm_hw_params_set_channels_near;
20904     pContext->alsa.snd_pcm_hw_params_set_channels_minmax  = (ma_proc)_snd_pcm_hw_params_set_channels_minmax;
20905     pContext->alsa.snd_pcm_hw_params_set_rate_resample    = (ma_proc)_snd_pcm_hw_params_set_rate_resample;
20906     pContext->alsa.snd_pcm_hw_params_set_rate             = (ma_proc)_snd_pcm_hw_params_set_rate;
20907     pContext->alsa.snd_pcm_hw_params_set_rate_near        = (ma_proc)_snd_pcm_hw_params_set_rate_near;
20908     pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)_snd_pcm_hw_params_set_buffer_size_near;
20909     pContext->alsa.snd_pcm_hw_params_set_periods_near     = (ma_proc)_snd_pcm_hw_params_set_periods_near;
20910     pContext->alsa.snd_pcm_hw_params_set_access           = (ma_proc)_snd_pcm_hw_params_set_access;
20911     pContext->alsa.snd_pcm_hw_params_get_format           = (ma_proc)_snd_pcm_hw_params_get_format;
20912     pContext->alsa.snd_pcm_hw_params_get_channels         = (ma_proc)_snd_pcm_hw_params_get_channels;
20913     pContext->alsa.snd_pcm_hw_params_get_channels_min     = (ma_proc)_snd_pcm_hw_params_get_channels_min;
20914     pContext->alsa.snd_pcm_hw_params_get_channels_max     = (ma_proc)_snd_pcm_hw_params_get_channels_max;
20915     pContext->alsa.snd_pcm_hw_params_get_rate             = (ma_proc)_snd_pcm_hw_params_get_rate;
20916     pContext->alsa.snd_pcm_hw_params_get_rate_min         = (ma_proc)_snd_pcm_hw_params_get_rate_min;
20917     pContext->alsa.snd_pcm_hw_params_get_rate_max         = (ma_proc)_snd_pcm_hw_params_get_rate_max;
20918     pContext->alsa.snd_pcm_hw_params_get_buffer_size      = (ma_proc)_snd_pcm_hw_params_get_buffer_size;
20919     pContext->alsa.snd_pcm_hw_params_get_periods          = (ma_proc)_snd_pcm_hw_params_get_periods;
20920     pContext->alsa.snd_pcm_hw_params_get_access           = (ma_proc)_snd_pcm_hw_params_get_access;
20921     pContext->alsa.snd_pcm_hw_params_test_format          = (ma_proc)_snd_pcm_hw_params_test_format;
20922     pContext->alsa.snd_pcm_hw_params_test_channels        = (ma_proc)_snd_pcm_hw_params_test_channels;
20923     pContext->alsa.snd_pcm_hw_params_test_rate            = (ma_proc)_snd_pcm_hw_params_test_rate;
20924     pContext->alsa.snd_pcm_hw_params                      = (ma_proc)_snd_pcm_hw_params;
20925     pContext->alsa.snd_pcm_sw_params_sizeof               = (ma_proc)_snd_pcm_sw_params_sizeof;
20926     pContext->alsa.snd_pcm_sw_params_current              = (ma_proc)_snd_pcm_sw_params_current;
20927     pContext->alsa.snd_pcm_sw_params_get_boundary         = (ma_proc)_snd_pcm_sw_params_get_boundary;
20928     pContext->alsa.snd_pcm_sw_params_set_avail_min        = (ma_proc)_snd_pcm_sw_params_set_avail_min;
20929     pContext->alsa.snd_pcm_sw_params_set_start_threshold  = (ma_proc)_snd_pcm_sw_params_set_start_threshold;
20930     pContext->alsa.snd_pcm_sw_params_set_stop_threshold   = (ma_proc)_snd_pcm_sw_params_set_stop_threshold;
20931     pContext->alsa.snd_pcm_sw_params                      = (ma_proc)_snd_pcm_sw_params;
20932     pContext->alsa.snd_pcm_format_mask_sizeof             = (ma_proc)_snd_pcm_format_mask_sizeof;
20933     pContext->alsa.snd_pcm_format_mask_test               = (ma_proc)_snd_pcm_format_mask_test;
20934     pContext->alsa.snd_pcm_get_chmap                      = (ma_proc)_snd_pcm_get_chmap;
20935     pContext->alsa.snd_pcm_state                          = (ma_proc)_snd_pcm_state;
20936     pContext->alsa.snd_pcm_prepare                        = (ma_proc)_snd_pcm_prepare;
20937     pContext->alsa.snd_pcm_start                          = (ma_proc)_snd_pcm_start;
20938     pContext->alsa.snd_pcm_drop                           = (ma_proc)_snd_pcm_drop;
20939     pContext->alsa.snd_pcm_drain                          = (ma_proc)_snd_pcm_drain;
20940     pContext->alsa.snd_device_name_hint                   = (ma_proc)_snd_device_name_hint;
20941     pContext->alsa.snd_device_name_get_hint               = (ma_proc)_snd_device_name_get_hint;
20942     pContext->alsa.snd_card_get_index                     = (ma_proc)_snd_card_get_index;
20943     pContext->alsa.snd_device_name_free_hint              = (ma_proc)_snd_device_name_free_hint;
20944     pContext->alsa.snd_pcm_mmap_begin                     = (ma_proc)_snd_pcm_mmap_begin;
20945     pContext->alsa.snd_pcm_mmap_commit                    = (ma_proc)_snd_pcm_mmap_commit;
20946     pContext->alsa.snd_pcm_recover                        = (ma_proc)_snd_pcm_recover;
20947     pContext->alsa.snd_pcm_readi                          = (ma_proc)_snd_pcm_readi;
20948     pContext->alsa.snd_pcm_writei                         = (ma_proc)_snd_pcm_writei;
20949     pContext->alsa.snd_pcm_avail                          = (ma_proc)_snd_pcm_avail;
20950     pContext->alsa.snd_pcm_avail_update                   = (ma_proc)_snd_pcm_avail_update;
20951     pContext->alsa.snd_pcm_wait                           = (ma_proc)_snd_pcm_wait;
20952     pContext->alsa.snd_pcm_info                           = (ma_proc)_snd_pcm_info;
20953     pContext->alsa.snd_pcm_info_sizeof                    = (ma_proc)_snd_pcm_info_sizeof;
20954     pContext->alsa.snd_pcm_info_get_name                  = (ma_proc)_snd_pcm_info_get_name;
20955     pContext->alsa.snd_config_update_free_global          = (ma_proc)_snd_config_update_free_global;
20956 #endif
20957
20958     pContext->alsa.useVerboseDeviceEnumeration = pConfig->alsa.useVerboseDeviceEnumeration;
20959
20960     if (ma_mutex_init(&pContext->alsa.internalDeviceEnumLock) != MA_SUCCESS) {
20961         ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[ALSA] WARNING: Failed to initialize mutex for internal device enumeration.", MA_ERROR);
20962     }
20963
20964     pCallbacks->onContextInit             = ma_context_init__alsa;
20965     pCallbacks->onContextUninit           = ma_context_uninit__alsa;
20966     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__alsa;
20967     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__alsa;
20968     pCallbacks->onDeviceInit              = ma_device_init__alsa;
20969     pCallbacks->onDeviceUninit            = ma_device_uninit__alsa;
20970     pCallbacks->onDeviceStart             = ma_device_start__alsa;
20971     pCallbacks->onDeviceStop              = ma_device_stop__alsa;
20972     pCallbacks->onDeviceRead              = ma_device_read__alsa;
20973     pCallbacks->onDeviceWrite             = ma_device_write__alsa;
20974     pCallbacks->onDeviceDataLoop          = NULL;
20975
20976     return MA_SUCCESS;
20977 }
20978 #endif  /* ALSA */
20979
20980
20981
20982 /******************************************************************************
20983
20984 PulseAudio Backend
20985
20986 ******************************************************************************/
20987 #ifdef MA_HAS_PULSEAUDIO
20988 /*
20989 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
20990 in the PulseAudio backend. I apologize if this gets a bit ranty for your liking - you might want to skip this discussion.
20991
20992 PulseAudio has something they call the "Simple API", which unfortunately isn't suitable for miniaudio. I've not seen anywhere where it
20993 allows you to enumerate over devices, nor does it seem to support the ability to stop and start streams. Looking at the documentation, it
20994 appears as though the stream is constantly running and you prevent sound from being emitted or captured by simply not calling the read or
20995 write functions. This is not a professional solution as it would be much better to *actually* stop the underlying stream. Perhaps the
20996 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
20997 when you want to have multiple streams to a single context. For these reasons, miniaudio is not using the simple API.
20998
20999 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
21000 get fun, and I don't mean that in a good way...
21001
21002 The problems start with the very name of the API - "asynchronous". Yes, this is an asynchronous oriented API which means your commands
21003 don't immediately take effect. You instead need to issue your commands, and then wait for them to complete. The waiting mechanism is
21004 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
21005 all of PulseAudio's problems stem from.
21006
21007 When you first initialize PulseAudio you need an object referred to as "main loop". You can implement this yourself by defining your own
21008 vtable, but it's much easier to just use one of the built-in main loop implementations. There's two generic implementations called
21009 pa_mainloop and pa_threaded_mainloop, and another implementation specific to GLib called pa_glib_mainloop. We're using pa_threaded_mainloop
21010 because it simplifies management of the worker thread. The idea of the main loop object is pretty self explanatory - you're supposed to use
21011 it to implement a worker thread which runs in a loop. The main loop is where operations are actually executed.
21012
21013 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
21014 to the vtable with `pa_threaded_mainloop_get_api()` (the main loop vtable is called `pa_mainloop_api`). Again, you can bypass the threaded
21015 main loop object entirely and just implement `pa_mainloop_api` directly, but there's no need for it unless you're doing something extremely
21016 specialized such as if you want to integrate it into your application's existing main loop infrastructure.
21017
21018 (EDIT 2021-01-26: miniaudio is no longer using `pa_threaded_mainloop` due to this issue: https://github.com/mackron/miniaudio/issues/262.
21019 It is now using `pa_mainloop` which turns out to be a simpler solution anyway. The rest of this rant still applies, however.)
21020
21021 Once you have your main loop vtable (the `pa_mainloop_api` object) you can create the PulseAudio context. This is very similar to
21022 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
21023 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
21024 is done with `pa_context_new()`, it's not actually connected to anything. When you connect, you call `pa_context_connect()`. However, if
21025 you remember, PulseAudio is an asynchronous API. That means you cannot just assume the context is connected after `pa_context_context()`
21026 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
21027 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.
21028 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.
21029 This waiting loop is therefore unavoidable. In order for the waiting to ever complete, however, the main loop needs to be running. Before
21030 attempting to connect the context, the main loop needs to be started with `pa_threaded_mainloop_start()`.
21031
21032 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
21033 internet connection. However, the *VAST* majority of cases don't involve this at all - they just connect to a local "server" running on the
21034 host machine. The fact that this would be the default rather than making `pa_context_connect()` synchronous tends to boggle the mind.
21035
21036 Once the context has been created and connected you can start creating a stream. A PulseAudio stream is analogous to miniaudio's device.
21037 The initialization of a stream is fairly standard - you configure some attributes (analogous to miniaudio's device config) and then call
21038 `pa_stream_new()` to actually create it. Here is where we start to get into "operations". When configuring the stream, you can get
21039 information about the source (such as sample format, sample rate, etc.), however it's not synchronous. Instead, a `pa_operation` object
21040 is returned from `pa_context_get_source_info_by_name()` (capture) or `pa_context_get_sink_info_by_name()` (playback). Then, you need to
21041 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
21042 context. Then, as an added bonus, you need to decrement the reference counter of the `pa_operation` object to ensure memory is cleaned up.
21043 All of that just to retrieve basic information about a device!
21044
21045 Once the basic information about the device has been retrieved, miniaudio can now create the stream with `ma_stream_new()`. Like the
21046 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
21047 choices in PulseAudio.
21048
21049 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
21050 because PulseAudio takes it literally, specifically the "can be". You would think these callbacks would be appropriate as the place for
21051 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
21052 set a flag that tells PulseAudio to not start the stream automatically. This is required because miniaudio does not auto-start devices
21053 straight after initialization - you need to call `ma_device_start()` manually. The problem is that even when this flag is specified,
21054 PulseAudio will immediately fire it's write or read callback. This is *technically* correct (based on the wording in the documentation)
21055 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
21056 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
21057 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
21058 that point (it may still need to load files or whatnot). Instead, this callback should only be fired when the application requests the
21059 stream be started which is how it works with literally *every* other callback-based audio API. Since miniaudio forbids firing of the data
21060 callback until the device has been started (as it should be with *all* callback based APIs), logic needs to be added to ensure miniaudio
21061 doesn't just blindly fire the application-defined data callback from within the PulseAudio callback before the stream has actually been
21062 started. The device state is used for this - if the state is anything other than `MA_STATE_STARTING` or `MA_STATE_STARTED`, the main data
21063 callback is not fired.
21064
21065 This, unfortunately, is not the end of the problems with the PulseAudio write callback. Any normal callback based audio API will
21066 continuously fire the callback at regular intervals based on the size of the internal buffer. This will only ever be fired when the device
21067 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
21068 PulseAudio. In PulseAudio, the data callback will *only* be called if you wrote something to it previously. That means, if you don't call
21069 `pa_stream_write()`, the callback will not get fired. On the surface you wouldn't think this would matter because you should be always
21070 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
21071 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
21072 *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
21073 important? Because that's how we've defined stopping to work in miniaudio. In miniaudio, stopping the device requires it to be drained
21074 before returning from ma_device_stop(). So we've stopped the device, which requires us to drain, but draining requires us to *not* write
21075 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!
21076
21077 This becomes a problem when stopping and then restarting the device. When the device is stopped, it's drained, which requires us to *not*
21078 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
21079 resume the stream naively. This means that starting the stream requires us to write data to the stream from outside the callback. This
21080 disconnect is something PulseAudio has got seriously wrong - there should only ever be a single source of data delivery, that being the
21081 callback. (I have tried using `pa_stream_flush()` to trigger the write callback to fire, but this just doesn't work for some reason.)
21082
21083 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,
21084 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
21085 "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
21086 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
21087 guessed it, asynchronous. This means you'll need our waiting loop as usual. Again, why this asynchronous design is the default is
21088 absolutely beyond me. Would it really be that hard to just make it run synchronously?
21089
21090 Teardown is pretty simple (what?!). It's just a matter of calling the relevant `_unref()` function on each object in reverse order that
21091 they were initialized in.
21092
21093 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
21094 embarrassingly unpractical. The main loop thing is an easy fix - have synchronous versions of all APIs. If an application wants these to
21095 run asynchronously, they can execute them in a separate thread themselves. The desire to run these asynchronously is such a niche
21096 requirement - it makes no sense to make it the default. The stream write callback needs to be change, or an alternative provided, that is
21097 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
21098 parameter which the program just writes to directly rather than having to call `pa_stream_writable_size()` and `pa_stream_write()`. These
21099 changes alone will change PulseAudio from one of the worst audio APIs to one of the best.
21100 */
21101
21102
21103 /*
21104 It is assumed pulseaudio.h is available when linking at compile time. When linking at compile time, we use the declarations in the header
21105 to check for type safety. We cannot do this when linking at run time because the header might not be available.
21106 */
21107 #ifdef MA_NO_RUNTIME_LINKING
21108
21109 /* pulseaudio.h marks some functions with "inline" which isn't always supported. Need to emulate it. */
21110 #if !defined(__cplusplus)
21111     #if defined(__STRICT_ANSI__)
21112         #if !defined(inline)
21113             #define inline __inline__ __attribute__((always_inline))
21114             #define MA_INLINE_DEFINED
21115         #endif
21116     #endif
21117 #endif
21118 #include <pulse/pulseaudio.h>
21119 #if defined(MA_INLINE_DEFINED)
21120     #undef inline
21121     #undef MA_INLINE_DEFINED
21122 #endif
21123
21124 #define MA_PA_OK                                       PA_OK
21125 #define MA_PA_ERR_ACCESS                               PA_ERR_ACCESS
21126 #define MA_PA_ERR_INVALID                              PA_ERR_INVALID
21127 #define MA_PA_ERR_NOENTITY                             PA_ERR_NOENTITY
21128
21129 #define MA_PA_CHANNELS_MAX                             PA_CHANNELS_MAX
21130 #define MA_PA_RATE_MAX                                 PA_RATE_MAX
21131
21132 typedef pa_context_flags_t ma_pa_context_flags_t;
21133 #define MA_PA_CONTEXT_NOFLAGS                          PA_CONTEXT_NOFLAGS
21134 #define MA_PA_CONTEXT_NOAUTOSPAWN                      PA_CONTEXT_NOAUTOSPAWN
21135 #define MA_PA_CONTEXT_NOFAIL                           PA_CONTEXT_NOFAIL
21136
21137 typedef pa_stream_flags_t ma_pa_stream_flags_t;
21138 #define MA_PA_STREAM_NOFLAGS                           PA_STREAM_NOFLAGS
21139 #define MA_PA_STREAM_START_CORKED                      PA_STREAM_START_CORKED
21140 #define MA_PA_STREAM_INTERPOLATE_TIMING                PA_STREAM_INTERPOLATE_TIMING
21141 #define MA_PA_STREAM_NOT_MONOTONIC                     PA_STREAM_NOT_MONOTONIC
21142 #define MA_PA_STREAM_AUTO_TIMING_UPDATE                PA_STREAM_AUTO_TIMING_UPDATE
21143 #define MA_PA_STREAM_NO_REMAP_CHANNELS                 PA_STREAM_NO_REMAP_CHANNELS
21144 #define MA_PA_STREAM_NO_REMIX_CHANNELS                 PA_STREAM_NO_REMIX_CHANNELS
21145 #define MA_PA_STREAM_FIX_FORMAT                        PA_STREAM_FIX_FORMAT
21146 #define MA_PA_STREAM_FIX_RATE                          PA_STREAM_FIX_RATE
21147 #define MA_PA_STREAM_FIX_CHANNELS                      PA_STREAM_FIX_CHANNELS
21148 #define MA_PA_STREAM_DONT_MOVE                         PA_STREAM_DONT_MOVE
21149 #define MA_PA_STREAM_VARIABLE_RATE                     PA_STREAM_VARIABLE_RATE
21150 #define MA_PA_STREAM_PEAK_DETECT                       PA_STREAM_PEAK_DETECT
21151 #define MA_PA_STREAM_START_MUTED                       PA_STREAM_START_MUTED
21152 #define MA_PA_STREAM_ADJUST_LATENCY                    PA_STREAM_ADJUST_LATENCY
21153 #define MA_PA_STREAM_EARLY_REQUESTS                    PA_STREAM_EARLY_REQUESTS
21154 #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND         PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
21155 #define MA_PA_STREAM_START_UNMUTED                     PA_STREAM_START_UNMUTED
21156 #define MA_PA_STREAM_FAIL_ON_SUSPEND                   PA_STREAM_FAIL_ON_SUSPEND
21157 #define MA_PA_STREAM_RELATIVE_VOLUME                   PA_STREAM_RELATIVE_VOLUME
21158 #define MA_PA_STREAM_PASSTHROUGH                       PA_STREAM_PASSTHROUGH
21159
21160 typedef pa_sink_flags_t ma_pa_sink_flags_t;
21161 #define MA_PA_SINK_NOFLAGS                             PA_SINK_NOFLAGS
21162 #define MA_PA_SINK_HW_VOLUME_CTRL                      PA_SINK_HW_VOLUME_CTRL
21163 #define MA_PA_SINK_LATENCY                             PA_SINK_LATENCY
21164 #define MA_PA_SINK_HARDWARE                            PA_SINK_HARDWARE
21165 #define MA_PA_SINK_NETWORK                             PA_SINK_NETWORK
21166 #define MA_PA_SINK_HW_MUTE_CTRL                        PA_SINK_HW_MUTE_CTRL
21167 #define MA_PA_SINK_DECIBEL_VOLUME                      PA_SINK_DECIBEL_VOLUME
21168 #define MA_PA_SINK_FLAT_VOLUME                         PA_SINK_FLAT_VOLUME
21169 #define MA_PA_SINK_DYNAMIC_LATENCY                     PA_SINK_DYNAMIC_LATENCY
21170 #define MA_PA_SINK_SET_FORMATS                         PA_SINK_SET_FORMATS
21171
21172 typedef pa_source_flags_t ma_pa_source_flags_t;
21173 #define MA_PA_SOURCE_NOFLAGS                           PA_SOURCE_NOFLAGS
21174 #define MA_PA_SOURCE_HW_VOLUME_CTRL                    PA_SOURCE_HW_VOLUME_CTRL
21175 #define MA_PA_SOURCE_LATENCY                           PA_SOURCE_LATENCY
21176 #define MA_PA_SOURCE_HARDWARE                          PA_SOURCE_HARDWARE
21177 #define MA_PA_SOURCE_NETWORK                           PA_SOURCE_NETWORK
21178 #define MA_PA_SOURCE_HW_MUTE_CTRL                      PA_SOURCE_HW_MUTE_CTRL
21179 #define MA_PA_SOURCE_DECIBEL_VOLUME                    PA_SOURCE_DECIBEL_VOLUME
21180 #define MA_PA_SOURCE_DYNAMIC_LATENCY                   PA_SOURCE_DYNAMIC_LATENCY
21181 #define MA_PA_SOURCE_FLAT_VOLUME                       PA_SOURCE_FLAT_VOLUME
21182
21183 typedef pa_context_state_t ma_pa_context_state_t;
21184 #define MA_PA_CONTEXT_UNCONNECTED                      PA_CONTEXT_UNCONNECTED
21185 #define MA_PA_CONTEXT_CONNECTING                       PA_CONTEXT_CONNECTING
21186 #define MA_PA_CONTEXT_AUTHORIZING                      PA_CONTEXT_AUTHORIZING
21187 #define MA_PA_CONTEXT_SETTING_NAME                     PA_CONTEXT_SETTING_NAME
21188 #define MA_PA_CONTEXT_READY                            PA_CONTEXT_READY
21189 #define MA_PA_CONTEXT_FAILED                           PA_CONTEXT_FAILED
21190 #define MA_PA_CONTEXT_TERMINATED                       PA_CONTEXT_TERMINATED
21191
21192 typedef pa_stream_state_t ma_pa_stream_state_t;
21193 #define MA_PA_STREAM_UNCONNECTED                       PA_STREAM_UNCONNECTED
21194 #define MA_PA_STREAM_CREATING                          PA_STREAM_CREATING
21195 #define MA_PA_STREAM_READY                             PA_STREAM_READY
21196 #define MA_PA_STREAM_FAILED                            PA_STREAM_FAILED
21197 #define MA_PA_STREAM_TERMINATED                        PA_STREAM_TERMINATED
21198
21199 typedef pa_operation_state_t ma_pa_operation_state_t;
21200 #define MA_PA_OPERATION_RUNNING                        PA_OPERATION_RUNNING
21201 #define MA_PA_OPERATION_DONE                           PA_OPERATION_DONE
21202 #define MA_PA_OPERATION_CANCELLED                      PA_OPERATION_CANCELLED
21203
21204 typedef pa_sink_state_t ma_pa_sink_state_t;
21205 #define MA_PA_SINK_INVALID_STATE                       PA_SINK_INVALID_STATE
21206 #define MA_PA_SINK_RUNNING                             PA_SINK_RUNNING
21207 #define MA_PA_SINK_IDLE                                PA_SINK_IDLE
21208 #define MA_PA_SINK_SUSPENDED                           PA_SINK_SUSPENDED
21209
21210 typedef pa_source_state_t ma_pa_source_state_t;
21211 #define MA_PA_SOURCE_INVALID_STATE                     PA_SOURCE_INVALID_STATE
21212 #define MA_PA_SOURCE_RUNNING                           PA_SOURCE_RUNNING
21213 #define MA_PA_SOURCE_IDLE                              PA_SOURCE_IDLE
21214 #define MA_PA_SOURCE_SUSPENDED                         PA_SOURCE_SUSPENDED
21215
21216 typedef pa_seek_mode_t ma_pa_seek_mode_t;
21217 #define MA_PA_SEEK_RELATIVE                            PA_SEEK_RELATIVE
21218 #define MA_PA_SEEK_ABSOLUTE                            PA_SEEK_ABSOLUTE
21219 #define MA_PA_SEEK_RELATIVE_ON_READ                    PA_SEEK_RELATIVE_ON_READ
21220 #define MA_PA_SEEK_RELATIVE_END                        PA_SEEK_RELATIVE_END
21221
21222 typedef pa_channel_position_t ma_pa_channel_position_t;
21223 #define MA_PA_CHANNEL_POSITION_INVALID                 PA_CHANNEL_POSITION_INVALID
21224 #define MA_PA_CHANNEL_POSITION_MONO                    PA_CHANNEL_POSITION_MONO
21225 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT              PA_CHANNEL_POSITION_FRONT_LEFT
21226 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT             PA_CHANNEL_POSITION_FRONT_RIGHT
21227 #define MA_PA_CHANNEL_POSITION_FRONT_CENTER            PA_CHANNEL_POSITION_FRONT_CENTER
21228 #define MA_PA_CHANNEL_POSITION_REAR_CENTER             PA_CHANNEL_POSITION_REAR_CENTER
21229 #define MA_PA_CHANNEL_POSITION_REAR_LEFT               PA_CHANNEL_POSITION_REAR_LEFT
21230 #define MA_PA_CHANNEL_POSITION_REAR_RIGHT              PA_CHANNEL_POSITION_REAR_RIGHT
21231 #define MA_PA_CHANNEL_POSITION_LFE                     PA_CHANNEL_POSITION_LFE
21232 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER    PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
21233 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER   PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
21234 #define MA_PA_CHANNEL_POSITION_SIDE_LEFT               PA_CHANNEL_POSITION_SIDE_LEFT
21235 #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT              PA_CHANNEL_POSITION_SIDE_RIGHT
21236 #define MA_PA_CHANNEL_POSITION_AUX0                    PA_CHANNEL_POSITION_AUX0
21237 #define MA_PA_CHANNEL_POSITION_AUX1                    PA_CHANNEL_POSITION_AUX1
21238 #define MA_PA_CHANNEL_POSITION_AUX2                    PA_CHANNEL_POSITION_AUX2
21239 #define MA_PA_CHANNEL_POSITION_AUX3                    PA_CHANNEL_POSITION_AUX3
21240 #define MA_PA_CHANNEL_POSITION_AUX4                    PA_CHANNEL_POSITION_AUX4
21241 #define MA_PA_CHANNEL_POSITION_AUX5                    PA_CHANNEL_POSITION_AUX5
21242 #define MA_PA_CHANNEL_POSITION_AUX6                    PA_CHANNEL_POSITION_AUX6
21243 #define MA_PA_CHANNEL_POSITION_AUX7                    PA_CHANNEL_POSITION_AUX7
21244 #define MA_PA_CHANNEL_POSITION_AUX8                    PA_CHANNEL_POSITION_AUX8
21245 #define MA_PA_CHANNEL_POSITION_AUX9                    PA_CHANNEL_POSITION_AUX9
21246 #define MA_PA_CHANNEL_POSITION_AUX10                   PA_CHANNEL_POSITION_AUX10
21247 #define MA_PA_CHANNEL_POSITION_AUX11                   PA_CHANNEL_POSITION_AUX11
21248 #define MA_PA_CHANNEL_POSITION_AUX12                   PA_CHANNEL_POSITION_AUX12
21249 #define MA_PA_CHANNEL_POSITION_AUX13                   PA_CHANNEL_POSITION_AUX13
21250 #define MA_PA_CHANNEL_POSITION_AUX14                   PA_CHANNEL_POSITION_AUX14
21251 #define MA_PA_CHANNEL_POSITION_AUX15                   PA_CHANNEL_POSITION_AUX15
21252 #define MA_PA_CHANNEL_POSITION_AUX16                   PA_CHANNEL_POSITION_AUX16
21253 #define MA_PA_CHANNEL_POSITION_AUX17                   PA_CHANNEL_POSITION_AUX17
21254 #define MA_PA_CHANNEL_POSITION_AUX18                   PA_CHANNEL_POSITION_AUX18
21255 #define MA_PA_CHANNEL_POSITION_AUX19                   PA_CHANNEL_POSITION_AUX19
21256 #define MA_PA_CHANNEL_POSITION_AUX20                   PA_CHANNEL_POSITION_AUX20
21257 #define MA_PA_CHANNEL_POSITION_AUX21                   PA_CHANNEL_POSITION_AUX21
21258 #define MA_PA_CHANNEL_POSITION_AUX22                   PA_CHANNEL_POSITION_AUX22
21259 #define MA_PA_CHANNEL_POSITION_AUX23                   PA_CHANNEL_POSITION_AUX23
21260 #define MA_PA_CHANNEL_POSITION_AUX24                   PA_CHANNEL_POSITION_AUX24
21261 #define MA_PA_CHANNEL_POSITION_AUX25                   PA_CHANNEL_POSITION_AUX25
21262 #define MA_PA_CHANNEL_POSITION_AUX26                   PA_CHANNEL_POSITION_AUX26
21263 #define MA_PA_CHANNEL_POSITION_AUX27                   PA_CHANNEL_POSITION_AUX27
21264 #define MA_PA_CHANNEL_POSITION_AUX28                   PA_CHANNEL_POSITION_AUX28
21265 #define MA_PA_CHANNEL_POSITION_AUX29                   PA_CHANNEL_POSITION_AUX29
21266 #define MA_PA_CHANNEL_POSITION_AUX30                   PA_CHANNEL_POSITION_AUX30
21267 #define MA_PA_CHANNEL_POSITION_AUX31                   PA_CHANNEL_POSITION_AUX31
21268 #define MA_PA_CHANNEL_POSITION_TOP_CENTER              PA_CHANNEL_POSITION_TOP_CENTER
21269 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT          PA_CHANNEL_POSITION_TOP_FRONT_LEFT
21270 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT         PA_CHANNEL_POSITION_TOP_FRONT_RIGHT
21271 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER        PA_CHANNEL_POSITION_TOP_FRONT_CENTER
21272 #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT           PA_CHANNEL_POSITION_TOP_REAR_LEFT
21273 #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT          PA_CHANNEL_POSITION_TOP_REAR_RIGHT
21274 #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER         PA_CHANNEL_POSITION_TOP_REAR_CENTER
21275 #define MA_PA_CHANNEL_POSITION_LEFT                    PA_CHANNEL_POSITION_LEFT
21276 #define MA_PA_CHANNEL_POSITION_RIGHT                   PA_CHANNEL_POSITION_RIGHT
21277 #define MA_PA_CHANNEL_POSITION_CENTER                  PA_CHANNEL_POSITION_CENTER
21278 #define MA_PA_CHANNEL_POSITION_SUBWOOFER               PA_CHANNEL_POSITION_SUBWOOFER
21279
21280 typedef pa_channel_map_def_t ma_pa_channel_map_def_t;
21281 #define MA_PA_CHANNEL_MAP_AIFF                         PA_CHANNEL_MAP_AIFF
21282 #define MA_PA_CHANNEL_MAP_ALSA                         PA_CHANNEL_MAP_ALSA
21283 #define MA_PA_CHANNEL_MAP_AUX                          PA_CHANNEL_MAP_AUX
21284 #define MA_PA_CHANNEL_MAP_WAVEEX                       PA_CHANNEL_MAP_WAVEEX
21285 #define MA_PA_CHANNEL_MAP_OSS                          PA_CHANNEL_MAP_OSS
21286 #define MA_PA_CHANNEL_MAP_DEFAULT                      PA_CHANNEL_MAP_DEFAULT
21287
21288 typedef pa_sample_format_t ma_pa_sample_format_t;
21289 #define MA_PA_SAMPLE_INVALID                           PA_SAMPLE_INVALID
21290 #define MA_PA_SAMPLE_U8                                PA_SAMPLE_U8
21291 #define MA_PA_SAMPLE_ALAW                              PA_SAMPLE_ALAW
21292 #define MA_PA_SAMPLE_ULAW                              PA_SAMPLE_ULAW
21293 #define MA_PA_SAMPLE_S16LE                             PA_SAMPLE_S16LE
21294 #define MA_PA_SAMPLE_S16BE                             PA_SAMPLE_S16BE
21295 #define MA_PA_SAMPLE_FLOAT32LE                         PA_SAMPLE_FLOAT32LE
21296 #define MA_PA_SAMPLE_FLOAT32BE                         PA_SAMPLE_FLOAT32BE
21297 #define MA_PA_SAMPLE_S32LE                             PA_SAMPLE_S32LE
21298 #define MA_PA_SAMPLE_S32BE                             PA_SAMPLE_S32BE
21299 #define MA_PA_SAMPLE_S24LE                             PA_SAMPLE_S24LE
21300 #define MA_PA_SAMPLE_S24BE                             PA_SAMPLE_S24BE
21301 #define MA_PA_SAMPLE_S24_32LE                          PA_SAMPLE_S24_32LE
21302 #define MA_PA_SAMPLE_S24_32BE                          PA_SAMPLE_S24_32BE
21303
21304 typedef pa_mainloop             ma_pa_mainloop;
21305 typedef pa_threaded_mainloop    ma_pa_threaded_mainloop;
21306 typedef pa_mainloop_api         ma_pa_mainloop_api;
21307 typedef pa_context              ma_pa_context;
21308 typedef pa_operation            ma_pa_operation;
21309 typedef pa_stream               ma_pa_stream;
21310 typedef pa_spawn_api            ma_pa_spawn_api;
21311 typedef pa_buffer_attr          ma_pa_buffer_attr;
21312 typedef pa_channel_map          ma_pa_channel_map;
21313 typedef pa_cvolume              ma_pa_cvolume;
21314 typedef pa_sample_spec          ma_pa_sample_spec;
21315 typedef pa_sink_info            ma_pa_sink_info;
21316 typedef pa_source_info          ma_pa_source_info;
21317
21318 typedef pa_context_notify_cb_t  ma_pa_context_notify_cb_t;
21319 typedef pa_sink_info_cb_t       ma_pa_sink_info_cb_t;
21320 typedef pa_source_info_cb_t     ma_pa_source_info_cb_t;
21321 typedef pa_stream_success_cb_t  ma_pa_stream_success_cb_t;
21322 typedef pa_stream_request_cb_t  ma_pa_stream_request_cb_t;
21323 typedef pa_free_cb_t            ma_pa_free_cb_t;
21324 #else
21325 #define MA_PA_OK                                       0
21326 #define MA_PA_ERR_ACCESS                               1
21327 #define MA_PA_ERR_INVALID                              2
21328 #define MA_PA_ERR_NOENTITY                             5
21329
21330 #define MA_PA_CHANNELS_MAX                             32
21331 #define MA_PA_RATE_MAX                                 384000
21332
21333 typedef int ma_pa_context_flags_t;
21334 #define MA_PA_CONTEXT_NOFLAGS                          0x00000000
21335 #define MA_PA_CONTEXT_NOAUTOSPAWN                      0x00000001
21336 #define MA_PA_CONTEXT_NOFAIL                           0x00000002
21337
21338 typedef int ma_pa_stream_flags_t;
21339 #define MA_PA_STREAM_NOFLAGS                           0x00000000
21340 #define MA_PA_STREAM_START_CORKED                      0x00000001
21341 #define MA_PA_STREAM_INTERPOLATE_TIMING                0x00000002
21342 #define MA_PA_STREAM_NOT_MONOTONIC                     0x00000004
21343 #define MA_PA_STREAM_AUTO_TIMING_UPDATE                0x00000008
21344 #define MA_PA_STREAM_NO_REMAP_CHANNELS                 0x00000010
21345 #define MA_PA_STREAM_NO_REMIX_CHANNELS                 0x00000020
21346 #define MA_PA_STREAM_FIX_FORMAT                        0x00000040
21347 #define MA_PA_STREAM_FIX_RATE                          0x00000080
21348 #define MA_PA_STREAM_FIX_CHANNELS                      0x00000100
21349 #define MA_PA_STREAM_DONT_MOVE                         0x00000200
21350 #define MA_PA_STREAM_VARIABLE_RATE                     0x00000400
21351 #define MA_PA_STREAM_PEAK_DETECT                       0x00000800
21352 #define MA_PA_STREAM_START_MUTED                       0x00001000
21353 #define MA_PA_STREAM_ADJUST_LATENCY                    0x00002000
21354 #define MA_PA_STREAM_EARLY_REQUESTS                    0x00004000
21355 #define MA_PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND         0x00008000
21356 #define MA_PA_STREAM_START_UNMUTED                     0x00010000
21357 #define MA_PA_STREAM_FAIL_ON_SUSPEND                   0x00020000
21358 #define MA_PA_STREAM_RELATIVE_VOLUME                   0x00040000
21359 #define MA_PA_STREAM_PASSTHROUGH                       0x00080000
21360
21361 typedef int ma_pa_sink_flags_t;
21362 #define MA_PA_SINK_NOFLAGS                             0x00000000
21363 #define MA_PA_SINK_HW_VOLUME_CTRL                      0x00000001
21364 #define MA_PA_SINK_LATENCY                             0x00000002
21365 #define MA_PA_SINK_HARDWARE                            0x00000004
21366 #define MA_PA_SINK_NETWORK                             0x00000008
21367 #define MA_PA_SINK_HW_MUTE_CTRL                        0x00000010
21368 #define MA_PA_SINK_DECIBEL_VOLUME                      0x00000020
21369 #define MA_PA_SINK_FLAT_VOLUME                         0x00000040
21370 #define MA_PA_SINK_DYNAMIC_LATENCY                     0x00000080
21371 #define MA_PA_SINK_SET_FORMATS                         0x00000100
21372
21373 typedef int ma_pa_source_flags_t;
21374 #define MA_PA_SOURCE_NOFLAGS                           0x00000000
21375 #define MA_PA_SOURCE_HW_VOLUME_CTRL                    0x00000001
21376 #define MA_PA_SOURCE_LATENCY                           0x00000002
21377 #define MA_PA_SOURCE_HARDWARE                          0x00000004
21378 #define MA_PA_SOURCE_NETWORK                           0x00000008
21379 #define MA_PA_SOURCE_HW_MUTE_CTRL                      0x00000010
21380 #define MA_PA_SOURCE_DECIBEL_VOLUME                    0x00000020
21381 #define MA_PA_SOURCE_DYNAMIC_LATENCY                   0x00000040
21382 #define MA_PA_SOURCE_FLAT_VOLUME                       0x00000080
21383
21384 typedef int ma_pa_context_state_t;
21385 #define MA_PA_CONTEXT_UNCONNECTED                      0
21386 #define MA_PA_CONTEXT_CONNECTING                       1
21387 #define MA_PA_CONTEXT_AUTHORIZING                      2
21388 #define MA_PA_CONTEXT_SETTING_NAME                     3
21389 #define MA_PA_CONTEXT_READY                            4
21390 #define MA_PA_CONTEXT_FAILED                           5
21391 #define MA_PA_CONTEXT_TERMINATED                       6
21392
21393 typedef int ma_pa_stream_state_t;
21394 #define MA_PA_STREAM_UNCONNECTED                       0
21395 #define MA_PA_STREAM_CREATING                          1
21396 #define MA_PA_STREAM_READY                             2
21397 #define MA_PA_STREAM_FAILED                            3
21398 #define MA_PA_STREAM_TERMINATED                        4
21399
21400 typedef int ma_pa_operation_state_t;
21401 #define MA_PA_OPERATION_RUNNING                        0
21402 #define MA_PA_OPERATION_DONE                           1
21403 #define MA_PA_OPERATION_CANCELLED                      2
21404
21405 typedef int ma_pa_sink_state_t;
21406 #define MA_PA_SINK_INVALID_STATE                       -1
21407 #define MA_PA_SINK_RUNNING                             0
21408 #define MA_PA_SINK_IDLE                                1
21409 #define MA_PA_SINK_SUSPENDED                           2
21410
21411 typedef int ma_pa_source_state_t;
21412 #define MA_PA_SOURCE_INVALID_STATE                     -1
21413 #define MA_PA_SOURCE_RUNNING                           0
21414 #define MA_PA_SOURCE_IDLE                              1
21415 #define MA_PA_SOURCE_SUSPENDED                         2
21416
21417 typedef int ma_pa_seek_mode_t;
21418 #define MA_PA_SEEK_RELATIVE                            0
21419 #define MA_PA_SEEK_ABSOLUTE                            1
21420 #define MA_PA_SEEK_RELATIVE_ON_READ                    2
21421 #define MA_PA_SEEK_RELATIVE_END                        3
21422
21423 typedef int ma_pa_channel_position_t;
21424 #define MA_PA_CHANNEL_POSITION_INVALID                 -1
21425 #define MA_PA_CHANNEL_POSITION_MONO                    0
21426 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT              1
21427 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT             2
21428 #define MA_PA_CHANNEL_POSITION_FRONT_CENTER            3
21429 #define MA_PA_CHANNEL_POSITION_REAR_CENTER             4
21430 #define MA_PA_CHANNEL_POSITION_REAR_LEFT               5
21431 #define MA_PA_CHANNEL_POSITION_REAR_RIGHT              6
21432 #define MA_PA_CHANNEL_POSITION_LFE                     7
21433 #define MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER    8
21434 #define MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER   9
21435 #define MA_PA_CHANNEL_POSITION_SIDE_LEFT               10
21436 #define MA_PA_CHANNEL_POSITION_SIDE_RIGHT              11
21437 #define MA_PA_CHANNEL_POSITION_AUX0                    12
21438 #define MA_PA_CHANNEL_POSITION_AUX1                    13
21439 #define MA_PA_CHANNEL_POSITION_AUX2                    14
21440 #define MA_PA_CHANNEL_POSITION_AUX3                    15
21441 #define MA_PA_CHANNEL_POSITION_AUX4                    16
21442 #define MA_PA_CHANNEL_POSITION_AUX5                    17
21443 #define MA_PA_CHANNEL_POSITION_AUX6                    18
21444 #define MA_PA_CHANNEL_POSITION_AUX7                    19
21445 #define MA_PA_CHANNEL_POSITION_AUX8                    20
21446 #define MA_PA_CHANNEL_POSITION_AUX9                    21
21447 #define MA_PA_CHANNEL_POSITION_AUX10                   22
21448 #define MA_PA_CHANNEL_POSITION_AUX11                   23
21449 #define MA_PA_CHANNEL_POSITION_AUX12                   24
21450 #define MA_PA_CHANNEL_POSITION_AUX13                   25
21451 #define MA_PA_CHANNEL_POSITION_AUX14                   26
21452 #define MA_PA_CHANNEL_POSITION_AUX15                   27
21453 #define MA_PA_CHANNEL_POSITION_AUX16                   28
21454 #define MA_PA_CHANNEL_POSITION_AUX17                   29
21455 #define MA_PA_CHANNEL_POSITION_AUX18                   30
21456 #define MA_PA_CHANNEL_POSITION_AUX19                   31
21457 #define MA_PA_CHANNEL_POSITION_AUX20                   32
21458 #define MA_PA_CHANNEL_POSITION_AUX21                   33
21459 #define MA_PA_CHANNEL_POSITION_AUX22                   34
21460 #define MA_PA_CHANNEL_POSITION_AUX23                   35
21461 #define MA_PA_CHANNEL_POSITION_AUX24                   36
21462 #define MA_PA_CHANNEL_POSITION_AUX25                   37
21463 #define MA_PA_CHANNEL_POSITION_AUX26                   38
21464 #define MA_PA_CHANNEL_POSITION_AUX27                   39
21465 #define MA_PA_CHANNEL_POSITION_AUX28                   40
21466 #define MA_PA_CHANNEL_POSITION_AUX29                   41
21467 #define MA_PA_CHANNEL_POSITION_AUX30                   42
21468 #define MA_PA_CHANNEL_POSITION_AUX31                   43
21469 #define MA_PA_CHANNEL_POSITION_TOP_CENTER              44
21470 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT          45
21471 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT         46
21472 #define MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER        47
21473 #define MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT           48
21474 #define MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT          49
21475 #define MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER         50
21476 #define MA_PA_CHANNEL_POSITION_LEFT                    MA_PA_CHANNEL_POSITION_FRONT_LEFT
21477 #define MA_PA_CHANNEL_POSITION_RIGHT                   MA_PA_CHANNEL_POSITION_FRONT_RIGHT
21478 #define MA_PA_CHANNEL_POSITION_CENTER                  MA_PA_CHANNEL_POSITION_FRONT_CENTER
21479 #define MA_PA_CHANNEL_POSITION_SUBWOOFER               MA_PA_CHANNEL_POSITION_LFE
21480
21481 typedef int ma_pa_channel_map_def_t;
21482 #define MA_PA_CHANNEL_MAP_AIFF                         0
21483 #define MA_PA_CHANNEL_MAP_ALSA                         1
21484 #define MA_PA_CHANNEL_MAP_AUX                          2
21485 #define MA_PA_CHANNEL_MAP_WAVEEX                       3
21486 #define MA_PA_CHANNEL_MAP_OSS                          4
21487 #define MA_PA_CHANNEL_MAP_DEFAULT                      MA_PA_CHANNEL_MAP_AIFF
21488
21489 typedef int ma_pa_sample_format_t;
21490 #define MA_PA_SAMPLE_INVALID                           -1
21491 #define MA_PA_SAMPLE_U8                                0
21492 #define MA_PA_SAMPLE_ALAW                              1
21493 #define MA_PA_SAMPLE_ULAW                              2
21494 #define MA_PA_SAMPLE_S16LE                             3
21495 #define MA_PA_SAMPLE_S16BE                             4
21496 #define MA_PA_SAMPLE_FLOAT32LE                         5
21497 #define MA_PA_SAMPLE_FLOAT32BE                         6
21498 #define MA_PA_SAMPLE_S32LE                             7
21499 #define MA_PA_SAMPLE_S32BE                             8
21500 #define MA_PA_SAMPLE_S24LE                             9
21501 #define MA_PA_SAMPLE_S24BE                             10
21502 #define MA_PA_SAMPLE_S24_32LE                          11
21503 #define MA_PA_SAMPLE_S24_32BE                          12
21504
21505 typedef struct ma_pa_mainloop           ma_pa_mainloop;
21506 typedef struct ma_pa_threaded_mainloop  ma_pa_threaded_mainloop;
21507 typedef struct ma_pa_mainloop_api       ma_pa_mainloop_api;
21508 typedef struct ma_pa_context            ma_pa_context;
21509 typedef struct ma_pa_operation          ma_pa_operation;
21510 typedef struct ma_pa_stream             ma_pa_stream;
21511 typedef struct ma_pa_spawn_api          ma_pa_spawn_api;
21512
21513 typedef struct
21514 {
21515     ma_uint32 maxlength;
21516     ma_uint32 tlength;
21517     ma_uint32 prebuf;
21518     ma_uint32 minreq;
21519     ma_uint32 fragsize;
21520 } ma_pa_buffer_attr;
21521
21522 typedef struct
21523 {
21524     ma_uint8 channels;
21525     ma_pa_channel_position_t map[MA_PA_CHANNELS_MAX];
21526 } ma_pa_channel_map;
21527
21528 typedef struct
21529 {
21530     ma_uint8 channels;
21531     ma_uint32 values[MA_PA_CHANNELS_MAX];
21532 } ma_pa_cvolume;
21533
21534 typedef struct
21535 {
21536     ma_pa_sample_format_t format;
21537     ma_uint32 rate;
21538     ma_uint8 channels;
21539 } ma_pa_sample_spec;
21540
21541 typedef struct
21542 {
21543     const char* name;
21544     ma_uint32 index;
21545     const char* description;
21546     ma_pa_sample_spec sample_spec;
21547     ma_pa_channel_map channel_map;
21548     ma_uint32 owner_module;
21549     ma_pa_cvolume volume;
21550     int mute;
21551     ma_uint32 monitor_source;
21552     const char* monitor_source_name;
21553     ma_uint64 latency;
21554     const char* driver;
21555     ma_pa_sink_flags_t flags;
21556     void* proplist;
21557     ma_uint64 configured_latency;
21558     ma_uint32 base_volume;
21559     ma_pa_sink_state_t state;
21560     ma_uint32 n_volume_steps;
21561     ma_uint32 card;
21562     ma_uint32 n_ports;
21563     void** ports;
21564     void* active_port;
21565     ma_uint8 n_formats;
21566     void** formats;
21567 } ma_pa_sink_info;
21568
21569 typedef struct
21570 {
21571     const char *name;
21572     ma_uint32 index;
21573     const char *description;
21574     ma_pa_sample_spec sample_spec;
21575     ma_pa_channel_map channel_map;
21576     ma_uint32 owner_module;
21577     ma_pa_cvolume volume;
21578     int mute;
21579     ma_uint32 monitor_of_sink;
21580     const char *monitor_of_sink_name;
21581     ma_uint64 latency;
21582     const char *driver;
21583     ma_pa_source_flags_t flags;
21584     void* proplist;
21585     ma_uint64 configured_latency;
21586     ma_uint32 base_volume;
21587     ma_pa_source_state_t state;
21588     ma_uint32 n_volume_steps;
21589     ma_uint32 card;
21590     ma_uint32 n_ports;
21591     void** ports;
21592     void* active_port;
21593     ma_uint8 n_formats;
21594     void** formats;
21595 } ma_pa_source_info;
21596
21597 typedef void (* ma_pa_context_notify_cb_t)(ma_pa_context* c, void* userdata);
21598 typedef void (* ma_pa_sink_info_cb_t)     (ma_pa_context* c, const ma_pa_sink_info* i, int eol, void* userdata);
21599 typedef void (* ma_pa_source_info_cb_t)   (ma_pa_context* c, const ma_pa_source_info* i, int eol, void* userdata);
21600 typedef void (* ma_pa_stream_success_cb_t)(ma_pa_stream* s, int success, void* userdata);
21601 typedef void (* ma_pa_stream_request_cb_t)(ma_pa_stream* s, size_t nbytes, void* userdata);
21602 typedef void (* ma_pa_free_cb_t)          (void* p);
21603 #endif
21604
21605
21606 typedef ma_pa_mainloop*          (* ma_pa_mainloop_new_proc)                   (void);
21607 typedef void                     (* ma_pa_mainloop_free_proc)                  (ma_pa_mainloop* m);
21608 typedef void                     (* ma_pa_mainloop_quit_proc)                  (ma_pa_mainloop* m, int retval);
21609 typedef ma_pa_mainloop_api*      (* ma_pa_mainloop_get_api_proc)               (ma_pa_mainloop* m);
21610 typedef int                      (* ma_pa_mainloop_iterate_proc)               (ma_pa_mainloop* m, int block, int* retval);
21611 typedef void                     (* ma_pa_mainloop_wakeup_proc)                (ma_pa_mainloop* m);
21612 typedef ma_pa_threaded_mainloop* (* ma_pa_threaded_mainloop_new_proc)          (void);
21613 typedef void                     (* ma_pa_threaded_mainloop_free_proc)         (ma_pa_threaded_mainloop* m);
21614 typedef int                      (* ma_pa_threaded_mainloop_start_proc)        (ma_pa_threaded_mainloop* m);
21615 typedef void                     (* ma_pa_threaded_mainloop_stop_proc)         (ma_pa_threaded_mainloop* m);
21616 typedef void                     (* ma_pa_threaded_mainloop_lock_proc)         (ma_pa_threaded_mainloop* m);
21617 typedef void                     (* ma_pa_threaded_mainloop_unlock_proc)       (ma_pa_threaded_mainloop* m);
21618 typedef void                     (* ma_pa_threaded_mainloop_wait_proc)         (ma_pa_threaded_mainloop* m);
21619 typedef void                     (* ma_pa_threaded_mainloop_signal_proc)       (ma_pa_threaded_mainloop* m, int wait_for_accept);
21620 typedef void                     (* ma_pa_threaded_mainloop_accept_proc)       (ma_pa_threaded_mainloop* m);
21621 typedef int                      (* ma_pa_threaded_mainloop_get_retval_proc)   (ma_pa_threaded_mainloop* m);
21622 typedef ma_pa_mainloop_api*      (* ma_pa_threaded_mainloop_get_api_proc)      (ma_pa_threaded_mainloop* m);
21623 typedef int                      (* ma_pa_threaded_mainloop_in_thread_proc)    (ma_pa_threaded_mainloop* m);
21624 typedef void                     (* ma_pa_threaded_mainloop_set_name_proc)     (ma_pa_threaded_mainloop* m, const char* name);
21625 typedef ma_pa_context*           (* ma_pa_context_new_proc)                    (ma_pa_mainloop_api* mainloop, const char* name);
21626 typedef void                     (* ma_pa_context_unref_proc)                  (ma_pa_context* c);
21627 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);
21628 typedef void                     (* ma_pa_context_disconnect_proc)             (ma_pa_context* c);
21629 typedef void                     (* ma_pa_context_set_state_callback_proc)     (ma_pa_context* c, ma_pa_context_notify_cb_t cb, void* userdata);
21630 typedef ma_pa_context_state_t    (* ma_pa_context_get_state_proc)              (ma_pa_context* c);
21631 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);
21632 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);
21633 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);
21634 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);
21635 typedef void                     (* ma_pa_operation_unref_proc)                (ma_pa_operation* o);
21636 typedef ma_pa_operation_state_t  (* ma_pa_operation_get_state_proc)            (ma_pa_operation* o);
21637 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);
21638 typedef int                      (* ma_pa_channel_map_valid_proc)              (const ma_pa_channel_map* m);
21639 typedef int                      (* ma_pa_channel_map_compatible_proc)         (const ma_pa_channel_map* m, const ma_pa_sample_spec* ss);
21640 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);
21641 typedef void                     (* ma_pa_stream_unref_proc)                   (ma_pa_stream* s);
21642 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);
21643 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);
21644 typedef int                      (* ma_pa_stream_disconnect_proc)              (ma_pa_stream* s);
21645 typedef ma_pa_stream_state_t     (* ma_pa_stream_get_state_proc)               (ma_pa_stream* s);
21646 typedef const ma_pa_sample_spec* (* ma_pa_stream_get_sample_spec_proc)         (ma_pa_stream* s);
21647 typedef const ma_pa_channel_map* (* ma_pa_stream_get_channel_map_proc)         (ma_pa_stream* s);
21648 typedef const ma_pa_buffer_attr* (* ma_pa_stream_get_buffer_attr_proc)         (ma_pa_stream* s);
21649 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);
21650 typedef const char*              (* ma_pa_stream_get_device_name_proc)         (ma_pa_stream* s);
21651 typedef void                     (* ma_pa_stream_set_write_callback_proc)      (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata);
21652 typedef void                     (* ma_pa_stream_set_read_callback_proc)       (ma_pa_stream* s, ma_pa_stream_request_cb_t cb, void* userdata);
21653 typedef ma_pa_operation*         (* ma_pa_stream_flush_proc)                   (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
21654 typedef ma_pa_operation*         (* ma_pa_stream_drain_proc)                   (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
21655 typedef int                      (* ma_pa_stream_is_corked_proc)               (ma_pa_stream* s);
21656 typedef ma_pa_operation*         (* ma_pa_stream_cork_proc)                    (ma_pa_stream* s, int b, ma_pa_stream_success_cb_t cb, void* userdata);
21657 typedef ma_pa_operation*         (* ma_pa_stream_trigger_proc)                 (ma_pa_stream* s, ma_pa_stream_success_cb_t cb, void* userdata);
21658 typedef int                      (* ma_pa_stream_begin_write_proc)             (ma_pa_stream* s, void** data, size_t* nbytes);
21659 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);
21660 typedef int                      (* ma_pa_stream_peek_proc)                    (ma_pa_stream* s, const void** data, size_t* nbytes);
21661 typedef int                      (* ma_pa_stream_drop_proc)                    (ma_pa_stream* s);
21662 typedef size_t                   (* ma_pa_stream_writable_size_proc)           (ma_pa_stream* s);
21663 typedef size_t                   (* ma_pa_stream_readable_size_proc)           (ma_pa_stream* s);
21664
21665 typedef struct
21666 {
21667     ma_uint32 count;
21668     ma_uint32 capacity;
21669     ma_device_info* pInfo;
21670 } ma_pulse_device_enum_data;
21671
21672 static ma_result ma_result_from_pulse(int result)
21673 {
21674     if (result < 0) {
21675         return MA_ERROR;
21676     }
21677
21678     switch (result) {
21679         case MA_PA_OK:           return MA_SUCCESS;
21680         case MA_PA_ERR_ACCESS:   return MA_ACCESS_DENIED;
21681         case MA_PA_ERR_INVALID:  return MA_INVALID_ARGS;
21682         case MA_PA_ERR_NOENTITY: return MA_NO_DEVICE;
21683         default:                 return MA_ERROR;
21684     }
21685 }
21686
21687 #if 0
21688 static ma_pa_sample_format_t ma_format_to_pulse(ma_format format)
21689 {
21690     if (ma_is_little_endian()) {
21691         switch (format) {
21692             case ma_format_s16: return MA_PA_SAMPLE_S16LE;
21693             case ma_format_s24: return MA_PA_SAMPLE_S24LE;
21694             case ma_format_s32: return MA_PA_SAMPLE_S32LE;
21695             case ma_format_f32: return MA_PA_SAMPLE_FLOAT32LE;
21696             default: break;
21697         }
21698     } else {
21699         switch (format) {
21700             case ma_format_s16: return MA_PA_SAMPLE_S16BE;
21701             case ma_format_s24: return MA_PA_SAMPLE_S24BE;
21702             case ma_format_s32: return MA_PA_SAMPLE_S32BE;
21703             case ma_format_f32: return MA_PA_SAMPLE_FLOAT32BE;
21704             default: break;
21705         }
21706     }
21707
21708     /* Endian agnostic. */
21709     switch (format) {
21710         case ma_format_u8: return MA_PA_SAMPLE_U8;
21711         default: return MA_PA_SAMPLE_INVALID;
21712     }
21713 }
21714 #endif
21715
21716 static ma_format ma_format_from_pulse(ma_pa_sample_format_t format)
21717 {
21718     if (ma_is_little_endian()) {
21719         switch (format) {
21720             case MA_PA_SAMPLE_S16LE:     return ma_format_s16;
21721             case MA_PA_SAMPLE_S24LE:     return ma_format_s24;
21722             case MA_PA_SAMPLE_S32LE:     return ma_format_s32;
21723             case MA_PA_SAMPLE_FLOAT32LE: return ma_format_f32;
21724             default: break;
21725         }
21726     } else {
21727         switch (format) {
21728             case MA_PA_SAMPLE_S16BE:     return ma_format_s16;
21729             case MA_PA_SAMPLE_S24BE:     return ma_format_s24;
21730             case MA_PA_SAMPLE_S32BE:     return ma_format_s32;
21731             case MA_PA_SAMPLE_FLOAT32BE: return ma_format_f32;
21732             default: break;
21733         }
21734     }
21735
21736     /* Endian agnostic. */
21737     switch (format) {
21738         case MA_PA_SAMPLE_U8: return ma_format_u8;
21739         default: return ma_format_unknown;
21740     }
21741 }
21742
21743 static ma_channel ma_channel_position_from_pulse(ma_pa_channel_position_t position)
21744 {
21745     switch (position)
21746     {
21747         case MA_PA_CHANNEL_POSITION_INVALID:               return MA_CHANNEL_NONE;
21748         case MA_PA_CHANNEL_POSITION_MONO:                  return MA_CHANNEL_MONO;
21749         case MA_PA_CHANNEL_POSITION_FRONT_LEFT:            return MA_CHANNEL_FRONT_LEFT;
21750         case MA_PA_CHANNEL_POSITION_FRONT_RIGHT:           return MA_CHANNEL_FRONT_RIGHT;
21751         case MA_PA_CHANNEL_POSITION_FRONT_CENTER:          return MA_CHANNEL_FRONT_CENTER;
21752         case MA_PA_CHANNEL_POSITION_REAR_CENTER:           return MA_CHANNEL_BACK_CENTER;
21753         case MA_PA_CHANNEL_POSITION_REAR_LEFT:             return MA_CHANNEL_BACK_LEFT;
21754         case MA_PA_CHANNEL_POSITION_REAR_RIGHT:            return MA_CHANNEL_BACK_RIGHT;
21755         case MA_PA_CHANNEL_POSITION_LFE:                   return MA_CHANNEL_LFE;
21756         case MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:  return MA_CHANNEL_FRONT_LEFT_CENTER;
21757         case MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
21758         case MA_PA_CHANNEL_POSITION_SIDE_LEFT:             return MA_CHANNEL_SIDE_LEFT;
21759         case MA_PA_CHANNEL_POSITION_SIDE_RIGHT:            return MA_CHANNEL_SIDE_RIGHT;
21760         case MA_PA_CHANNEL_POSITION_AUX0:                  return MA_CHANNEL_AUX_0;
21761         case MA_PA_CHANNEL_POSITION_AUX1:                  return MA_CHANNEL_AUX_1;
21762         case MA_PA_CHANNEL_POSITION_AUX2:                  return MA_CHANNEL_AUX_2;
21763         case MA_PA_CHANNEL_POSITION_AUX3:                  return MA_CHANNEL_AUX_3;
21764         case MA_PA_CHANNEL_POSITION_AUX4:                  return MA_CHANNEL_AUX_4;
21765         case MA_PA_CHANNEL_POSITION_AUX5:                  return MA_CHANNEL_AUX_5;
21766         case MA_PA_CHANNEL_POSITION_AUX6:                  return MA_CHANNEL_AUX_6;
21767         case MA_PA_CHANNEL_POSITION_AUX7:                  return MA_CHANNEL_AUX_7;
21768         case MA_PA_CHANNEL_POSITION_AUX8:                  return MA_CHANNEL_AUX_8;
21769         case MA_PA_CHANNEL_POSITION_AUX9:                  return MA_CHANNEL_AUX_9;
21770         case MA_PA_CHANNEL_POSITION_AUX10:                 return MA_CHANNEL_AUX_10;
21771         case MA_PA_CHANNEL_POSITION_AUX11:                 return MA_CHANNEL_AUX_11;
21772         case MA_PA_CHANNEL_POSITION_AUX12:                 return MA_CHANNEL_AUX_12;
21773         case MA_PA_CHANNEL_POSITION_AUX13:                 return MA_CHANNEL_AUX_13;
21774         case MA_PA_CHANNEL_POSITION_AUX14:                 return MA_CHANNEL_AUX_14;
21775         case MA_PA_CHANNEL_POSITION_AUX15:                 return MA_CHANNEL_AUX_15;
21776         case MA_PA_CHANNEL_POSITION_AUX16:                 return MA_CHANNEL_AUX_16;
21777         case MA_PA_CHANNEL_POSITION_AUX17:                 return MA_CHANNEL_AUX_17;
21778         case MA_PA_CHANNEL_POSITION_AUX18:                 return MA_CHANNEL_AUX_18;
21779         case MA_PA_CHANNEL_POSITION_AUX19:                 return MA_CHANNEL_AUX_19;
21780         case MA_PA_CHANNEL_POSITION_AUX20:                 return MA_CHANNEL_AUX_20;
21781         case MA_PA_CHANNEL_POSITION_AUX21:                 return MA_CHANNEL_AUX_21;
21782         case MA_PA_CHANNEL_POSITION_AUX22:                 return MA_CHANNEL_AUX_22;
21783         case MA_PA_CHANNEL_POSITION_AUX23:                 return MA_CHANNEL_AUX_23;
21784         case MA_PA_CHANNEL_POSITION_AUX24:                 return MA_CHANNEL_AUX_24;
21785         case MA_PA_CHANNEL_POSITION_AUX25:                 return MA_CHANNEL_AUX_25;
21786         case MA_PA_CHANNEL_POSITION_AUX26:                 return MA_CHANNEL_AUX_26;
21787         case MA_PA_CHANNEL_POSITION_AUX27:                 return MA_CHANNEL_AUX_27;
21788         case MA_PA_CHANNEL_POSITION_AUX28:                 return MA_CHANNEL_AUX_28;
21789         case MA_PA_CHANNEL_POSITION_AUX29:                 return MA_CHANNEL_AUX_29;
21790         case MA_PA_CHANNEL_POSITION_AUX30:                 return MA_CHANNEL_AUX_30;
21791         case MA_PA_CHANNEL_POSITION_AUX31:                 return MA_CHANNEL_AUX_31;
21792         case MA_PA_CHANNEL_POSITION_TOP_CENTER:            return MA_CHANNEL_TOP_CENTER;
21793         case MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT:        return MA_CHANNEL_TOP_FRONT_LEFT;
21794         case MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:       return MA_CHANNEL_TOP_FRONT_RIGHT;
21795         case MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER:      return MA_CHANNEL_TOP_FRONT_CENTER;
21796         case MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT:         return MA_CHANNEL_TOP_BACK_LEFT;
21797         case MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT:        return MA_CHANNEL_TOP_BACK_RIGHT;
21798         case MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER:       return MA_CHANNEL_TOP_BACK_CENTER;
21799         default: return MA_CHANNEL_NONE;
21800     }
21801 }
21802
21803 #if 0
21804 static ma_pa_channel_position_t ma_channel_position_to_pulse(ma_channel position)
21805 {
21806     switch (position)
21807     {
21808         case MA_CHANNEL_NONE:               return MA_PA_CHANNEL_POSITION_INVALID;
21809         case MA_CHANNEL_FRONT_LEFT:         return MA_PA_CHANNEL_POSITION_FRONT_LEFT;
21810         case MA_CHANNEL_FRONT_RIGHT:        return MA_PA_CHANNEL_POSITION_FRONT_RIGHT;
21811         case MA_CHANNEL_FRONT_CENTER:       return MA_PA_CHANNEL_POSITION_FRONT_CENTER;
21812         case MA_CHANNEL_LFE:                return MA_PA_CHANNEL_POSITION_LFE;
21813         case MA_CHANNEL_BACK_LEFT:          return MA_PA_CHANNEL_POSITION_REAR_LEFT;
21814         case MA_CHANNEL_BACK_RIGHT:         return MA_PA_CHANNEL_POSITION_REAR_RIGHT;
21815         case MA_CHANNEL_FRONT_LEFT_CENTER:  return MA_PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
21816         case MA_CHANNEL_FRONT_RIGHT_CENTER: return MA_PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
21817         case MA_CHANNEL_BACK_CENTER:        return MA_PA_CHANNEL_POSITION_REAR_CENTER;
21818         case MA_CHANNEL_SIDE_LEFT:          return MA_PA_CHANNEL_POSITION_SIDE_LEFT;
21819         case MA_CHANNEL_SIDE_RIGHT:         return MA_PA_CHANNEL_POSITION_SIDE_RIGHT;
21820         case MA_CHANNEL_TOP_CENTER:         return MA_PA_CHANNEL_POSITION_TOP_CENTER;
21821         case MA_CHANNEL_TOP_FRONT_LEFT:     return MA_PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
21822         case MA_CHANNEL_TOP_FRONT_CENTER:   return MA_PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
21823         case MA_CHANNEL_TOP_FRONT_RIGHT:    return MA_PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
21824         case MA_CHANNEL_TOP_BACK_LEFT:      return MA_PA_CHANNEL_POSITION_TOP_REAR_LEFT;
21825         case MA_CHANNEL_TOP_BACK_CENTER:    return MA_PA_CHANNEL_POSITION_TOP_REAR_CENTER;
21826         case MA_CHANNEL_TOP_BACK_RIGHT:     return MA_PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
21827         case MA_CHANNEL_19:                 return MA_PA_CHANNEL_POSITION_AUX18;
21828         case MA_CHANNEL_20:                 return MA_PA_CHANNEL_POSITION_AUX19;
21829         case MA_CHANNEL_21:                 return MA_PA_CHANNEL_POSITION_AUX20;
21830         case MA_CHANNEL_22:                 return MA_PA_CHANNEL_POSITION_AUX21;
21831         case MA_CHANNEL_23:                 return MA_PA_CHANNEL_POSITION_AUX22;
21832         case MA_CHANNEL_24:                 return MA_PA_CHANNEL_POSITION_AUX23;
21833         case MA_CHANNEL_25:                 return MA_PA_CHANNEL_POSITION_AUX24;
21834         case MA_CHANNEL_26:                 return MA_PA_CHANNEL_POSITION_AUX25;
21835         case MA_CHANNEL_27:                 return MA_PA_CHANNEL_POSITION_AUX26;
21836         case MA_CHANNEL_28:                 return MA_PA_CHANNEL_POSITION_AUX27;
21837         case MA_CHANNEL_29:                 return MA_PA_CHANNEL_POSITION_AUX28;
21838         case MA_CHANNEL_30:                 return MA_PA_CHANNEL_POSITION_AUX29;
21839         case MA_CHANNEL_31:                 return MA_PA_CHANNEL_POSITION_AUX30;
21840         case MA_CHANNEL_32:                 return MA_PA_CHANNEL_POSITION_AUX31;
21841         default: return (ma_pa_channel_position_t)position;
21842     }
21843 }
21844 #endif
21845
21846 static ma_result ma_wait_for_operation__pulse(ma_context* pContext, ma_pa_operation* pOP)
21847 {
21848     int resultPA;
21849     ma_pa_operation_state_t state;
21850
21851     MA_ASSERT(pContext != NULL);
21852     MA_ASSERT(pOP != NULL);
21853
21854     for (;;) {
21855         state = ((ma_pa_operation_get_state_proc)pContext->pulse.pa_operation_get_state)(pOP);
21856         if (state != MA_PA_OPERATION_RUNNING) {
21857             break;  /* Done. */
21858         }
21859
21860         resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL);
21861         if (resultPA < 0) {
21862             return ma_result_from_pulse(resultPA);
21863         }
21864     }
21865
21866     return MA_SUCCESS;
21867 }
21868
21869 static ma_result ma_wait_for_operation_and_unref__pulse(ma_context* pContext, ma_pa_operation* pOP)
21870 {
21871     ma_result result;
21872
21873     if (pOP == NULL) {
21874         return MA_INVALID_ARGS;
21875     }
21876
21877     result = ma_wait_for_operation__pulse(pContext, pOP);
21878     ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
21879
21880     return result;
21881 }
21882
21883 static ma_result ma_context_wait_for_pa_context_to_connect__pulse(ma_context* pContext)
21884 {
21885     int resultPA;
21886     ma_pa_context_state_t state;
21887
21888     for (;;) {
21889         state = ((ma_pa_context_get_state_proc)pContext->pulse.pa_context_get_state)((ma_pa_context*)pContext->pulse.pPulseContext);
21890         if (state == MA_PA_CONTEXT_READY) {
21891             break;  /* Done. */
21892         }
21893
21894         if (state == MA_PA_CONTEXT_FAILED || state == MA_PA_CONTEXT_TERMINATED) {
21895             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio context.", MA_ERROR);
21896         }
21897
21898         resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL);
21899         if (resultPA < 0) {
21900             return ma_result_from_pulse(resultPA);
21901         }
21902     }
21903
21904     /* Should never get here. */
21905     return MA_SUCCESS;
21906 }
21907
21908 static ma_result ma_context_wait_for_pa_stream_to_connect__pulse(ma_context* pContext, ma_pa_stream* pStream)
21909 {
21910     int resultPA;
21911     ma_pa_stream_state_t state;
21912
21913     for (;;) {
21914         state = ((ma_pa_stream_get_state_proc)pContext->pulse.pa_stream_get_state)(pStream);
21915         if (state == MA_PA_STREAM_READY) {
21916             break;  /* Done. */
21917         }
21918
21919         if (state == MA_PA_STREAM_FAILED || state == MA_PA_STREAM_TERMINATED) {
21920             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while connecting the PulseAudio stream.", MA_ERROR);
21921         }
21922
21923         resultPA = ((ma_pa_mainloop_iterate_proc)pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pContext->pulse.pMainLoop, 1, NULL);
21924         if (resultPA < 0) {
21925             return ma_result_from_pulse(resultPA);
21926         }
21927     }
21928
21929     return MA_SUCCESS;
21930 }
21931
21932
21933 static void ma_device_sink_info_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
21934 {
21935     ma_pa_sink_info* pInfoOut;
21936
21937     if (endOfList > 0) {
21938         return;
21939     }
21940
21941     pInfoOut = (ma_pa_sink_info*)pUserData;
21942     MA_ASSERT(pInfoOut != NULL);
21943
21944     *pInfoOut = *pInfo;
21945
21946     (void)pPulseContext; /* Unused. */
21947 }
21948
21949 static void ma_device_source_info_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
21950 {
21951     ma_pa_source_info* pInfoOut;
21952
21953     if (endOfList > 0) {
21954         return;
21955     }
21956
21957     pInfoOut = (ma_pa_source_info*)pUserData;
21958     MA_ASSERT(pInfoOut != NULL);
21959
21960     *pInfoOut = *pInfo;
21961
21962     (void)pPulseContext; /* Unused. */
21963 }
21964
21965 static void ma_device_sink_name_callback(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
21966 {
21967     ma_device* pDevice;
21968
21969     if (endOfList > 0) {
21970         return;
21971     }
21972
21973     pDevice = (ma_device*)pUserData;
21974     MA_ASSERT(pDevice != NULL);
21975
21976     ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), pInfo->description, (size_t)-1);
21977
21978     (void)pPulseContext; /* Unused. */
21979 }
21980
21981 static void ma_device_source_name_callback(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
21982 {
21983     ma_device* pDevice;
21984
21985     if (endOfList > 0) {
21986         return;
21987     }
21988
21989     pDevice = (ma_device*)pUserData;
21990     MA_ASSERT(pDevice != NULL);
21991
21992     ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), pInfo->description, (size_t)-1);
21993
21994     (void)pPulseContext; /* Unused. */
21995 }
21996
21997
21998 static ma_result ma_context_get_sink_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_sink_info* pSinkInfo)
21999 {
22000     ma_pa_operation* pOP;
22001
22002     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);
22003     if (pOP == NULL) {
22004         return MA_ERROR;
22005     }
22006
22007     return ma_wait_for_operation_and_unref__pulse(pContext, pOP);
22008 }
22009
22010 static ma_result ma_context_get_source_info__pulse(ma_context* pContext, const char* pDeviceName, ma_pa_source_info* pSourceInfo)
22011 {
22012     ma_pa_operation* pOP;
22013
22014     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);
22015     if (pOP == NULL) {
22016         return MA_ERROR;
22017     }
22018
22019     return ma_wait_for_operation_and_unref__pulse(pContext, pOP);;
22020 }
22021
22022 static ma_result ma_context_get_default_device_index__pulse(ma_context* pContext, ma_device_type deviceType, ma_uint32* pIndex)
22023 {
22024     ma_result result;
22025
22026     MA_ASSERT(pContext != NULL);
22027     MA_ASSERT(pIndex   != NULL);
22028
22029     if (pIndex != NULL) {
22030         *pIndex = (ma_uint32)-1;
22031     }
22032
22033     if (deviceType == ma_device_type_playback) {
22034         ma_pa_sink_info sinkInfo;
22035         result = ma_context_get_sink_info__pulse(pContext, NULL, &sinkInfo);
22036         if (result != MA_SUCCESS) {
22037             return result;
22038         }
22039
22040         if (pIndex != NULL) {
22041             *pIndex = sinkInfo.index;
22042         }
22043     }
22044
22045     if (deviceType == ma_device_type_capture) {
22046         ma_pa_source_info sourceInfo;
22047         result = ma_context_get_source_info__pulse(pContext, NULL, &sourceInfo);
22048         if (result != MA_SUCCESS) {
22049             return result;
22050         }
22051
22052         if (pIndex != NULL) {
22053             *pIndex = sourceInfo.index;
22054         }
22055     }
22056
22057     return MA_SUCCESS;
22058 }
22059
22060
22061 typedef struct
22062 {
22063     ma_context* pContext;
22064     ma_enum_devices_callback_proc callback;
22065     void* pUserData;
22066     ma_bool32 isTerminated;
22067     ma_uint32 defaultDeviceIndexPlayback;
22068     ma_uint32 defaultDeviceIndexCapture;
22069 } ma_context_enumerate_devices_callback_data__pulse;
22070
22071 static void ma_context_enumerate_devices_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pSinkInfo, int endOfList, void* pUserData)
22072 {
22073     ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData;
22074     ma_device_info deviceInfo;
22075
22076     MA_ASSERT(pData != NULL);
22077
22078     if (endOfList || pData->isTerminated) {
22079         return;
22080     }
22081
22082     MA_ZERO_OBJECT(&deviceInfo);
22083
22084     /* The name from PulseAudio is the ID for miniaudio. */
22085     if (pSinkInfo->name != NULL) {
22086         ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSinkInfo->name, (size_t)-1);
22087     }
22088
22089     /* The description from PulseAudio is the name for miniaudio. */
22090     if (pSinkInfo->description != NULL) {
22091         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSinkInfo->description, (size_t)-1);
22092     }
22093
22094     if (pSinkInfo->index == pData->defaultDeviceIndexPlayback) {
22095         deviceInfo.isDefault = MA_TRUE;
22096     }
22097
22098     pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_playback, &deviceInfo, pData->pUserData);
22099
22100     (void)pPulseContext; /* Unused. */
22101 }
22102
22103 static void ma_context_enumerate_devices_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pSourceInfo, int endOfList, void* pUserData)
22104 {
22105     ma_context_enumerate_devices_callback_data__pulse* pData = (ma_context_enumerate_devices_callback_data__pulse*)pUserData;
22106     ma_device_info deviceInfo;
22107
22108     MA_ASSERT(pData != NULL);
22109
22110     if (endOfList || pData->isTerminated) {
22111         return;
22112     }
22113
22114     MA_ZERO_OBJECT(&deviceInfo);
22115
22116     /* The name from PulseAudio is the ID for miniaudio. */
22117     if (pSourceInfo->name != NULL) {
22118         ma_strncpy_s(deviceInfo.id.pulse, sizeof(deviceInfo.id.pulse), pSourceInfo->name, (size_t)-1);
22119     }
22120
22121     /* The description from PulseAudio is the name for miniaudio. */
22122     if (pSourceInfo->description != NULL) {
22123         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), pSourceInfo->description, (size_t)-1);
22124     }
22125
22126     if (pSourceInfo->index == pData->defaultDeviceIndexCapture) {
22127         deviceInfo.isDefault = MA_TRUE;
22128     }
22129
22130     pData->isTerminated = !pData->callback(pData->pContext, ma_device_type_capture, &deviceInfo, pData->pUserData);
22131
22132     (void)pPulseContext; /* Unused. */
22133 }
22134
22135 static ma_result ma_context_enumerate_devices__pulse(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
22136 {
22137     ma_result result = MA_SUCCESS;
22138     ma_context_enumerate_devices_callback_data__pulse callbackData;
22139     ma_pa_operation* pOP = NULL;
22140
22141     MA_ASSERT(pContext != NULL);
22142     MA_ASSERT(callback != NULL);
22143
22144     callbackData.pContext = pContext;
22145     callbackData.callback = callback;
22146     callbackData.pUserData = pUserData;
22147     callbackData.isTerminated = MA_FALSE;
22148     callbackData.defaultDeviceIndexPlayback = (ma_uint32)-1;
22149     callbackData.defaultDeviceIndexCapture  = (ma_uint32)-1;
22150
22151     /* We need to get the index of the default devices. */
22152     ma_context_get_default_device_index__pulse(pContext, ma_device_type_playback, &callbackData.defaultDeviceIndexPlayback);
22153     ma_context_get_default_device_index__pulse(pContext, ma_device_type_capture,  &callbackData.defaultDeviceIndexCapture);
22154
22155     /* Playback. */
22156     if (!callbackData.isTerminated) {
22157         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);
22158         if (pOP == NULL) {
22159             result = MA_ERROR;
22160             goto done;
22161         }
22162
22163         result = ma_wait_for_operation__pulse(pContext, pOP);
22164         ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
22165
22166         if (result != MA_SUCCESS) {
22167             goto done;
22168         }
22169     }
22170
22171
22172     /* Capture. */
22173     if (!callbackData.isTerminated) {
22174         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);
22175         if (pOP == NULL) {
22176             result = MA_ERROR;
22177             goto done;
22178         }
22179
22180         result = ma_wait_for_operation__pulse(pContext, pOP);
22181         ((ma_pa_operation_unref_proc)pContext->pulse.pa_operation_unref)(pOP);
22182
22183         if (result != MA_SUCCESS) {
22184             goto done;
22185         }
22186     }
22187
22188 done:
22189     return result;
22190 }
22191
22192
22193 typedef struct
22194 {
22195     ma_device_info* pDeviceInfo;
22196     ma_uint32 defaultDeviceIndex;
22197     ma_bool32 foundDevice;
22198 } ma_context_get_device_info_callback_data__pulse;
22199
22200 static void ma_context_get_device_info_sink_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_sink_info* pInfo, int endOfList, void* pUserData)
22201 {
22202     ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData;
22203
22204     if (endOfList > 0) {
22205         return;
22206     }
22207
22208     MA_ASSERT(pData != NULL);
22209     pData->foundDevice = MA_TRUE;
22210
22211     if (pInfo->name != NULL) {
22212         ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1);
22213     }
22214
22215     if (pInfo->description != NULL) {
22216         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1);
22217     }
22218
22219     /*
22220     We're just reporting a single data format here. I think technically PulseAudio might support
22221     all formats, but I don't trust that PulseAudio will do *anything* right, so I'm just going to
22222     report the "native" device format.
22223     */
22224     pData->pDeviceInfo->nativeDataFormats[0].format     = ma_format_from_pulse(pInfo->sample_spec.format);
22225     pData->pDeviceInfo->nativeDataFormats[0].channels   = pInfo->sample_spec.channels;
22226     pData->pDeviceInfo->nativeDataFormats[0].sampleRate = pInfo->sample_spec.rate;
22227     pData->pDeviceInfo->nativeDataFormats[0].flags      = 0;
22228     pData->pDeviceInfo->nativeDataFormatCount = 1;
22229
22230     if (pData->defaultDeviceIndex == pInfo->index) {
22231         pData->pDeviceInfo->isDefault = MA_TRUE;
22232     }
22233
22234     (void)pPulseContext; /* Unused. */
22235 }
22236
22237 static void ma_context_get_device_info_source_callback__pulse(ma_pa_context* pPulseContext, const ma_pa_source_info* pInfo, int endOfList, void* pUserData)
22238 {
22239     ma_context_get_device_info_callback_data__pulse* pData = (ma_context_get_device_info_callback_data__pulse*)pUserData;
22240
22241     if (endOfList > 0) {
22242         return;
22243     }
22244
22245     MA_ASSERT(pData != NULL);
22246     pData->foundDevice = MA_TRUE;
22247
22248     if (pInfo->name != NULL) {
22249         ma_strncpy_s(pData->pDeviceInfo->id.pulse, sizeof(pData->pDeviceInfo->id.pulse), pInfo->name, (size_t)-1);
22250     }
22251
22252     if (pInfo->description != NULL) {
22253         ma_strncpy_s(pData->pDeviceInfo->name, sizeof(pData->pDeviceInfo->name), pInfo->description, (size_t)-1);
22254     }
22255
22256     /*
22257     We're just reporting a single data format here. I think technically PulseAudio might support
22258     all formats, but I don't trust that PulseAudio will do *anything* right, so I'm just going to
22259     report the "native" device format.
22260     */
22261     pData->pDeviceInfo->nativeDataFormats[0].format     = ma_format_from_pulse(pInfo->sample_spec.format);
22262     pData->pDeviceInfo->nativeDataFormats[0].channels   = pInfo->sample_spec.channels;
22263     pData->pDeviceInfo->nativeDataFormats[0].sampleRate = pInfo->sample_spec.rate;
22264     pData->pDeviceInfo->nativeDataFormats[0].flags      = 0;
22265     pData->pDeviceInfo->nativeDataFormatCount = 1;
22266
22267     if (pData->defaultDeviceIndex == pInfo->index) {
22268         pData->pDeviceInfo->isDefault = MA_TRUE;
22269     }
22270
22271     (void)pPulseContext; /* Unused. */
22272 }
22273
22274 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)
22275 {
22276     ma_result result = MA_SUCCESS;
22277     ma_context_get_device_info_callback_data__pulse callbackData;
22278     ma_pa_operation* pOP = NULL;
22279
22280     MA_ASSERT(pContext != NULL);
22281
22282     callbackData.pDeviceInfo = pDeviceInfo;
22283     callbackData.foundDevice = MA_FALSE;
22284
22285     result = ma_context_get_default_device_index__pulse(pContext, deviceType, &callbackData.defaultDeviceIndex);
22286
22287     if (deviceType == ma_device_type_playback) {
22288         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), pDeviceID->pulse, ma_context_get_device_info_sink_callback__pulse, &callbackData);
22289     } else {
22290         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), pDeviceID->pulse, ma_context_get_device_info_source_callback__pulse, &callbackData);
22291     }
22292
22293     if (pOP != NULL) {
22294         ma_wait_for_operation_and_unref__pulse(pContext, pOP);
22295     } else {
22296         result = MA_ERROR;
22297         goto done;
22298     }
22299
22300     if (!callbackData.foundDevice) {
22301         result = MA_NO_DEVICE;
22302         goto done;
22303     }
22304
22305 done:
22306     return result;
22307 }
22308
22309 static ma_result ma_device_uninit__pulse(ma_device* pDevice)
22310 {
22311     ma_context* pContext;
22312
22313     MA_ASSERT(pDevice != NULL);
22314
22315     pContext = pDevice->pContext;
22316     MA_ASSERT(pContext != NULL);
22317
22318     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
22319         ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22320         ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22321     }
22322
22323     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
22324         ((ma_pa_stream_disconnect_proc)pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22325         ((ma_pa_stream_unref_proc)pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22326     }
22327
22328     if (pDevice->type == ma_device_type_duplex) {
22329         ma_duplex_rb_uninit(&pDevice->duplexRB);
22330     }
22331
22332     return MA_SUCCESS;
22333 }
22334
22335 static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFrames, ma_uint32 periods, const ma_pa_sample_spec* ss)
22336 {
22337     ma_pa_buffer_attr attr;
22338     attr.maxlength = periodSizeInFrames * periods * ma_get_bytes_per_frame(ma_format_from_pulse(ss->format), ss->channels);
22339     attr.tlength   = attr.maxlength / periods;
22340     attr.prebuf    = (ma_uint32)-1;
22341     attr.minreq    = (ma_uint32)-1;
22342     attr.fragsize  = attr.maxlength / periods;
22343
22344     return attr;
22345 }
22346
22347 static ma_pa_stream* ma_context__pa_stream_new__pulse(ma_context* pContext, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap)
22348 {
22349     static int g_StreamCounter = 0;
22350     char actualStreamName[256];
22351
22352     if (pStreamName != NULL) {
22353         ma_strncpy_s(actualStreamName, sizeof(actualStreamName), pStreamName, (size_t)-1);
22354     } else {
22355         ma_strcpy_s(actualStreamName, sizeof(actualStreamName), "miniaudio:");
22356         ma_itoa_s(g_StreamCounter, actualStreamName + 8, sizeof(actualStreamName)-8, 10);  /* 8 = strlen("miniaudio:") */
22357     }
22358     g_StreamCounter += 1;
22359
22360     return ((ma_pa_stream_new_proc)pContext->pulse.pa_stream_new)((ma_pa_context*)pContext->pulse.pPulseContext, actualStreamName, ss, cmap);
22361 }
22362
22363
22364 static void ma_device_on_read__pulse(ma_pa_stream* pStream, size_t byteCount, void* pUserData)
22365 {
22366     ma_device* pDevice = (ma_device*)pUserData;
22367     ma_uint32 bpf;
22368     ma_uint64 frameCount;
22369     ma_uint64 framesProcessed;
22370
22371     MA_ASSERT(pDevice != NULL);
22372
22373     bpf = ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
22374     MA_ASSERT(bpf > 0);
22375
22376     frameCount = byteCount / bpf;
22377     framesProcessed = 0;
22378
22379     while (ma_device_get_state(pDevice) == MA_STATE_STARTED && framesProcessed < frameCount) {
22380         const void* pMappedPCMFrames;
22381         size_t bytesMapped;
22382         ma_uint64 framesMapped;
22383
22384         int pulseResult = ((ma_pa_stream_peek_proc)pDevice->pContext->pulse.pa_stream_peek)(pStream, &pMappedPCMFrames, &bytesMapped);
22385         if (pulseResult < 0) {
22386             break; /* Failed to map. Abort. */
22387         }
22388
22389         framesMapped = bytesMapped / bpf;
22390         if (framesMapped > 0) {
22391             if (pMappedPCMFrames != NULL) {
22392                 ma_device_handle_backend_data_callback(pDevice, NULL, pMappedPCMFrames, framesMapped);
22393             } else {
22394                 /* It's a hole. */
22395             #if defined(MA_DEBUG_OUTPUT)
22396                 printf("[PulseAudio] ma_device_on_read__pulse: Hole.\n");
22397             #endif
22398             }
22399
22400             pulseResult = ((ma_pa_stream_drop_proc)pDevice->pContext->pulse.pa_stream_drop)(pStream);
22401             if (pulseResult < 0) {
22402                 break;  /* Failed to drop the buffer. */
22403             }
22404
22405             framesProcessed += framesMapped;
22406
22407         } else {
22408             /* Nothing was mapped. Just abort. */
22409             break;
22410         }
22411     }
22412 }
22413
22414 static ma_result ma_device_write_to_stream__pulse(ma_device* pDevice, ma_pa_stream* pStream, ma_uint64* pFramesProcessed)
22415 {
22416     ma_result result = MA_SUCCESS;
22417     ma_uint64 framesProcessed = 0;
22418     size_t bytesMapped;
22419     ma_uint32 bpf;
22420     ma_uint32 deviceState;
22421
22422     MA_ASSERT(pDevice != NULL);
22423     MA_ASSERT(pStream != NULL);
22424
22425     bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
22426     MA_ASSERT(bpf > 0);
22427
22428     deviceState = ma_device_get_state(pDevice);
22429
22430     bytesMapped = ((ma_pa_stream_writable_size_proc)pDevice->pContext->pulse.pa_stream_writable_size)(pStream);
22431     if (bytesMapped != (size_t)-1) {
22432         if (bytesMapped > 0) {
22433             ma_uint64 framesMapped;
22434             void* pMappedPCMFrames;
22435             int pulseResult = ((ma_pa_stream_begin_write_proc)pDevice->pContext->pulse.pa_stream_begin_write)(pStream, &pMappedPCMFrames, &bytesMapped);
22436             if (pulseResult < 0) {
22437                 result = ma_result_from_pulse(pulseResult);
22438                 goto done;
22439             }
22440
22441             framesMapped = bytesMapped / bpf;
22442
22443             if (deviceState == MA_STATE_STARTED) {
22444                 ma_device_handle_backend_data_callback(pDevice, pMappedPCMFrames, NULL, framesMapped);
22445             } else {
22446                 /* Device is not started. Don't write anything to it. */
22447             }
22448
22449             pulseResult = ((ma_pa_stream_write_proc)pDevice->pContext->pulse.pa_stream_write)(pStream, pMappedPCMFrames, bytesMapped, NULL, 0, MA_PA_SEEK_RELATIVE);
22450             if (pulseResult < 0) {
22451                 result = ma_result_from_pulse(pulseResult);
22452                 goto done;  /* Failed to write data to stream. */
22453             }
22454
22455             framesProcessed += framesMapped;
22456         } else {
22457             result = MA_ERROR;  /* No data available. Abort. */
22458             goto done;
22459         }
22460     } else {
22461         result = MA_ERROR;  /* Failed to retrieve the writable size. Abort. */
22462         goto done;
22463     }
22464
22465 done:
22466     if (pFramesProcessed != NULL) {
22467         *pFramesProcessed = framesProcessed;
22468     }
22469
22470     return result;
22471 }
22472
22473 static void ma_device_on_write__pulse(ma_pa_stream* pStream, size_t byteCount, void* pUserData)
22474 {
22475     ma_device* pDevice = (ma_device*)pUserData;
22476     ma_uint32 bpf;
22477     ma_uint64 frameCount;
22478     ma_uint64 framesProcessed;
22479     ma_uint32 deviceState;
22480     ma_result result;
22481
22482     MA_ASSERT(pDevice != NULL);
22483
22484     /*
22485     Don't do anything if the device isn't initialized yet. Yes, this can happen because PulseAudio
22486     can fire this callback before the stream has even started. Ridiculous.
22487     */
22488     deviceState = ma_device_get_state(pDevice);
22489     if (deviceState != MA_STATE_STARTING && deviceState != MA_STATE_STARTED) {
22490         return;
22491     }
22492
22493     bpf = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
22494     MA_ASSERT(bpf > 0);
22495
22496     frameCount = byteCount / bpf;
22497     framesProcessed = 0;
22498
22499     while (framesProcessed < frameCount) {
22500         ma_uint64 framesProcessedThisIteration;
22501
22502         /* Don't keep trying to process frames if the device isn't started. */
22503         deviceState = ma_device_get_state(pDevice);
22504         if (deviceState != MA_STATE_STARTING && deviceState != MA_STATE_STARTED) {
22505             break;
22506         }
22507
22508         result = ma_device_write_to_stream__pulse(pDevice, pStream, &framesProcessedThisIteration);
22509         if (result != MA_SUCCESS) {
22510             break;
22511         }
22512
22513         framesProcessed += framesProcessedThisIteration;
22514     }
22515 }
22516
22517 static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
22518 {
22519     /*
22520     Notes for PulseAudio:
22521
22522       - We're always using native format/channels/rate regardless of whether or not PulseAudio
22523         supports the format directly through their own data conversion system. I'm doing this to
22524         reduce as much variability from the PulseAudio side as possible because it's seems to be
22525         extremely unreliable at everything it does.
22526
22527       - When both the period size in frames and milliseconds are 0, we default to miniaudio's
22528         default buffer sizes rather than leaving it up to PulseAudio because I don't trust
22529         PulseAudio to give us any kind of reasonable latency by default.
22530
22531       - Do not ever, *ever* forget to use MA_PA_STREAM_ADJUST_LATENCY. If you don't specify this
22532         flag, capture mode will just not work properly until you open another PulseAudio app.
22533     */
22534
22535     ma_result result = MA_SUCCESS;
22536     int error = 0;
22537     const char* devPlayback = NULL;
22538     const char* devCapture  = NULL;
22539     ma_format format = ma_format_unknown;
22540     ma_uint32 channels = 0;
22541     ma_uint32 sampleRate = 0;
22542     ma_pa_sink_info sinkInfo;
22543     ma_pa_source_info sourceInfo;
22544     ma_pa_sample_spec ss;
22545     ma_pa_channel_map cmap;
22546     ma_pa_buffer_attr attr;
22547     const ma_pa_sample_spec* pActualSS   = NULL;
22548     const ma_pa_channel_map* pActualCMap = NULL;
22549     const ma_pa_buffer_attr* pActualAttr = NULL;
22550     ma_uint32 iChannel;
22551     ma_pa_stream_flags_t streamFlags;
22552
22553     MA_ASSERT(pDevice != NULL);
22554     MA_ZERO_OBJECT(&pDevice->pulse);
22555
22556     if (pConfig->deviceType == ma_device_type_loopback) {
22557         return MA_DEVICE_TYPE_NOT_SUPPORTED;
22558     }
22559
22560     /* No exclusive mode with the PulseAudio backend. */
22561     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.shareMode == ma_share_mode_exclusive) ||
22562         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.shareMode  == ma_share_mode_exclusive)) {
22563         return MA_SHARE_MODE_NOT_SUPPORTED;
22564     }
22565
22566     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
22567         if (pDescriptorPlayback->pDeviceID != NULL) {
22568             devPlayback = pDescriptorPlayback->pDeviceID->pulse;
22569         }
22570
22571         format     = pDescriptorPlayback->format;
22572         channels   = pDescriptorPlayback->channels;
22573         sampleRate = pDescriptorPlayback->sampleRate;
22574     }
22575
22576     if (pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) {
22577         if (pDescriptorCapture->pDeviceID != NULL) {
22578             devCapture = pDescriptorCapture->pDeviceID->pulse;
22579         }
22580         
22581         format     = pDescriptorCapture->format;
22582         channels   = pDescriptorCapture->channels;
22583         sampleRate = pDescriptorCapture->sampleRate;
22584     }
22585
22586     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
22587         result = ma_context_get_source_info__pulse(pDevice->pContext, devCapture, &sourceInfo);
22588         if (result != MA_SUCCESS) {
22589             ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve source info for capture device.", result);
22590             goto on_error0;
22591         }
22592
22593         ss   = sourceInfo.sample_spec;
22594         cmap = sourceInfo.channel_map;
22595
22596         /* We now have enough information to calculate our actual period size in frames. */
22597         pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, ss.rate, pConfig->performanceProfile);
22598
22599         attr = ma_device__pa_buffer_attr_new(pDescriptorCapture->periodSizeInFrames, pDescriptorCapture->periodCount, &ss);
22600     #ifdef MA_DEBUG_OUTPUT
22601         printf("[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);
22602     #endif
22603
22604         pDevice->pulse.pStreamCapture = ma_context__pa_stream_new__pulse(pDevice->pContext, pConfig->pulse.pStreamNameCapture, &ss, &cmap);
22605         if (pDevice->pulse.pStreamCapture == NULL) {
22606             result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio capture stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
22607             goto on_error0;
22608         }
22609
22610
22611         /* The callback needs to be set before connecting the stream. */
22612         ((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);
22613
22614
22615         /* Connect after we've got all of our internal state set up. */
22616         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;
22617         if (devCapture != NULL) {
22618             streamFlags |= MA_PA_STREAM_DONT_MOVE;
22619         }
22620
22621         error = ((ma_pa_stream_connect_record_proc)pDevice->pContext->pulse.pa_stream_connect_record)((ma_pa_stream*)pDevice->pulse.pStreamCapture, devCapture, &attr, streamFlags);
22622         if (error != MA_PA_OK) {
22623             result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio capture stream.", ma_result_from_pulse(error));
22624             goto on_error1;
22625         }
22626
22627         result = ma_context_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, (ma_pa_stream*)pDevice->pulse.pStreamCapture);
22628         if (result != MA_SUCCESS) {
22629             goto on_error2;
22630         }
22631
22632         /* Internal format. */
22633         pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22634         if (pActualSS != NULL) {
22635             ss = *pActualSS;
22636         }
22637
22638         pDescriptorCapture->format     = ma_format_from_pulse(ss.format);
22639         pDescriptorCapture->channels   = ss.channels;
22640         pDescriptorCapture->sampleRate = ss.rate;
22641
22642         /* Internal channel map. */
22643         pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22644         if (pActualCMap != NULL) {
22645             cmap = *pActualCMap;
22646         }
22647
22648         for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
22649             pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
22650         }
22651
22652
22653         /* Buffer. */
22654         pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22655         if (pActualAttr != NULL) {
22656             attr = *pActualAttr;
22657         }
22658
22659         pDescriptorCapture->periodCount        = attr.maxlength / attr.fragsize;
22660         pDescriptorCapture->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) / pDescriptorCapture->periodCount;
22661     #ifdef MA_DEBUG_OUTPUT
22662         printf("[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);
22663     #endif
22664
22665
22666         /* Name. */
22667         devCapture = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22668         if (devCapture != NULL) {
22669             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->pContext->pulse.pPulseContext, devCapture, ma_device_source_name_callback, pDevice);
22670             ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP);
22671         }
22672     }
22673
22674     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
22675         result = ma_context_get_sink_info__pulse(pDevice->pContext, devPlayback, &sinkInfo);
22676         if (result != MA_SUCCESS) {
22677             ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to retrieve sink info for playback device.", result);
22678             goto on_error2;
22679         }
22680
22681         ss   = sinkInfo.sample_spec;
22682         cmap = sinkInfo.channel_map;
22683
22684         /* We now have enough information to calculate the actual buffer size in frames. */
22685         pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, ss.rate, pConfig->performanceProfile);
22686
22687         attr = ma_device__pa_buffer_attr_new(pDescriptorPlayback->periodSizeInFrames, pDescriptorPlayback->periodCount, &ss);
22688     #ifdef MA_DEBUG_OUTPUT
22689         printf("[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);
22690     #endif
22691
22692         pDevice->pulse.pStreamPlayback = ma_context__pa_stream_new__pulse(pDevice->pContext, pConfig->pulse.pStreamNamePlayback, &ss, &cmap);
22693         if (pDevice->pulse.pStreamPlayback == NULL) {
22694             result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio playback stream.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
22695             goto on_error2;
22696         }
22697
22698
22699         /*
22700         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
22701         device state of MA_STATE_UNINITIALIZED.
22702         */
22703         ((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);
22704
22705
22706         /* Connect after we've got all of our internal state set up. */
22707         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;
22708         if (devPlayback != NULL) {
22709             streamFlags |= MA_PA_STREAM_DONT_MOVE;
22710         }
22711
22712         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);
22713         if (error != MA_PA_OK) {
22714             result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio playback stream.", ma_result_from_pulse(error));
22715             goto on_error3;
22716         }
22717
22718         result = ma_context_wait_for_pa_stream_to_connect__pulse(pDevice->pContext, (ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22719         if (result != MA_SUCCESS) {
22720             goto on_error3;
22721         }
22722
22723
22724         /* Internal format. */
22725         pActualSS = ((ma_pa_stream_get_sample_spec_proc)pDevice->pContext->pulse.pa_stream_get_sample_spec)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22726         if (pActualSS != NULL) {
22727             ss = *pActualSS;
22728         }
22729
22730         pDescriptorPlayback->format     = ma_format_from_pulse(ss.format);
22731         pDescriptorPlayback->channels   = ss.channels;
22732         pDescriptorPlayback->sampleRate = ss.rate;
22733
22734         /* Internal channel map. */
22735         pActualCMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22736         if (pActualCMap != NULL) {
22737             cmap = *pActualCMap;
22738         }
22739
22740         for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
22741             pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]);
22742         }
22743
22744
22745         /* Buffer. */
22746         pActualAttr = ((ma_pa_stream_get_buffer_attr_proc)pDevice->pContext->pulse.pa_stream_get_buffer_attr)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22747         if (pActualAttr != NULL) {
22748             attr = *pActualAttr;
22749         }
22750
22751         pDescriptorPlayback->periodCount        = attr.maxlength / attr.tlength;
22752         pDescriptorPlayback->periodSizeInFrames = attr.maxlength / ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) / pDescriptorPlayback->periodCount;
22753     #ifdef MA_DEBUG_OUTPUT
22754         printf("[PulseAudio] Playback actual attr: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d, fragsize=%d; internalPeriodSizeInFrames=%d\n", attr.maxlength, attr.tlength, attr.prebuf, attr.minreq, attr.fragsize, pDevice->playback.internalPeriodSizeInFrames);
22755     #endif
22756
22757
22758         /* Name. */
22759         devPlayback = ((ma_pa_stream_get_device_name_proc)pDevice->pContext->pulse.pa_stream_get_device_name)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22760         if (devPlayback != NULL) {
22761             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->pContext->pulse.pPulseContext, devPlayback, ma_device_sink_name_callback, pDevice);
22762             ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP);
22763         }
22764     }
22765
22766
22767     /*
22768     We need a ring buffer for handling duplex mode. We can use the main duplex ring buffer in the main
22769     part of the ma_device struct. We cannot, however, depend on ma_device_init() initializing this for
22770     us later on because that will only do it if it's a fully asynchronous backend - i.e. the
22771     onDeviceDataLoop callback is NULL, which is not the case for PulseAudio.
22772     */
22773     if (pConfig->deviceType == ma_device_type_duplex) {
22774         result = ma_duplex_rb_init(format, channels, sampleRate, pDescriptorCapture->sampleRate, pDescriptorCapture->periodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
22775         if (result != MA_SUCCESS) {
22776             result = ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to initialize ring buffer.", result);
22777             goto on_error4;
22778         }
22779     }
22780
22781     return MA_SUCCESS;
22782
22783
22784 on_error4:
22785     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
22786         ((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22787     }
22788 on_error3:
22789     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
22790         ((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamPlayback);
22791     }
22792 on_error2:
22793     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
22794         ((ma_pa_stream_disconnect_proc)pDevice->pContext->pulse.pa_stream_disconnect)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22795     }
22796 on_error1:
22797     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
22798         ((ma_pa_stream_unref_proc)pDevice->pContext->pulse.pa_stream_unref)((ma_pa_stream*)pDevice->pulse.pStreamCapture);
22799     }
22800 on_error0:
22801     return result;
22802 }
22803
22804
22805 static void ma_pulse_operation_complete_callback(ma_pa_stream* pStream, int success, void* pUserData)
22806 {
22807     ma_bool32* pIsSuccessful = (ma_bool32*)pUserData;
22808     MA_ASSERT(pIsSuccessful != NULL);
22809
22810     *pIsSuccessful = (ma_bool32)success;
22811
22812     (void)pStream; /* Unused. */
22813 }
22814
22815 static ma_result ma_device__cork_stream__pulse(ma_device* pDevice, ma_device_type deviceType, int cork)
22816 {
22817     ma_context* pContext = pDevice->pContext;
22818     ma_bool32 wasSuccessful;
22819     ma_pa_stream* pStream;
22820     ma_pa_operation* pOP;
22821     ma_result result;
22822
22823     /* This should not be called with a duplex device type. */
22824     if (deviceType == ma_device_type_duplex) {
22825         return MA_INVALID_ARGS;
22826     }
22827
22828     wasSuccessful = MA_FALSE;
22829
22830     pStream = (ma_pa_stream*)((deviceType == ma_device_type_capture) ? pDevice->pulse.pStreamCapture : pDevice->pulse.pStreamPlayback);
22831     MA_ASSERT(pStream != NULL);
22832
22833     pOP = ((ma_pa_stream_cork_proc)pContext->pulse.pa_stream_cork)(pStream, cork, ma_pulse_operation_complete_callback, &wasSuccessful);
22834     if (pOP == NULL) {
22835         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to cork PulseAudio stream.", (cork == 0) ? MA_FAILED_TO_START_BACKEND_DEVICE : MA_FAILED_TO_STOP_BACKEND_DEVICE);
22836     }
22837
22838     result = ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP);
22839     if (result != MA_SUCCESS) {
22840         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] An error occurred while waiting for the PulseAudio stream to cork.", result);
22841     }
22842
22843     if (!wasSuccessful) {
22844         if (cork) {
22845             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to stop PulseAudio stream.", MA_FAILED_TO_STOP_BACKEND_DEVICE);
22846         } else {
22847             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to start PulseAudio stream.", MA_FAILED_TO_START_BACKEND_DEVICE);
22848         }
22849     }
22850
22851     return MA_SUCCESS;
22852 }
22853
22854 static ma_result ma_device_start__pulse(ma_device* pDevice)
22855 {
22856     ma_result result;
22857
22858     MA_ASSERT(pDevice != NULL);
22859
22860     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
22861         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 0);
22862         if (result != MA_SUCCESS) {
22863             return result;
22864         }
22865     }
22866
22867     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
22868         /* We need to fill some data before uncorking. Not doing this will result in the write callback never getting fired. */
22869         result = ma_device_write_to_stream__pulse(pDevice, (ma_pa_stream*)(pDevice->pulse.pStreamPlayback), NULL);
22870         if (result != MA_SUCCESS) {
22871             return result; /* Failed to write data. Not sure what to do here... Just aborting. */
22872         }
22873
22874         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 0);
22875         if (result != MA_SUCCESS) {
22876             return result;
22877         }
22878     }
22879
22880     return MA_SUCCESS;
22881 }
22882
22883 static ma_result ma_device_stop__pulse(ma_device* pDevice)
22884 {
22885     ma_result result;
22886     ma_bool32 wasSuccessful;
22887
22888     MA_ASSERT(pDevice != NULL);
22889
22890     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
22891         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_capture, 1);
22892         if (result != MA_SUCCESS) {
22893             return result;
22894         }
22895     }
22896
22897     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
22898         /* The stream needs to be drained if it's a playback device. */
22899         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);
22900         ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pOP);
22901
22902         result = ma_device__cork_stream__pulse(pDevice, ma_device_type_playback, 1);
22903         if (result != MA_SUCCESS) {
22904             return result;
22905         }
22906     }
22907
22908     return MA_SUCCESS;
22909 }
22910
22911 static ma_result ma_device_data_loop__pulse(ma_device* pDevice)
22912 {
22913     int resultPA;
22914
22915     MA_ASSERT(pDevice != NULL);
22916
22917     /* NOTE: Don't start the device here. It'll be done at a higher level. */
22918
22919     /*
22920     All data is handled through callbacks. All we need to do is iterate over the main loop and let
22921     the callbacks deal with it.
22922     */
22923     while (ma_device_get_state(pDevice) == MA_STATE_STARTED) {
22924         resultPA = ((ma_pa_mainloop_iterate_proc)pDevice->pContext->pulse.pa_mainloop_iterate)((ma_pa_mainloop*)pDevice->pContext->pulse.pMainLoop, 1, NULL);
22925         if (resultPA < 0) {
22926             break;
22927         }
22928     }
22929
22930     /* NOTE: Don't stop the device here. It'll be done at a higher level. */
22931     return MA_SUCCESS;
22932 }
22933
22934 static ma_result ma_device_data_loop_wakeup__pulse(ma_device* pDevice)
22935 {
22936     MA_ASSERT(pDevice != NULL);
22937
22938     ((ma_pa_mainloop_wakeup_proc)pDevice->pContext->pulse.pa_mainloop_wakeup)((ma_pa_mainloop*)pDevice->pContext->pulse.pMainLoop);
22939
22940     return MA_SUCCESS;
22941 }
22942
22943 static ma_result ma_context_uninit__pulse(ma_context* pContext)
22944 {
22945     MA_ASSERT(pContext != NULL);
22946     MA_ASSERT(pContext->backend == ma_backend_pulseaudio);
22947
22948     ((ma_pa_context_disconnect_proc)pContext->pulse.pa_context_disconnect)((ma_pa_context*)pContext->pulse.pPulseContext);
22949     ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)((ma_pa_context*)pContext->pulse.pPulseContext);
22950     ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)pContext->pulse.pMainLoop);
22951
22952 #ifndef MA_NO_RUNTIME_LINKING
22953     ma_dlclose(pContext, pContext->pulse.pulseSO);
22954 #endif
22955
22956     return MA_SUCCESS;
22957 }
22958
22959 static ma_result ma_context_init__pulse(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
22960 {
22961     ma_result result;
22962 #ifndef MA_NO_RUNTIME_LINKING
22963     const char* libpulseNames[] = {
22964         "libpulse.so",
22965         "libpulse.so.0"
22966     };
22967     size_t i;
22968
22969     for (i = 0; i < ma_countof(libpulseNames); ++i) {
22970         pContext->pulse.pulseSO = ma_dlopen(pContext, libpulseNames[i]);
22971         if (pContext->pulse.pulseSO != NULL) {
22972             break;
22973         }
22974     }
22975
22976     if (pContext->pulse.pulseSO == NULL) {
22977         return MA_NO_BACKEND;
22978     }
22979
22980     pContext->pulse.pa_mainloop_new                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_new");
22981     pContext->pulse.pa_mainloop_free                   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_free");
22982     pContext->pulse.pa_mainloop_quit                   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_quit");
22983     pContext->pulse.pa_mainloop_get_api                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_get_api");
22984     pContext->pulse.pa_mainloop_iterate                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_iterate");
22985     pContext->pulse.pa_mainloop_wakeup                 = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_wakeup");
22986     pContext->pulse.pa_threaded_mainloop_new           = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_new");
22987     pContext->pulse.pa_threaded_mainloop_free          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_free");
22988     pContext->pulse.pa_threaded_mainloop_start         = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_start");
22989     pContext->pulse.pa_threaded_mainloop_stop          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_stop");
22990     pContext->pulse.pa_threaded_mainloop_lock          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_lock");
22991     pContext->pulse.pa_threaded_mainloop_unlock        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_unlock");
22992     pContext->pulse.pa_threaded_mainloop_wait          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_wait");
22993     pContext->pulse.pa_threaded_mainloop_signal        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_signal");
22994     pContext->pulse.pa_threaded_mainloop_accept        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_accept");
22995     pContext->pulse.pa_threaded_mainloop_get_retval    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_retval");
22996     pContext->pulse.pa_threaded_mainloop_get_api       = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_get_api");
22997     pContext->pulse.pa_threaded_mainloop_in_thread     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_in_thread");
22998     pContext->pulse.pa_threaded_mainloop_set_name      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_threaded_mainloop_set_name");
22999     pContext->pulse.pa_context_new                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_new");
23000     pContext->pulse.pa_context_unref                   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_unref");
23001     pContext->pulse.pa_context_connect                 = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_connect");
23002     pContext->pulse.pa_context_disconnect              = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_disconnect");
23003     pContext->pulse.pa_context_set_state_callback      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_set_state_callback");
23004     pContext->pulse.pa_context_get_state               = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_state");
23005     pContext->pulse.pa_context_get_sink_info_list      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_list");
23006     pContext->pulse.pa_context_get_source_info_list    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_list");
23007     pContext->pulse.pa_context_get_sink_info_by_name   = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name");
23008     pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_by_name");
23009     pContext->pulse.pa_operation_unref                 = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_unref");
23010     pContext->pulse.pa_operation_get_state             = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_get_state");
23011     pContext->pulse.pa_channel_map_init_extend         = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_init_extend");
23012     pContext->pulse.pa_channel_map_valid               = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_valid");
23013     pContext->pulse.pa_channel_map_compatible          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_compatible");
23014     pContext->pulse.pa_stream_new                      = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_new");
23015     pContext->pulse.pa_stream_unref                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_unref");
23016     pContext->pulse.pa_stream_connect_playback         = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_playback");
23017     pContext->pulse.pa_stream_connect_record           = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_record");
23018     pContext->pulse.pa_stream_disconnect               = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_disconnect");
23019     pContext->pulse.pa_stream_get_state                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_state");
23020     pContext->pulse.pa_stream_get_sample_spec          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_sample_spec");
23021     pContext->pulse.pa_stream_get_channel_map          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_channel_map");
23022     pContext->pulse.pa_stream_get_buffer_attr          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_buffer_attr");
23023     pContext->pulse.pa_stream_set_buffer_attr          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_buffer_attr");
23024     pContext->pulse.pa_stream_get_device_name          = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name");
23025     pContext->pulse.pa_stream_set_write_callback       = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback");
23026     pContext->pulse.pa_stream_set_read_callback        = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback");
23027     pContext->pulse.pa_stream_flush                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush");
23028     pContext->pulse.pa_stream_drain                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain");
23029     pContext->pulse.pa_stream_is_corked                = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked");
23030     pContext->pulse.pa_stream_cork                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_cork");
23031     pContext->pulse.pa_stream_trigger                  = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_trigger");
23032     pContext->pulse.pa_stream_begin_write              = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_begin_write");
23033     pContext->pulse.pa_stream_write                    = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_write");
23034     pContext->pulse.pa_stream_peek                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_peek");
23035     pContext->pulse.pa_stream_drop                     = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drop");
23036     pContext->pulse.pa_stream_writable_size            = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_writable_size");
23037     pContext->pulse.pa_stream_readable_size            = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_readable_size");
23038 #else
23039     /* This strange assignment system is just for type safety. */
23040     ma_pa_mainloop_new_proc                    _pa_mainloop_new                   = pa_mainloop_new;
23041     ma_pa_mainloop_free_proc                   _pa_mainloop_free                  = pa_mainloop_free;
23042     ma_pa_mainloop_quit_proc                   _pa_mainloop_quit                  = pa_mainloop_quit;
23043     ma_pa_mainloop_get_api_proc                _pa_mainloop_get_api               = pa_mainloop_get_api;
23044     ma_pa_mainloop_iterate_proc                _pa_mainloop_iterate               = pa_mainloop_iterate;
23045     ma_pa_mainloop_wakeup_proc                 _pa_mainloop_wakeup                = pa_mainloop_wakeup;
23046     ma_pa_threaded_mainloop_new_proc           _pa_threaded_mainloop_new          = pa_threaded_mainloop_new;
23047     ma_pa_threaded_mainloop_free_proc          _pa_threaded_mainloop_free         = pa_threaded_mainloop_free;
23048     ma_pa_threaded_mainloop_start_proc         _pa_threaded_mainloop_start        = pa_threaded_mainloop_start;
23049     ma_pa_threaded_mainloop_stop_proc          _pa_threaded_mainloop_stop         = pa_threaded_mainloop_stop;
23050     ma_pa_threaded_mainloop_lock_proc          _pa_threaded_mainloop_lock         = pa_threaded_mainloop_lock;
23051     ma_pa_threaded_mainloop_unlock_proc        _pa_threaded_mainloop_unlock       = pa_threaded_mainloop_unlock;
23052     ma_pa_threaded_mainloop_wait_proc          _pa_threaded_mainloop_wait         = pa_threaded_mainloop_wait;
23053     ma_pa_threaded_mainloop_signal_proc        _pa_threaded_mainloop_signal       = pa_threaded_mainloop_signal;
23054     ma_pa_threaded_mainloop_accept_proc        _pa_threaded_mainloop_accept       = pa_threaded_mainloop_accept;
23055     ma_pa_threaded_mainloop_get_retval_proc    _pa_threaded_mainloop_get_retval   = pa_threaded_mainloop_get_retval;
23056     ma_pa_threaded_mainloop_get_api_proc       _pa_threaded_mainloop_get_api      = pa_threaded_mainloop_get_api;
23057     ma_pa_threaded_mainloop_in_thread_proc     _pa_threaded_mainloop_in_thread    = pa_threaded_mainloop_in_thread;
23058     ma_pa_threaded_mainloop_set_name_proc      _pa_threaded_mainloop_set_name     = pa_threaded_mainloop_set_name;
23059     ma_pa_context_new_proc                     _pa_context_new                    = pa_context_new;
23060     ma_pa_context_unref_proc                   _pa_context_unref                  = pa_context_unref;
23061     ma_pa_context_connect_proc                 _pa_context_connect                = pa_context_connect;
23062     ma_pa_context_disconnect_proc              _pa_context_disconnect             = pa_context_disconnect;
23063     ma_pa_context_set_state_callback_proc      _pa_context_set_state_callback     = pa_context_set_state_callback;
23064     ma_pa_context_get_state_proc               _pa_context_get_state              = pa_context_get_state;
23065     ma_pa_context_get_sink_info_list_proc      _pa_context_get_sink_info_list     = pa_context_get_sink_info_list;
23066     ma_pa_context_get_source_info_list_proc    _pa_context_get_source_info_list   = pa_context_get_source_info_list;
23067     ma_pa_context_get_sink_info_by_name_proc   _pa_context_get_sink_info_by_name  = pa_context_get_sink_info_by_name;
23068     ma_pa_context_get_source_info_by_name_proc _pa_context_get_source_info_by_name= pa_context_get_source_info_by_name;
23069     ma_pa_operation_unref_proc                 _pa_operation_unref                = pa_operation_unref;
23070     ma_pa_operation_get_state_proc             _pa_operation_get_state            = pa_operation_get_state;
23071     ma_pa_channel_map_init_extend_proc         _pa_channel_map_init_extend        = pa_channel_map_init_extend;
23072     ma_pa_channel_map_valid_proc               _pa_channel_map_valid              = pa_channel_map_valid;
23073     ma_pa_channel_map_compatible_proc          _pa_channel_map_compatible         = pa_channel_map_compatible;
23074     ma_pa_stream_new_proc                      _pa_stream_new                     = pa_stream_new;
23075     ma_pa_stream_unref_proc                    _pa_stream_unref                   = pa_stream_unref;
23076     ma_pa_stream_connect_playback_proc         _pa_stream_connect_playback        = pa_stream_connect_playback;
23077     ma_pa_stream_connect_record_proc           _pa_stream_connect_record          = pa_stream_connect_record;
23078     ma_pa_stream_disconnect_proc               _pa_stream_disconnect              = pa_stream_disconnect;
23079     ma_pa_stream_get_state_proc                _pa_stream_get_state               = pa_stream_get_state;
23080     ma_pa_stream_get_sample_spec_proc          _pa_stream_get_sample_spec         = pa_stream_get_sample_spec;
23081     ma_pa_stream_get_channel_map_proc          _pa_stream_get_channel_map         = pa_stream_get_channel_map;
23082     ma_pa_stream_get_buffer_attr_proc          _pa_stream_get_buffer_attr         = pa_stream_get_buffer_attr;
23083     ma_pa_stream_set_buffer_attr_proc          _pa_stream_set_buffer_attr         = pa_stream_set_buffer_attr;
23084     ma_pa_stream_get_device_name_proc          _pa_stream_get_device_name         = pa_stream_get_device_name;
23085     ma_pa_stream_set_write_callback_proc       _pa_stream_set_write_callback      = pa_stream_set_write_callback;
23086     ma_pa_stream_set_read_callback_proc        _pa_stream_set_read_callback       = pa_stream_set_read_callback;
23087     ma_pa_stream_flush_proc                    _pa_stream_flush                   = pa_stream_flush;
23088     ma_pa_stream_drain_proc                    _pa_stream_drain                   = pa_stream_drain;
23089     ma_pa_stream_is_corked_proc                _pa_stream_is_corked               = pa_stream_is_corked;
23090     ma_pa_stream_cork_proc                     _pa_stream_cork                    = pa_stream_cork;
23091     ma_pa_stream_trigger_proc                  _pa_stream_trigger                 = pa_stream_trigger;
23092     ma_pa_stream_begin_write_proc              _pa_stream_begin_write             = pa_stream_begin_write;
23093     ma_pa_stream_write_proc                    _pa_stream_write                   = pa_stream_write;
23094     ma_pa_stream_peek_proc                     _pa_stream_peek                    = pa_stream_peek;
23095     ma_pa_stream_drop_proc                     _pa_stream_drop                    = pa_stream_drop;
23096     ma_pa_stream_writable_size_proc            _pa_stream_writable_size           = pa_stream_writable_size;
23097     ma_pa_stream_readable_size_proc            _pa_stream_readable_size           = pa_stream_readable_size;
23098
23099     pContext->pulse.pa_mainloop_new                    = (ma_proc)_pa_mainloop_new;
23100     pContext->pulse.pa_mainloop_free                   = (ma_proc)_pa_mainloop_free;
23101     pContext->pulse.pa_mainloop_quit                   = (ma_proc)_pa_mainloop_quit;
23102     pContext->pulse.pa_mainloop_get_api                = (ma_proc)_pa_mainloop_get_api;
23103     pContext->pulse.pa_mainloop_iterate                = (ma_proc)_pa_mainloop_iterate;
23104     pContext->pulse.pa_mainloop_wakeup                 = (ma_proc)_pa_mainloop_wakeup;
23105     pContext->pulse.pa_threaded_mainloop_new           = (ma_proc)_pa_threaded_mainloop_new;
23106     pContext->pulse.pa_threaded_mainloop_free          = (ma_proc)_pa_threaded_mainloop_free;
23107     pContext->pulse.pa_threaded_mainloop_start         = (ma_proc)_pa_threaded_mainloop_start;
23108     pContext->pulse.pa_threaded_mainloop_stop          = (ma_proc)_pa_threaded_mainloop_stop;
23109     pContext->pulse.pa_threaded_mainloop_lock          = (ma_proc)_pa_threaded_mainloop_lock;
23110     pContext->pulse.pa_threaded_mainloop_unlock        = (ma_proc)_pa_threaded_mainloop_unlock;
23111     pContext->pulse.pa_threaded_mainloop_wait          = (ma_proc)_pa_threaded_mainloop_wait;
23112     pContext->pulse.pa_threaded_mainloop_signal        = (ma_proc)_pa_threaded_mainloop_signal;
23113     pContext->pulse.pa_threaded_mainloop_accept        = (ma_proc)_pa_threaded_mainloop_accept;
23114     pContext->pulse.pa_threaded_mainloop_get_retval    = (ma_proc)_pa_threaded_mainloop_get_retval;
23115     pContext->pulse.pa_threaded_mainloop_get_api       = (ma_proc)_pa_threaded_mainloop_get_api;
23116     pContext->pulse.pa_threaded_mainloop_in_thread     = (ma_proc)_pa_threaded_mainloop_in_thread;
23117     pContext->pulse.pa_threaded_mainloop_set_name      = (ma_proc)_pa_threaded_mainloop_set_name;
23118     pContext->pulse.pa_context_new                     = (ma_proc)_pa_context_new;
23119     pContext->pulse.pa_context_unref                   = (ma_proc)_pa_context_unref;
23120     pContext->pulse.pa_context_connect                 = (ma_proc)_pa_context_connect;
23121     pContext->pulse.pa_context_disconnect              = (ma_proc)_pa_context_disconnect;
23122     pContext->pulse.pa_context_set_state_callback      = (ma_proc)_pa_context_set_state_callback;
23123     pContext->pulse.pa_context_get_state               = (ma_proc)_pa_context_get_state;
23124     pContext->pulse.pa_context_get_sink_info_list      = (ma_proc)_pa_context_get_sink_info_list;
23125     pContext->pulse.pa_context_get_source_info_list    = (ma_proc)_pa_context_get_source_info_list;
23126     pContext->pulse.pa_context_get_sink_info_by_name   = (ma_proc)_pa_context_get_sink_info_by_name;
23127     pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)_pa_context_get_source_info_by_name;
23128     pContext->pulse.pa_operation_unref                 = (ma_proc)_pa_operation_unref;
23129     pContext->pulse.pa_operation_get_state             = (ma_proc)_pa_operation_get_state;
23130     pContext->pulse.pa_channel_map_init_extend         = (ma_proc)_pa_channel_map_init_extend;
23131     pContext->pulse.pa_channel_map_valid               = (ma_proc)_pa_channel_map_valid;
23132     pContext->pulse.pa_channel_map_compatible          = (ma_proc)_pa_channel_map_compatible;
23133     pContext->pulse.pa_stream_new                      = (ma_proc)_pa_stream_new;
23134     pContext->pulse.pa_stream_unref                    = (ma_proc)_pa_stream_unref;
23135     pContext->pulse.pa_stream_connect_playback         = (ma_proc)_pa_stream_connect_playback;
23136     pContext->pulse.pa_stream_connect_record           = (ma_proc)_pa_stream_connect_record;
23137     pContext->pulse.pa_stream_disconnect               = (ma_proc)_pa_stream_disconnect;
23138     pContext->pulse.pa_stream_get_state                = (ma_proc)_pa_stream_get_state;
23139     pContext->pulse.pa_stream_get_sample_spec          = (ma_proc)_pa_stream_get_sample_spec;
23140     pContext->pulse.pa_stream_get_channel_map          = (ma_proc)_pa_stream_get_channel_map;
23141     pContext->pulse.pa_stream_get_buffer_attr          = (ma_proc)_pa_stream_get_buffer_attr;
23142     pContext->pulse.pa_stream_set_buffer_attr          = (ma_proc)_pa_stream_set_buffer_attr;
23143     pContext->pulse.pa_stream_get_device_name          = (ma_proc)_pa_stream_get_device_name;
23144     pContext->pulse.pa_stream_set_write_callback       = (ma_proc)_pa_stream_set_write_callback;
23145     pContext->pulse.pa_stream_set_read_callback        = (ma_proc)_pa_stream_set_read_callback;
23146     pContext->pulse.pa_stream_flush                    = (ma_proc)_pa_stream_flush;
23147     pContext->pulse.pa_stream_drain                    = (ma_proc)_pa_stream_drain;
23148     pContext->pulse.pa_stream_is_corked                = (ma_proc)_pa_stream_is_corked;
23149     pContext->pulse.pa_stream_cork                     = (ma_proc)_pa_stream_cork;
23150     pContext->pulse.pa_stream_trigger                  = (ma_proc)_pa_stream_trigger;
23151     pContext->pulse.pa_stream_begin_write              = (ma_proc)_pa_stream_begin_write;
23152     pContext->pulse.pa_stream_write                    = (ma_proc)_pa_stream_write;
23153     pContext->pulse.pa_stream_peek                     = (ma_proc)_pa_stream_peek;
23154     pContext->pulse.pa_stream_drop                     = (ma_proc)_pa_stream_drop;
23155     pContext->pulse.pa_stream_writable_size            = (ma_proc)_pa_stream_writable_size;
23156     pContext->pulse.pa_stream_readable_size            = (ma_proc)_pa_stream_readable_size;
23157 #endif
23158
23159     /* 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. */
23160     pContext->pulse.pMainLoop = ((ma_pa_mainloop_new_proc)pContext->pulse.pa_mainloop_new)();
23161     if (pContext->pulse.pMainLoop == NULL) {
23162         result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create mainloop.", MA_FAILED_TO_INIT_BACKEND);
23163     #ifndef MA_NO_RUNTIME_LINKING
23164         ma_dlclose(pContext, pContext->pulse.pulseSO);
23165     #endif
23166         return result;
23167     }
23168
23169     pContext->pulse.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*)pContext->pulse.pMainLoop), pConfig->pulse.pApplicationName);
23170     if (pContext->pulse.pPulseContext == NULL) {
23171         result = ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to create PulseAudio context.", MA_FAILED_TO_INIT_BACKEND);
23172         ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop));
23173     #ifndef MA_NO_RUNTIME_LINKING
23174         ma_dlclose(pContext, pContext->pulse.pulseSO);
23175     #endif
23176         return result;
23177     }
23178
23179     /* Now we need to connect to the context. Everything is asynchronous so we need to wait for it to connect before returning. */
23180     result = ma_result_from_pulse(((ma_pa_context_connect_proc)pContext->pulse.pa_context_connect)((ma_pa_context*)pContext->pulse.pPulseContext, pConfig->pulse.pServerName, (pConfig->pulse.tryAutoSpawn) ? 0 : MA_PA_CONTEXT_NOAUTOSPAWN, NULL));
23181     if (result != MA_SUCCESS) {
23182         ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[PulseAudio] Failed to connect PulseAudio context.", result);
23183         ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop));
23184     #ifndef MA_NO_RUNTIME_LINKING
23185         ma_dlclose(pContext, pContext->pulse.pulseSO);
23186     #endif
23187         return result;
23188     }
23189
23190     /* Since ma_context_init() runs synchronously we need to wait for the PulseAudio context to connect before we return. */
23191     result = ma_context_wait_for_pa_context_to_connect__pulse(pContext);
23192     if (result != MA_SUCCESS) {
23193         ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)((ma_pa_mainloop*)(pContext->pulse.pMainLoop));
23194     #ifndef MA_NO_RUNTIME_LINKING
23195         ma_dlclose(pContext, pContext->pulse.pulseSO);
23196     #endif
23197         return result;
23198     }
23199
23200
23201     /* With pa_mainloop we run a synchronous backend, but we implement our own main loop. */
23202     pCallbacks->onContextInit             = ma_context_init__pulse;
23203     pCallbacks->onContextUninit           = ma_context_uninit__pulse;
23204     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__pulse;
23205     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__pulse;
23206     pCallbacks->onDeviceInit              = ma_device_init__pulse;
23207     pCallbacks->onDeviceUninit            = ma_device_uninit__pulse;
23208     pCallbacks->onDeviceStart             = ma_device_start__pulse;
23209     pCallbacks->onDeviceStop              = ma_device_stop__pulse;
23210     pCallbacks->onDeviceRead              = NULL;   /* Not used because we're implementing onDeviceDataLoop. */
23211     pCallbacks->onDeviceWrite             = NULL;   /* Not used because we're implementing onDeviceDataLoop. */
23212     pCallbacks->onDeviceDataLoop          = ma_device_data_loop__pulse;
23213     pCallbacks->onDeviceDataLoopWakeup    = ma_device_data_loop_wakeup__pulse;
23214
23215     return MA_SUCCESS;
23216 }
23217 #endif
23218
23219
23220 /******************************************************************************
23221
23222 JACK Backend
23223
23224 ******************************************************************************/
23225 #ifdef MA_HAS_JACK
23226
23227 /* It is assumed jack.h is available when compile-time linking is being used. */
23228 #ifdef MA_NO_RUNTIME_LINKING
23229 #include <jack/jack.h>
23230
23231 typedef jack_nframes_t              ma_jack_nframes_t;
23232 typedef jack_options_t              ma_jack_options_t;
23233 typedef jack_status_t               ma_jack_status_t;
23234 typedef jack_client_t               ma_jack_client_t;
23235 typedef jack_port_t                 ma_jack_port_t;
23236 typedef JackProcessCallback         ma_JackProcessCallback;
23237 typedef JackBufferSizeCallback      ma_JackBufferSizeCallback;
23238 typedef JackShutdownCallback        ma_JackShutdownCallback;
23239 #define MA_JACK_DEFAULT_AUDIO_TYPE  JACK_DEFAULT_AUDIO_TYPE
23240 #define ma_JackNoStartServer        JackNoStartServer
23241 #define ma_JackPortIsInput          JackPortIsInput
23242 #define ma_JackPortIsOutput         JackPortIsOutput
23243 #define ma_JackPortIsPhysical       JackPortIsPhysical
23244 #else
23245 typedef ma_uint32               ma_jack_nframes_t;
23246 typedef int                     ma_jack_options_t;
23247 typedef int                     ma_jack_status_t;
23248 typedef struct ma_jack_client_t ma_jack_client_t;
23249 typedef struct ma_jack_port_t   ma_jack_port_t;
23250 typedef int  (* ma_JackProcessCallback)   (ma_jack_nframes_t nframes, void* arg);
23251 typedef int  (* ma_JackBufferSizeCallback)(ma_jack_nframes_t nframes, void* arg);
23252 typedef void (* ma_JackShutdownCallback)  (void* arg);
23253 #define MA_JACK_DEFAULT_AUDIO_TYPE "32 bit float mono audio"
23254 #define ma_JackNoStartServer       1
23255 #define ma_JackPortIsInput         1
23256 #define ma_JackPortIsOutput        2
23257 #define ma_JackPortIsPhysical      4
23258 #endif
23259
23260 typedef ma_jack_client_t* (* ma_jack_client_open_proc)             (const char* client_name, ma_jack_options_t options, ma_jack_status_t* status, ...);
23261 typedef int               (* ma_jack_client_close_proc)            (ma_jack_client_t* client);
23262 typedef int               (* ma_jack_client_name_size_proc)        (void);
23263 typedef int               (* ma_jack_set_process_callback_proc)    (ma_jack_client_t* client, ma_JackProcessCallback process_callback, void* arg);
23264 typedef int               (* ma_jack_set_buffer_size_callback_proc)(ma_jack_client_t* client, ma_JackBufferSizeCallback bufsize_callback, void* arg);
23265 typedef void              (* ma_jack_on_shutdown_proc)             (ma_jack_client_t* client, ma_JackShutdownCallback function, void* arg);
23266 typedef ma_jack_nframes_t (* ma_jack_get_sample_rate_proc)         (ma_jack_client_t* client);
23267 typedef ma_jack_nframes_t (* ma_jack_get_buffer_size_proc)         (ma_jack_client_t* client);
23268 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);
23269 typedef int               (* ma_jack_activate_proc)                (ma_jack_client_t* client);
23270 typedef int               (* ma_jack_deactivate_proc)              (ma_jack_client_t* client);
23271 typedef int               (* ma_jack_connect_proc)                 (ma_jack_client_t* client, const char* source_port, const char* destination_port);
23272 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);
23273 typedef const char*       (* ma_jack_port_name_proc)               (const ma_jack_port_t* port);
23274 typedef void*             (* ma_jack_port_get_buffer_proc)         (ma_jack_port_t* port, ma_jack_nframes_t nframes);
23275 typedef void              (* ma_jack_free_proc)                    (void* ptr);
23276
23277 static ma_result ma_context_open_client__jack(ma_context* pContext, ma_jack_client_t** ppClient)
23278 {
23279     size_t maxClientNameSize;
23280     char clientName[256];
23281     ma_jack_status_t status;
23282     ma_jack_client_t* pClient;
23283
23284     MA_ASSERT(pContext != NULL);
23285     MA_ASSERT(ppClient != NULL);
23286
23287     if (ppClient) {
23288         *ppClient = NULL;
23289     }
23290
23291     maxClientNameSize = ((ma_jack_client_name_size_proc)pContext->jack.jack_client_name_size)(); /* Includes null terminator. */
23292     ma_strncpy_s(clientName, ma_min(sizeof(clientName), maxClientNameSize), (pContext->jack.pClientName != NULL) ? pContext->jack.pClientName : "miniaudio", (size_t)-1);
23293
23294     pClient = ((ma_jack_client_open_proc)pContext->jack.jack_client_open)(clientName, (pContext->jack.tryStartServer) ? 0 : ma_JackNoStartServer, &status, NULL);
23295     if (pClient == NULL) {
23296         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
23297     }
23298
23299     if (ppClient) {
23300         *ppClient = pClient;
23301     }
23302
23303     return MA_SUCCESS;
23304 }
23305
23306
23307 static ma_result ma_context_enumerate_devices__jack(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
23308 {
23309     ma_bool32 cbResult = MA_TRUE;
23310
23311     MA_ASSERT(pContext != NULL);
23312     MA_ASSERT(callback != NULL);
23313
23314     /* Playback. */
23315     if (cbResult) {
23316         ma_device_info deviceInfo;
23317         MA_ZERO_OBJECT(&deviceInfo);
23318         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
23319         deviceInfo.isDefault = MA_TRUE;    /* JACK only uses default devices. */
23320         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
23321     }
23322
23323     /* Capture. */
23324     if (cbResult) {
23325         ma_device_info deviceInfo;
23326         MA_ZERO_OBJECT(&deviceInfo);
23327         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
23328         deviceInfo.isDefault = MA_TRUE;    /* JACK only uses default devices. */
23329         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
23330     }
23331
23332     (void)cbResult; /* For silencing a static analysis warning. */
23333
23334     return MA_SUCCESS;
23335 }
23336
23337 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)
23338 {
23339     ma_jack_client_t* pClient;
23340     ma_result result;
23341     const char** ppPorts;
23342
23343     MA_ASSERT(pContext != NULL);
23344
23345     if (pDeviceID != NULL && pDeviceID->jack != 0) {
23346         return MA_NO_DEVICE;   /* Don't know the device. */
23347     }
23348
23349     /* Name / Description */
23350     if (deviceType == ma_device_type_playback) {
23351         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
23352     } else {
23353         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
23354     }
23355
23356     /* Jack only uses default devices. */
23357     pDeviceInfo->isDefault = MA_TRUE;
23358
23359     /* Jack only supports f32 and has a specific channel count and sample rate. */
23360     pDeviceInfo->nativeDataFormats[0].format = ma_format_f32;
23361
23362     /* The channel count and sample rate can only be determined by opening the device. */
23363     result = ma_context_open_client__jack(pContext, &pClient);
23364     if (result != MA_SUCCESS) {
23365         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result);
23366     }
23367
23368     pDeviceInfo->nativeDataFormats[0].sampleRate = ((ma_jack_get_sample_rate_proc)pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pClient);
23369     pDeviceInfo->nativeDataFormats[0].channels   = 0;
23370
23371     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));
23372     if (ppPorts == NULL) {
23373         ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
23374         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
23375     }
23376
23377     while (ppPorts[pDeviceInfo->nativeDataFormats[0].channels] != NULL) {
23378         pDeviceInfo->nativeDataFormats[0].channels += 1;
23379     }
23380
23381     pDeviceInfo->nativeDataFormats[0].flags = 0;
23382     pDeviceInfo->nativeDataFormatCount = 1;
23383
23384     ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppPorts);
23385     ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pClient);
23386
23387     (void)pContext;
23388     return MA_SUCCESS;
23389 }
23390
23391
23392 static ma_result ma_device_uninit__jack(ma_device* pDevice)
23393 {
23394     ma_context* pContext;
23395
23396     MA_ASSERT(pDevice != NULL);
23397
23398     pContext = pDevice->pContext;
23399     MA_ASSERT(pContext != NULL);
23400
23401     if (pDevice->jack.pClient != NULL) {
23402         ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDevice->jack.pClient);
23403     }
23404
23405     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23406         ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
23407     }
23408
23409     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23410         ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
23411     }
23412
23413     return MA_SUCCESS;
23414 }
23415
23416 static void ma_device__jack_shutdown_callback(void* pUserData)
23417 {
23418     /* JACK died. Stop the device. */
23419     ma_device* pDevice = (ma_device*)pUserData;
23420     MA_ASSERT(pDevice != NULL);
23421
23422     ma_device_stop(pDevice);
23423 }
23424
23425 static int ma_device__jack_buffer_size_callback(ma_jack_nframes_t frameCount, void* pUserData)
23426 {
23427     ma_device* pDevice = (ma_device*)pUserData;
23428     MA_ASSERT(pDevice != NULL);
23429
23430     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23431         size_t newBufferSize = frameCount * (pDevice->capture.internalChannels * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
23432         float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks);
23433         if (pNewBuffer == NULL) {
23434             return MA_OUT_OF_MEMORY;
23435         }
23436
23437         ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferCapture, &pDevice->pContext->allocationCallbacks);
23438
23439         pDevice->jack.pIntermediaryBufferCapture = pNewBuffer;
23440         pDevice->playback.internalPeriodSizeInFrames = frameCount;
23441     }
23442
23443     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23444         size_t newBufferSize = frameCount * (pDevice->playback.internalChannels * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
23445         float* pNewBuffer = (float*)ma__calloc_from_callbacks(newBufferSize, &pDevice->pContext->allocationCallbacks);
23446         if (pNewBuffer == NULL) {
23447             return MA_OUT_OF_MEMORY;
23448         }
23449
23450         ma__free_from_callbacks(pDevice->jack.pIntermediaryBufferPlayback, &pDevice->pContext->allocationCallbacks);
23451
23452         pDevice->jack.pIntermediaryBufferPlayback = pNewBuffer;
23453         pDevice->playback.internalPeriodSizeInFrames = frameCount;
23454     }
23455
23456     return 0;
23457 }
23458
23459 static int ma_device__jack_process_callback(ma_jack_nframes_t frameCount, void* pUserData)
23460 {
23461     ma_device* pDevice;
23462     ma_context* pContext;
23463     ma_uint32 iChannel;
23464
23465     pDevice = (ma_device*)pUserData;
23466     MA_ASSERT(pDevice != NULL);
23467
23468     pContext = pDevice->pContext;
23469     MA_ASSERT(pContext != NULL);
23470
23471     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23472         /* Channels need to be interleaved. */
23473         for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
23474             const float* pSrc = (const float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsCapture[iChannel], frameCount);
23475             if (pSrc != NULL) {
23476                 float* pDst = pDevice->jack.pIntermediaryBufferCapture + iChannel;
23477                 ma_jack_nframes_t iFrame;
23478                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
23479                     *pDst = *pSrc;
23480
23481                     pDst += pDevice->capture.internalChannels;
23482                     pSrc += 1;
23483                 }
23484             }
23485         }
23486
23487         ma_device_handle_backend_data_callback(pDevice, NULL, pDevice->jack.pIntermediaryBufferCapture, frameCount);
23488     }
23489
23490     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23491         ma_device_handle_backend_data_callback(pDevice, pDevice->jack.pIntermediaryBufferPlayback, NULL, frameCount);
23492
23493         /* Channels need to be deinterleaved. */
23494         for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
23495             float* pDst = (float*)((ma_jack_port_get_buffer_proc)pContext->jack.jack_port_get_buffer)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[iChannel], frameCount);
23496             if (pDst != NULL) {
23497                 const float* pSrc = pDevice->jack.pIntermediaryBufferPlayback + iChannel;
23498                 ma_jack_nframes_t iFrame;
23499                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
23500                     *pDst = *pSrc;
23501
23502                     pDst += 1;
23503                     pSrc += pDevice->playback.internalChannels;
23504                 }
23505             }
23506         }
23507     }
23508
23509     return 0;
23510 }
23511
23512 static ma_result ma_device_init__jack(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
23513 {
23514     ma_result result;
23515     ma_uint32 periodSizeInFrames;
23516
23517     MA_ASSERT(pConfig != NULL);
23518     MA_ASSERT(pDevice != NULL);
23519
23520     if (pConfig->deviceType == ma_device_type_loopback) {
23521         return MA_DEVICE_TYPE_NOT_SUPPORTED;
23522     }
23523
23524     /* Only supporting default devices with JACK. */
23525     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->pDeviceID != NULL && pDescriptorPlayback->pDeviceID->jack != 0) ||
23526         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->pDeviceID  != NULL && pDescriptorCapture->pDeviceID->jack  != 0)) {
23527         return MA_NO_DEVICE;
23528     }
23529
23530     /* No exclusive mode with the JACK backend. */
23531     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
23532         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
23533         return MA_SHARE_MODE_NOT_SUPPORTED;
23534     }
23535
23536     /* Open the client. */
23537     result = ma_context_open_client__jack(pDevice->pContext, (ma_jack_client_t**)&pDevice->jack.pClient);
23538     if (result != MA_SUCCESS) {
23539         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to open client.", result);
23540     }
23541
23542     /* Callbacks. */
23543     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) {
23544         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set process callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
23545     }
23546     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) {
23547         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to set buffer size callback.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
23548     }
23549
23550     ((ma_jack_on_shutdown_proc)pDevice->pContext->jack.jack_on_shutdown)((ma_jack_client_t*)pDevice->jack.pClient, ma_device__jack_shutdown_callback, pDevice);
23551
23552
23553     /* The buffer size in frames can change. */
23554     periodSizeInFrames = ((ma_jack_get_buffer_size_proc)pDevice->pContext->jack.jack_get_buffer_size)((ma_jack_client_t*)pDevice->jack.pClient);
23555
23556     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
23557         const char** ppPorts;
23558
23559         pDescriptorCapture->format     = ma_format_f32;
23560         pDescriptorCapture->channels   = 0;
23561         pDescriptorCapture->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
23562         ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDescriptorCapture->channels, pDescriptorCapture->channelMap);
23563
23564         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);
23565         if (ppPorts == NULL) {
23566             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
23567         }
23568
23569         while (ppPorts[pDescriptorCapture->channels] != NULL) {
23570             char name[64];
23571             ma_strcpy_s(name, sizeof(name), "capture");
23572             ma_itoa_s((int)pDescriptorCapture->channels, name+7, sizeof(name)-7, 10); /* 7 = length of "capture" */
23573
23574             pDevice->jack.pPortsCapture[pDescriptorCapture->channels] = ((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);
23575             if (pDevice->jack.pPortsCapture[pDescriptorCapture->channels] == NULL) {
23576                 ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
23577                 ma_device_uninit__jack(pDevice);
23578                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
23579             }
23580
23581             pDescriptorCapture->channels += 1;
23582         }
23583
23584         ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
23585
23586         pDescriptorCapture->periodSizeInFrames = periodSizeInFrames;
23587         pDescriptorCapture->periodCount        = 1; /* There's no notion of a period in JACK. Just set to 1. */
23588
23589         pDevice->jack.pIntermediaryBufferCapture = (float*)ma__calloc_from_callbacks(pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels), &pDevice->pContext->allocationCallbacks);
23590         if (pDevice->jack.pIntermediaryBufferCapture == NULL) {
23591             ma_device_uninit__jack(pDevice);
23592             return MA_OUT_OF_MEMORY;
23593         }
23594     }
23595
23596     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
23597         const char** ppPorts;
23598
23599         pDescriptorPlayback->format     = ma_format_f32;
23600         pDescriptorPlayback->channels   = 0;
23601         pDescriptorPlayback->sampleRate = ((ma_jack_get_sample_rate_proc)pDevice->pContext->jack.jack_get_sample_rate)((ma_jack_client_t*)pDevice->jack.pClient);
23602         ma_get_standard_channel_map(ma_standard_channel_map_alsa, pDescriptorPlayback->channels, pDescriptorPlayback->channelMap);
23603
23604         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);
23605         if (ppPorts == NULL) {
23606             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to query physical ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
23607         }
23608
23609         while (ppPorts[pDescriptorPlayback->channels] != NULL) {
23610             char name[64];
23611             ma_strcpy_s(name, sizeof(name), "playback");
23612             ma_itoa_s((int)pDescriptorPlayback->channels, name+8, sizeof(name)-8, 10); /* 8 = length of "playback" */
23613
23614             pDevice->jack.pPortsPlayback[pDescriptorPlayback->channels] = ((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);
23615             if (pDevice->jack.pPortsPlayback[pDescriptorPlayback->channels] == NULL) {
23616                 ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
23617                 ma_device_uninit__jack(pDevice);
23618                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to register ports.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
23619             }
23620
23621             pDescriptorPlayback->channels += 1;
23622         }
23623
23624         ((ma_jack_free_proc)pDevice->pContext->jack.jack_free)((void*)ppPorts);
23625
23626         pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames;
23627         pDescriptorPlayback->periodCount        = 1;   /* There's no notion of a period in JACK. Just set to 1. */
23628
23629         pDevice->jack.pIntermediaryBufferPlayback = (float*)ma__calloc_from_callbacks(pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels), &pDevice->pContext->allocationCallbacks);
23630         if (pDevice->jack.pIntermediaryBufferPlayback == NULL) {
23631             ma_device_uninit__jack(pDevice);
23632             return MA_OUT_OF_MEMORY;
23633         }
23634     }
23635
23636     return MA_SUCCESS;
23637 }
23638
23639
23640 static ma_result ma_device_start__jack(ma_device* pDevice)
23641 {
23642     ma_context* pContext = pDevice->pContext;
23643     int resultJACK;
23644     size_t i;
23645
23646     resultJACK = ((ma_jack_activate_proc)pContext->jack.jack_activate)((ma_jack_client_t*)pDevice->jack.pClient);
23647     if (resultJACK != 0) {
23648         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to activate the JACK client.", MA_FAILED_TO_START_BACKEND_DEVICE);
23649     }
23650
23651     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
23652         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);
23653         if (ppServerPorts == NULL) {
23654             ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
23655             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR);
23656         }
23657
23658         for (i = 0; ppServerPorts[i] != NULL; ++i) {
23659             const char* pServerPort = ppServerPorts[i];
23660             const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsCapture[i]);
23661
23662             resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pServerPort, pClientPort);
23663             if (resultJACK != 0) {
23664                 ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
23665                 ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
23666                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR);
23667             }
23668         }
23669
23670         ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
23671     }
23672
23673     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
23674         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);
23675         if (ppServerPorts == NULL) {
23676             ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
23677             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to retrieve physical ports.", MA_ERROR);
23678         }
23679
23680         for (i = 0; ppServerPorts[i] != NULL; ++i) {
23681             const char* pServerPort = ppServerPorts[i];
23682             const char* pClientPort = ((ma_jack_port_name_proc)pContext->jack.jack_port_name)((ma_jack_port_t*)pDevice->jack.pPortsPlayback[i]);
23683
23684             resultJACK = ((ma_jack_connect_proc)pContext->jack.jack_connect)((ma_jack_client_t*)pDevice->jack.pClient, pClientPort, pServerPort);
23685             if (resultJACK != 0) {
23686                 ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
23687                 ((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient);
23688                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] Failed to connect ports.", MA_ERROR);
23689             }
23690         }
23691
23692         ((ma_jack_free_proc)pContext->jack.jack_free)((void*)ppServerPorts);
23693     }
23694
23695     return MA_SUCCESS;
23696 }
23697
23698 static ma_result ma_device_stop__jack(ma_device* pDevice)
23699 {
23700     ma_context* pContext = pDevice->pContext;
23701     ma_stop_proc onStop;
23702
23703     if (((ma_jack_deactivate_proc)pContext->jack.jack_deactivate)((ma_jack_client_t*)pDevice->jack.pClient) != 0) {
23704         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[JACK] An error occurred when deactivating the JACK client.", MA_ERROR);
23705     }
23706
23707     onStop = pDevice->onStop;
23708     if (onStop) {
23709         onStop(pDevice);
23710     }
23711
23712     return MA_SUCCESS;
23713 }
23714
23715
23716 static ma_result ma_context_uninit__jack(ma_context* pContext)
23717 {
23718     MA_ASSERT(pContext != NULL);
23719     MA_ASSERT(pContext->backend == ma_backend_jack);
23720
23721     ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks);
23722     pContext->jack.pClientName = NULL;
23723
23724 #ifndef MA_NO_RUNTIME_LINKING
23725     ma_dlclose(pContext, pContext->jack.jackSO);
23726 #endif
23727
23728     return MA_SUCCESS;
23729 }
23730
23731 static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
23732 {
23733 #ifndef MA_NO_RUNTIME_LINKING
23734     const char* libjackNames[] = {
23735 #ifdef MA_WIN32
23736         "libjack.dll",
23737         "libjack64.dll"
23738 #else
23739         "libjack.so",
23740         "libjack.so.0"
23741 #endif
23742     };
23743     size_t i;
23744
23745     for (i = 0; i < ma_countof(libjackNames); ++i) {
23746         pContext->jack.jackSO = ma_dlopen(pContext, libjackNames[i]);
23747         if (pContext->jack.jackSO != NULL) {
23748             break;
23749         }
23750     }
23751
23752     if (pContext->jack.jackSO == NULL) {
23753         return MA_NO_BACKEND;
23754     }
23755
23756     pContext->jack.jack_client_open              = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_open");
23757     pContext->jack.jack_client_close             = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_close");
23758     pContext->jack.jack_client_name_size         = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_name_size");
23759     pContext->jack.jack_set_process_callback     = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_process_callback");
23760     pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_buffer_size_callback");
23761     pContext->jack.jack_on_shutdown              = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_on_shutdown");
23762     pContext->jack.jack_get_sample_rate          = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_sample_rate");
23763     pContext->jack.jack_get_buffer_size          = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_buffer_size");
23764     pContext->jack.jack_get_ports                = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_ports");
23765     pContext->jack.jack_activate                 = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_activate");
23766     pContext->jack.jack_deactivate               = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_deactivate");
23767     pContext->jack.jack_connect                  = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_connect");
23768     pContext->jack.jack_port_register            = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_register");
23769     pContext->jack.jack_port_name                = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_name");
23770     pContext->jack.jack_port_get_buffer          = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_get_buffer");
23771     pContext->jack.jack_free                     = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_free");
23772 #else
23773     /*
23774     This strange assignment system is here just to ensure type safety of miniaudio's function pointer
23775     types. If anything differs slightly the compiler should throw a warning.
23776     */
23777     ma_jack_client_open_proc              _jack_client_open              = jack_client_open;
23778     ma_jack_client_close_proc             _jack_client_close             = jack_client_close;
23779     ma_jack_client_name_size_proc         _jack_client_name_size         = jack_client_name_size;
23780     ma_jack_set_process_callback_proc     _jack_set_process_callback     = jack_set_process_callback;
23781     ma_jack_set_buffer_size_callback_proc _jack_set_buffer_size_callback = jack_set_buffer_size_callback;
23782     ma_jack_on_shutdown_proc              _jack_on_shutdown              = jack_on_shutdown;
23783     ma_jack_get_sample_rate_proc          _jack_get_sample_rate          = jack_get_sample_rate;
23784     ma_jack_get_buffer_size_proc          _jack_get_buffer_size          = jack_get_buffer_size;
23785     ma_jack_get_ports_proc                _jack_get_ports                = jack_get_ports;
23786     ma_jack_activate_proc                 _jack_activate                 = jack_activate;
23787     ma_jack_deactivate_proc               _jack_deactivate               = jack_deactivate;
23788     ma_jack_connect_proc                  _jack_connect                  = jack_connect;
23789     ma_jack_port_register_proc            _jack_port_register            = jack_port_register;
23790     ma_jack_port_name_proc                _jack_port_name                = jack_port_name;
23791     ma_jack_port_get_buffer_proc          _jack_port_get_buffer          = jack_port_get_buffer;
23792     ma_jack_free_proc                     _jack_free                     = jack_free;
23793
23794     pContext->jack.jack_client_open              = (ma_proc)_jack_client_open;
23795     pContext->jack.jack_client_close             = (ma_proc)_jack_client_close;
23796     pContext->jack.jack_client_name_size         = (ma_proc)_jack_client_name_size;
23797     pContext->jack.jack_set_process_callback     = (ma_proc)_jack_set_process_callback;
23798     pContext->jack.jack_set_buffer_size_callback = (ma_proc)_jack_set_buffer_size_callback;
23799     pContext->jack.jack_on_shutdown              = (ma_proc)_jack_on_shutdown;
23800     pContext->jack.jack_get_sample_rate          = (ma_proc)_jack_get_sample_rate;
23801     pContext->jack.jack_get_buffer_size          = (ma_proc)_jack_get_buffer_size;
23802     pContext->jack.jack_get_ports                = (ma_proc)_jack_get_ports;
23803     pContext->jack.jack_activate                 = (ma_proc)_jack_activate;
23804     pContext->jack.jack_deactivate               = (ma_proc)_jack_deactivate;
23805     pContext->jack.jack_connect                  = (ma_proc)_jack_connect;
23806     pContext->jack.jack_port_register            = (ma_proc)_jack_port_register;
23807     pContext->jack.jack_port_name                = (ma_proc)_jack_port_name;
23808     pContext->jack.jack_port_get_buffer          = (ma_proc)_jack_port_get_buffer;
23809     pContext->jack.jack_free                     = (ma_proc)_jack_free;
23810 #endif
23811
23812     if (pConfig->jack.pClientName != NULL) {
23813         pContext->jack.pClientName = ma_copy_string(pConfig->jack.pClientName, &pContext->allocationCallbacks);
23814     }
23815     pContext->jack.tryStartServer = pConfig->jack.tryStartServer;
23816
23817     /*
23818     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
23819     a temporary client.
23820     */
23821     {
23822         ma_jack_client_t* pDummyClient;
23823         ma_result result = ma_context_open_client__jack(pContext, &pDummyClient);
23824         if (result != MA_SUCCESS) {
23825             ma_free(pContext->jack.pClientName, &pContext->allocationCallbacks);
23826         #ifndef MA_NO_RUNTIME_LINKING
23827             ma_dlclose(pContext, pContext->jack.jackSO);
23828         #endif
23829             return MA_NO_BACKEND;
23830         }
23831
23832         ((ma_jack_client_close_proc)pContext->jack.jack_client_close)((ma_jack_client_t*)pDummyClient);
23833     }
23834
23835
23836     pCallbacks->onContextInit             = ma_context_init__jack;
23837     pCallbacks->onContextUninit           = ma_context_uninit__jack;
23838     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__jack;
23839     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__jack;
23840     pCallbacks->onDeviceInit              = ma_device_init__jack;
23841     pCallbacks->onDeviceUninit            = ma_device_uninit__jack;
23842     pCallbacks->onDeviceStart             = ma_device_start__jack;
23843     pCallbacks->onDeviceStop              = ma_device_stop__jack;
23844     pCallbacks->onDeviceRead              = NULL;   /* Not used because JACK is asynchronous. */
23845     pCallbacks->onDeviceWrite             = NULL;   /* Not used because JACK is asynchronous. */
23846     pCallbacks->onDeviceDataLoop          = NULL;   /* Not used because JACK is asynchronous. */
23847
23848     return MA_SUCCESS;
23849 }
23850 #endif  /* JACK */
23851
23852
23853
23854 /******************************************************************************
23855
23856 Core Audio Backend
23857
23858 References
23859 ==========
23860 - Technical Note TN2091: Device input using the HAL Output Audio Unit
23861     https://developer.apple.com/library/archive/technotes/tn2091/_index.html
23862
23863 ******************************************************************************/
23864 #ifdef MA_HAS_COREAUDIO
23865 #include <TargetConditionals.h>
23866
23867 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1
23868     #define MA_APPLE_MOBILE
23869     #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
23870         #define MA_APPLE_TV
23871     #endif
23872     #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
23873         #define MA_APPLE_WATCH
23874     #endif
23875 #else
23876     #define MA_APPLE_DESKTOP
23877 #endif
23878
23879 #if defined(MA_APPLE_DESKTOP)
23880 #include <CoreAudio/CoreAudio.h>
23881 #else
23882 #include <AVFoundation/AVFoundation.h>
23883 #endif
23884
23885 #include <AudioToolbox/AudioToolbox.h>
23886
23887 /* CoreFoundation */
23888 typedef Boolean (* ma_CFStringGetCString_proc)(CFStringRef theString, char* buffer, CFIndex bufferSize, CFStringEncoding encoding);
23889 typedef void (* ma_CFRelease_proc)(CFTypeRef cf);
23890
23891 /* CoreAudio */
23892 #if defined(MA_APPLE_DESKTOP)
23893 typedef OSStatus (* ma_AudioObjectGetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* ioDataSize, void* outData);
23894 typedef OSStatus (* ma_AudioObjectGetPropertyDataSize_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32* outDataSize);
23895 typedef OSStatus (* ma_AudioObjectSetPropertyData_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, UInt32 inQualifierDataSize, const void* inQualifierData, UInt32 inDataSize, const void* inData);
23896 typedef OSStatus (* ma_AudioObjectAddPropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData);
23897 typedef OSStatus (* ma_AudioObjectRemovePropertyListener_proc)(AudioObjectID inObjectID, const AudioObjectPropertyAddress* inAddress, AudioObjectPropertyListenerProc inListener, void* inClientData);
23898 #endif
23899
23900 /* AudioToolbox */
23901 typedef AudioComponent (* ma_AudioComponentFindNext_proc)(AudioComponent inComponent, const AudioComponentDescription* inDesc);
23902 typedef OSStatus (* ma_AudioComponentInstanceDispose_proc)(AudioComponentInstance inInstance);
23903 typedef OSStatus (* ma_AudioComponentInstanceNew_proc)(AudioComponent inComponent, AudioComponentInstance* outInstance);
23904 typedef OSStatus (* ma_AudioOutputUnitStart_proc)(AudioUnit inUnit);
23905 typedef OSStatus (* ma_AudioOutputUnitStop_proc)(AudioUnit inUnit);
23906 typedef OSStatus (* ma_AudioUnitAddPropertyListener_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitPropertyListenerProc inProc, void* inProcUserData);
23907 typedef OSStatus (* ma_AudioUnitGetPropertyInfo_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32* outDataSize, Boolean* outWriteable);
23908 typedef OSStatus (* ma_AudioUnitGetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void* outData, UInt32* ioDataSize);
23909 typedef OSStatus (* ma_AudioUnitSetProperty_proc)(AudioUnit inUnit, AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, const void* inData, UInt32 inDataSize);
23910 typedef OSStatus (* ma_AudioUnitInitialize_proc)(AudioUnit inUnit);
23911 typedef OSStatus (* ma_AudioUnitRender_proc)(AudioUnit inUnit, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inOutputBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData);
23912
23913
23914 #define MA_COREAUDIO_OUTPUT_BUS    0
23915 #define MA_COREAUDIO_INPUT_BUS     1
23916
23917 #if defined(MA_APPLE_DESKTOP)
23918 static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit);
23919 #endif
23920
23921 /*
23922 Core Audio
23923
23924 So far, Core Audio has been the worst backend to work with due to being both unintuitive and having almost no documentation
23925 apart from comments in the headers (which admittedly are quite good). For my own purposes, and for anybody out there whose
23926 needing to figure out how this darn thing works, I'm going to outline a few things here.
23927
23928 Since miniaudio is a fairly low-level API, one of the things it needs is control over specific devices, and it needs to be
23929 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
23930 that supports this level of detail. There was some public domain sample code I stumbled across that used the AudioComponent
23931 and AudioUnit APIs, but I couldn't see anything that gave low-level control over device selection and capabilities (the
23932 distinction between playback and capture in particular). Therefore, miniaudio is using the AudioObject API.
23933
23934 Most (all?) functions in the AudioObject API take a AudioObjectID as it's input. This is the device identifier. When
23935 retrieving global information, such as the device list, you use kAudioObjectSystemObject. When retrieving device-specific
23936 data, you pass in the ID for that device. In order to retrieve device-specific IDs you need to enumerate over each of the
23937 devices. This is done using the AudioObjectGetPropertyDataSize() and AudioObjectGetPropertyData() APIs which seem to be
23938 the central APIs for retrieving information about the system and specific devices.
23939
23940 To use the AudioObjectGetPropertyData() API you need to use the notion of a property address. A property address is a
23941 structure with three variables and is used to identify which property you are getting or setting. The first is the "selector"
23942 which is basically the specific property that you're wanting to retrieve or set. The second is the "scope", which is
23943 typically set to kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyScopeInput for input-specific properties and
23944 kAudioObjectPropertyScopeOutput for output-specific properties. The last is the "element" which is always set to
23945 kAudioObjectPropertyElementMaster in miniaudio's case. I don't know of any cases where this would be set to anything different.
23946
23947 Back to the earlier issue of device retrieval, you first use the AudioObjectGetPropertyDataSize() API to retrieve the size
23948 of the raw data which is just a list of AudioDeviceID's. You use the kAudioObjectSystemObject AudioObjectID, and a property
23949 address with the kAudioHardwarePropertyDevices selector and the kAudioObjectPropertyScopeGlobal scope. Once you have the
23950 size, allocate a block of memory of that size and then call AudioObjectGetPropertyData(). The data is just a list of
23951 AudioDeviceID's so just do "dataSize/sizeof(AudioDeviceID)" to know the device count.
23952 */
23953
23954 static ma_result ma_result_from_OSStatus(OSStatus status)
23955 {
23956     switch (status)
23957     {
23958         case noErr:                                   return MA_SUCCESS;
23959     #if defined(MA_APPLE_DESKTOP)
23960         case kAudioHardwareNotRunningError:           return MA_DEVICE_NOT_STARTED;
23961         case kAudioHardwareUnspecifiedError:          return MA_ERROR;
23962         case kAudioHardwareUnknownPropertyError:      return MA_INVALID_ARGS;
23963         case kAudioHardwareBadPropertySizeError:      return MA_INVALID_OPERATION;
23964         case kAudioHardwareIllegalOperationError:     return MA_INVALID_OPERATION;
23965         case kAudioHardwareBadObjectError:            return MA_INVALID_ARGS;
23966         case kAudioHardwareBadDeviceError:            return MA_INVALID_ARGS;
23967         case kAudioHardwareBadStreamError:            return MA_INVALID_ARGS;
23968         case kAudioHardwareUnsupportedOperationError: return MA_INVALID_OPERATION;
23969         case kAudioDeviceUnsupportedFormatError:      return MA_FORMAT_NOT_SUPPORTED;
23970         case kAudioDevicePermissionsError:            return MA_ACCESS_DENIED;
23971     #endif
23972         default:                                      return MA_ERROR;
23973     }
23974 }
23975
23976 #if 0
23977 static ma_channel ma_channel_from_AudioChannelBitmap(AudioChannelBitmap bit)
23978 {
23979     switch (bit)
23980     {
23981         case kAudioChannelBit_Left:                 return MA_CHANNEL_LEFT;
23982         case kAudioChannelBit_Right:                return MA_CHANNEL_RIGHT;
23983         case kAudioChannelBit_Center:               return MA_CHANNEL_FRONT_CENTER;
23984         case kAudioChannelBit_LFEScreen:            return MA_CHANNEL_LFE;
23985         case kAudioChannelBit_LeftSurround:         return MA_CHANNEL_BACK_LEFT;
23986         case kAudioChannelBit_RightSurround:        return MA_CHANNEL_BACK_RIGHT;
23987         case kAudioChannelBit_LeftCenter:           return MA_CHANNEL_FRONT_LEFT_CENTER;
23988         case kAudioChannelBit_RightCenter:          return MA_CHANNEL_FRONT_RIGHT_CENTER;
23989         case kAudioChannelBit_CenterSurround:       return MA_CHANNEL_BACK_CENTER;
23990         case kAudioChannelBit_LeftSurroundDirect:   return MA_CHANNEL_SIDE_LEFT;
23991         case kAudioChannelBit_RightSurroundDirect:  return MA_CHANNEL_SIDE_RIGHT;
23992         case kAudioChannelBit_TopCenterSurround:    return MA_CHANNEL_TOP_CENTER;
23993         case kAudioChannelBit_VerticalHeightLeft:   return MA_CHANNEL_TOP_FRONT_LEFT;
23994         case kAudioChannelBit_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER;
23995         case kAudioChannelBit_VerticalHeightRight:  return MA_CHANNEL_TOP_FRONT_RIGHT;
23996         case kAudioChannelBit_TopBackLeft:          return MA_CHANNEL_TOP_BACK_LEFT;
23997         case kAudioChannelBit_TopBackCenter:        return MA_CHANNEL_TOP_BACK_CENTER;
23998         case kAudioChannelBit_TopBackRight:         return MA_CHANNEL_TOP_BACK_RIGHT;
23999         default:                                    return MA_CHANNEL_NONE;
24000     }
24001 }
24002 #endif
24003
24004 static ma_result ma_format_from_AudioStreamBasicDescription(const AudioStreamBasicDescription* pDescription, ma_format* pFormatOut)
24005 {
24006     MA_ASSERT(pDescription != NULL);
24007     MA_ASSERT(pFormatOut != NULL);
24008
24009     *pFormatOut = ma_format_unknown;   /* Safety. */
24010
24011     /* There's a few things miniaudio doesn't support. */
24012     if (pDescription->mFormatID != kAudioFormatLinearPCM) {
24013         return MA_FORMAT_NOT_SUPPORTED;
24014     }
24015
24016     /* We don't support any non-packed formats that are aligned high. */
24017     if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsAlignedHigh) != 0) {
24018         return MA_FORMAT_NOT_SUPPORTED;
24019     }
24020
24021     /* Only supporting native-endian. */
24022     if ((ma_is_little_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) || (ma_is_big_endian() && (pDescription->mFormatFlags & kAudioFormatFlagIsBigEndian) == 0)) {
24023         return MA_FORMAT_NOT_SUPPORTED;
24024     }
24025
24026     /* We are not currently supporting non-interleaved formats (this will be added in a future version of miniaudio). */
24027     /*if ((pDescription->mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) {
24028         return MA_FORMAT_NOT_SUPPORTED;
24029     }*/
24030
24031     if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) {
24032         if (pDescription->mBitsPerChannel == 32) {
24033             *pFormatOut = ma_format_f32;
24034             return MA_SUCCESS;
24035         }
24036     } else {
24037         if ((pDescription->mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0) {
24038             if (pDescription->mBitsPerChannel == 16) {
24039                 *pFormatOut = ma_format_s16;
24040                 return MA_SUCCESS;
24041             } else if (pDescription->mBitsPerChannel == 24) {
24042                 if (pDescription->mBytesPerFrame == (pDescription->mBitsPerChannel/8 * pDescription->mChannelsPerFrame)) {
24043                     *pFormatOut = ma_format_s24;
24044                     return MA_SUCCESS;
24045                 } else {
24046                     if (pDescription->mBytesPerFrame/pDescription->mChannelsPerFrame == sizeof(ma_int32)) {
24047                         /* TODO: Implement ma_format_s24_32. */
24048                         /**pFormatOut = ma_format_s24_32;*/
24049                         /*return MA_SUCCESS;*/
24050                         return MA_FORMAT_NOT_SUPPORTED;
24051                     }
24052                 }
24053             } else if (pDescription->mBitsPerChannel == 32) {
24054                 *pFormatOut = ma_format_s32;
24055                 return MA_SUCCESS;
24056             }
24057         } else {
24058             if (pDescription->mBitsPerChannel == 8) {
24059                 *pFormatOut = ma_format_u8;
24060                 return MA_SUCCESS;
24061             }
24062         }
24063     }
24064
24065     /* Getting here means the format is not supported. */
24066     return MA_FORMAT_NOT_SUPPORTED;
24067 }
24068
24069 #if defined(MA_APPLE_DESKTOP)
24070 static ma_channel ma_channel_from_AudioChannelLabel(AudioChannelLabel label)
24071 {
24072     switch (label)
24073     {
24074         case kAudioChannelLabel_Unknown:              return MA_CHANNEL_NONE;
24075         case kAudioChannelLabel_Unused:               return MA_CHANNEL_NONE;
24076         case kAudioChannelLabel_UseCoordinates:       return MA_CHANNEL_NONE;
24077         case kAudioChannelLabel_Left:                 return MA_CHANNEL_LEFT;
24078         case kAudioChannelLabel_Right:                return MA_CHANNEL_RIGHT;
24079         case kAudioChannelLabel_Center:               return MA_CHANNEL_FRONT_CENTER;
24080         case kAudioChannelLabel_LFEScreen:            return MA_CHANNEL_LFE;
24081         case kAudioChannelLabel_LeftSurround:         return MA_CHANNEL_BACK_LEFT;
24082         case kAudioChannelLabel_RightSurround:        return MA_CHANNEL_BACK_RIGHT;
24083         case kAudioChannelLabel_LeftCenter:           return MA_CHANNEL_FRONT_LEFT_CENTER;
24084         case kAudioChannelLabel_RightCenter:          return MA_CHANNEL_FRONT_RIGHT_CENTER;
24085         case kAudioChannelLabel_CenterSurround:       return MA_CHANNEL_BACK_CENTER;
24086         case kAudioChannelLabel_LeftSurroundDirect:   return MA_CHANNEL_SIDE_LEFT;
24087         case kAudioChannelLabel_RightSurroundDirect:  return MA_CHANNEL_SIDE_RIGHT;
24088         case kAudioChannelLabel_TopCenterSurround:    return MA_CHANNEL_TOP_CENTER;
24089         case kAudioChannelLabel_VerticalHeightLeft:   return MA_CHANNEL_TOP_FRONT_LEFT;
24090         case kAudioChannelLabel_VerticalHeightCenter: return MA_CHANNEL_TOP_FRONT_CENTER;
24091         case kAudioChannelLabel_VerticalHeightRight:  return MA_CHANNEL_TOP_FRONT_RIGHT;
24092         case kAudioChannelLabel_TopBackLeft:          return MA_CHANNEL_TOP_BACK_LEFT;
24093         case kAudioChannelLabel_TopBackCenter:        return MA_CHANNEL_TOP_BACK_CENTER;
24094         case kAudioChannelLabel_TopBackRight:         return MA_CHANNEL_TOP_BACK_RIGHT;
24095         case kAudioChannelLabel_RearSurroundLeft:     return MA_CHANNEL_BACK_LEFT;
24096         case kAudioChannelLabel_RearSurroundRight:    return MA_CHANNEL_BACK_RIGHT;
24097         case kAudioChannelLabel_LeftWide:             return MA_CHANNEL_SIDE_LEFT;
24098         case kAudioChannelLabel_RightWide:            return MA_CHANNEL_SIDE_RIGHT;
24099         case kAudioChannelLabel_LFE2:                 return MA_CHANNEL_LFE;
24100         case kAudioChannelLabel_LeftTotal:            return MA_CHANNEL_LEFT;
24101         case kAudioChannelLabel_RightTotal:           return MA_CHANNEL_RIGHT;
24102         case kAudioChannelLabel_HearingImpaired:      return MA_CHANNEL_NONE;
24103         case kAudioChannelLabel_Narration:            return MA_CHANNEL_MONO;
24104         case kAudioChannelLabel_Mono:                 return MA_CHANNEL_MONO;
24105         case kAudioChannelLabel_DialogCentricMix:     return MA_CHANNEL_MONO;
24106         case kAudioChannelLabel_CenterSurroundDirect: return MA_CHANNEL_BACK_CENTER;
24107         case kAudioChannelLabel_Haptic:               return MA_CHANNEL_NONE;
24108         case kAudioChannelLabel_Ambisonic_W:          return MA_CHANNEL_NONE;
24109         case kAudioChannelLabel_Ambisonic_X:          return MA_CHANNEL_NONE;
24110         case kAudioChannelLabel_Ambisonic_Y:          return MA_CHANNEL_NONE;
24111         case kAudioChannelLabel_Ambisonic_Z:          return MA_CHANNEL_NONE;
24112         case kAudioChannelLabel_MS_Mid:               return MA_CHANNEL_LEFT;
24113         case kAudioChannelLabel_MS_Side:              return MA_CHANNEL_RIGHT;
24114         case kAudioChannelLabel_XY_X:                 return MA_CHANNEL_LEFT;
24115         case kAudioChannelLabel_XY_Y:                 return MA_CHANNEL_RIGHT;
24116         case kAudioChannelLabel_HeadphonesLeft:       return MA_CHANNEL_LEFT;
24117         case kAudioChannelLabel_HeadphonesRight:      return MA_CHANNEL_RIGHT;
24118         case kAudioChannelLabel_ClickTrack:           return MA_CHANNEL_NONE;
24119         case kAudioChannelLabel_ForeignLanguage:      return MA_CHANNEL_NONE;
24120         case kAudioChannelLabel_Discrete:             return MA_CHANNEL_NONE;
24121         case kAudioChannelLabel_Discrete_0:           return MA_CHANNEL_AUX_0;
24122         case kAudioChannelLabel_Discrete_1:           return MA_CHANNEL_AUX_1;
24123         case kAudioChannelLabel_Discrete_2:           return MA_CHANNEL_AUX_2;
24124         case kAudioChannelLabel_Discrete_3:           return MA_CHANNEL_AUX_3;
24125         case kAudioChannelLabel_Discrete_4:           return MA_CHANNEL_AUX_4;
24126         case kAudioChannelLabel_Discrete_5:           return MA_CHANNEL_AUX_5;
24127         case kAudioChannelLabel_Discrete_6:           return MA_CHANNEL_AUX_6;
24128         case kAudioChannelLabel_Discrete_7:           return MA_CHANNEL_AUX_7;
24129         case kAudioChannelLabel_Discrete_8:           return MA_CHANNEL_AUX_8;
24130         case kAudioChannelLabel_Discrete_9:           return MA_CHANNEL_AUX_9;
24131         case kAudioChannelLabel_Discrete_10:          return MA_CHANNEL_AUX_10;
24132         case kAudioChannelLabel_Discrete_11:          return MA_CHANNEL_AUX_11;
24133         case kAudioChannelLabel_Discrete_12:          return MA_CHANNEL_AUX_12;
24134         case kAudioChannelLabel_Discrete_13:          return MA_CHANNEL_AUX_13;
24135         case kAudioChannelLabel_Discrete_14:          return MA_CHANNEL_AUX_14;
24136         case kAudioChannelLabel_Discrete_15:          return MA_CHANNEL_AUX_15;
24137         case kAudioChannelLabel_Discrete_65535:       return MA_CHANNEL_NONE;
24138
24139     #if 0   /* Introduced in a later version of macOS. */
24140         case kAudioChannelLabel_HOA_ACN:              return MA_CHANNEL_NONE;
24141         case kAudioChannelLabel_HOA_ACN_0:            return MA_CHANNEL_AUX_0;
24142         case kAudioChannelLabel_HOA_ACN_1:            return MA_CHANNEL_AUX_1;
24143         case kAudioChannelLabel_HOA_ACN_2:            return MA_CHANNEL_AUX_2;
24144         case kAudioChannelLabel_HOA_ACN_3:            return MA_CHANNEL_AUX_3;
24145         case kAudioChannelLabel_HOA_ACN_4:            return MA_CHANNEL_AUX_4;
24146         case kAudioChannelLabel_HOA_ACN_5:            return MA_CHANNEL_AUX_5;
24147         case kAudioChannelLabel_HOA_ACN_6:            return MA_CHANNEL_AUX_6;
24148         case kAudioChannelLabel_HOA_ACN_7:            return MA_CHANNEL_AUX_7;
24149         case kAudioChannelLabel_HOA_ACN_8:            return MA_CHANNEL_AUX_8;
24150         case kAudioChannelLabel_HOA_ACN_9:            return MA_CHANNEL_AUX_9;
24151         case kAudioChannelLabel_HOA_ACN_10:           return MA_CHANNEL_AUX_10;
24152         case kAudioChannelLabel_HOA_ACN_11:           return MA_CHANNEL_AUX_11;
24153         case kAudioChannelLabel_HOA_ACN_12:           return MA_CHANNEL_AUX_12;
24154         case kAudioChannelLabel_HOA_ACN_13:           return MA_CHANNEL_AUX_13;
24155         case kAudioChannelLabel_HOA_ACN_14:           return MA_CHANNEL_AUX_14;
24156         case kAudioChannelLabel_HOA_ACN_15:           return MA_CHANNEL_AUX_15;
24157         case kAudioChannelLabel_HOA_ACN_65024:        return MA_CHANNEL_NONE;
24158     #endif
24159
24160         default:                                      return MA_CHANNEL_NONE;
24161     }
24162 }
24163
24164 static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* pChannelLayout, ma_channel* pChannelMap, size_t channelMapCap)
24165 {
24166     MA_ASSERT(pChannelLayout != NULL);
24167
24168     if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
24169         UInt32 iChannel;
24170         for (iChannel = 0; iChannel < pChannelLayout->mNumberChannelDescriptions && iChannel < channelMapCap; ++iChannel) {
24171             pChannelMap[iChannel] = ma_channel_from_AudioChannelLabel(pChannelLayout->mChannelDescriptions[iChannel].mChannelLabel);
24172         }
24173     } else
24174 #if 0
24175     if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
24176         /* This is the same kind of system that's used by Windows audio APIs. */
24177         UInt32 iChannel = 0;
24178         UInt32 iBit;
24179         AudioChannelBitmap bitmap = pChannelLayout->mChannelBitmap;
24180         for (iBit = 0; iBit < 32 && iChannel < channelMapCap; ++iBit) {
24181             AudioChannelBitmap bit = bitmap & (1 << iBit);
24182             if (bit != 0) {
24183                 pChannelMap[iChannel++] = ma_channel_from_AudioChannelBit(bit);
24184             }
24185         }
24186     } else
24187 #endif
24188     {
24189         /*
24190         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
24191         be updated to determine the mapping based on the tag.
24192         */
24193         UInt32 channelCount;
24194
24195         /* Our channel map retrieval APIs below take 32-bit integers, so we'll want to clamp the channel map capacity. */
24196         if (channelMapCap > 0xFFFFFFFF) {
24197             channelMapCap = 0xFFFFFFFF;
24198         }
24199
24200         channelCount = ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag), (UInt32)channelMapCap);
24201
24202         switch (pChannelLayout->mChannelLayoutTag)
24203         {
24204             case kAudioChannelLayoutTag_Mono:
24205             case kAudioChannelLayoutTag_Stereo:
24206             case kAudioChannelLayoutTag_StereoHeadphones:
24207             case kAudioChannelLayoutTag_MatrixStereo:
24208             case kAudioChannelLayoutTag_MidSide:
24209             case kAudioChannelLayoutTag_XY:
24210             case kAudioChannelLayoutTag_Binaural:
24211             case kAudioChannelLayoutTag_Ambisonic_B_Format:
24212             {
24213                 ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap);
24214             } break;
24215
24216             case kAudioChannelLayoutTag_Octagonal:
24217             {
24218                 pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
24219                 pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
24220             } /* Intentional fallthrough. */
24221             case kAudioChannelLayoutTag_Hexagonal:
24222             {
24223                 pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
24224             } /* Intentional fallthrough. */
24225             case kAudioChannelLayoutTag_Pentagonal:
24226             {
24227                 pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
24228             } /* Intentional fallghrough. */
24229             case kAudioChannelLayoutTag_Quadraphonic:
24230             {
24231                 pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
24232                 pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
24233                 pChannelMap[1] = MA_CHANNEL_RIGHT;
24234                 pChannelMap[0] = MA_CHANNEL_LEFT;
24235             } break;
24236
24237             /* TODO: Add support for more tags here. */
24238
24239             default:
24240             {
24241                 ma_get_standard_channel_map(ma_standard_channel_map_default, channelCount, pChannelMap);
24242             } break;
24243         }
24244     }
24245
24246     return MA_SUCCESS;
24247 }
24248
24249 static ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt32* pDeviceCount, AudioObjectID** ppDeviceObjectIDs) /* NOTE: Free the returned buffer with ma_free(). */
24250 {
24251     AudioObjectPropertyAddress propAddressDevices;
24252     UInt32 deviceObjectsDataSize;
24253     OSStatus status;
24254     AudioObjectID* pDeviceObjectIDs;
24255
24256     MA_ASSERT(pContext != NULL);
24257     MA_ASSERT(pDeviceCount != NULL);
24258     MA_ASSERT(ppDeviceObjectIDs != NULL);
24259
24260     /* Safety. */
24261     *pDeviceCount = 0;
24262     *ppDeviceObjectIDs = NULL;
24263
24264     propAddressDevices.mSelector = kAudioHardwarePropertyDevices;
24265     propAddressDevices.mScope    = kAudioObjectPropertyScopeGlobal;
24266     propAddressDevices.mElement  = kAudioObjectPropertyElementMaster;
24267
24268     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize);
24269     if (status != noErr) {
24270         return ma_result_from_OSStatus(status);
24271     }
24272
24273     pDeviceObjectIDs = (AudioObjectID*)ma_malloc(deviceObjectsDataSize, &pContext->allocationCallbacks);
24274     if (pDeviceObjectIDs == NULL) {
24275         return MA_OUT_OF_MEMORY;
24276     }
24277
24278     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDevices, 0, NULL, &deviceObjectsDataSize, pDeviceObjectIDs);
24279     if (status != noErr) {
24280         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
24281         return ma_result_from_OSStatus(status);
24282     }
24283
24284     *pDeviceCount = deviceObjectsDataSize / sizeof(AudioObjectID);
24285     *ppDeviceObjectIDs = pDeviceObjectIDs;
24286
24287     return MA_SUCCESS;
24288 }
24289
24290 static ma_result ma_get_AudioObject_uid_as_CFStringRef(ma_context* pContext, AudioObjectID objectID, CFStringRef* pUID)
24291 {
24292     AudioObjectPropertyAddress propAddress;
24293     UInt32 dataSize;
24294     OSStatus status;
24295
24296     MA_ASSERT(pContext != NULL);
24297
24298     propAddress.mSelector = kAudioDevicePropertyDeviceUID;
24299     propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
24300     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24301
24302     dataSize = sizeof(*pUID);
24303     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, pUID);
24304     if (status != noErr) {
24305         return ma_result_from_OSStatus(status);
24306     }
24307
24308     return MA_SUCCESS;
24309 }
24310
24311 static ma_result ma_get_AudioObject_uid(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut)
24312 {
24313     CFStringRef uid;
24314     ma_result result;
24315
24316     MA_ASSERT(pContext != NULL);
24317
24318     result = ma_get_AudioObject_uid_as_CFStringRef(pContext, objectID, &uid);
24319     if (result != MA_SUCCESS) {
24320         return result;
24321     }
24322
24323     if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(uid, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
24324         return MA_ERROR;
24325     }
24326
24327     ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(uid);
24328     return MA_SUCCESS;
24329 }
24330
24331 static ma_result ma_get_AudioObject_name(ma_context* pContext, AudioObjectID objectID, size_t bufferSize, char* bufferOut)
24332 {
24333     AudioObjectPropertyAddress propAddress;
24334     CFStringRef deviceName = NULL;
24335     UInt32 dataSize;
24336     OSStatus status;
24337
24338     MA_ASSERT(pContext != NULL);
24339
24340     propAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
24341     propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
24342     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24343
24344     dataSize = sizeof(deviceName);
24345     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(objectID, &propAddress, 0, NULL, &dataSize, &deviceName);
24346     if (status != noErr) {
24347         return ma_result_from_OSStatus(status);
24348     }
24349
24350     if (!((ma_CFStringGetCString_proc)pContext->coreaudio.CFStringGetCString)(deviceName, bufferOut, bufferSize, kCFStringEncodingUTF8)) {
24351         return MA_ERROR;
24352     }
24353
24354     ((ma_CFRelease_proc)pContext->coreaudio.CFRelease)(deviceName);
24355     return MA_SUCCESS;
24356 }
24357
24358 static ma_bool32 ma_does_AudioObject_support_scope(ma_context* pContext, AudioObjectID deviceObjectID, AudioObjectPropertyScope scope)
24359 {
24360     AudioObjectPropertyAddress propAddress;
24361     UInt32 dataSize;
24362     OSStatus status;
24363     AudioBufferList* pBufferList;
24364     ma_bool32 isSupported;
24365
24366     MA_ASSERT(pContext != NULL);
24367
24368     /* 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. */
24369     propAddress.mSelector = kAudioDevicePropertyStreamConfiguration;
24370     propAddress.mScope    = scope;
24371     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24372
24373     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
24374     if (status != noErr) {
24375         return MA_FALSE;
24376     }
24377
24378     pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(dataSize, &pContext->allocationCallbacks);
24379     if (pBufferList == NULL) {
24380         return MA_FALSE;   /* Out of memory. */
24381     }
24382
24383     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pBufferList);
24384     if (status != noErr) {
24385         ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks);
24386         return MA_FALSE;
24387     }
24388
24389     isSupported = MA_FALSE;
24390     if (pBufferList->mNumberBuffers > 0) {
24391         isSupported = MA_TRUE;
24392     }
24393
24394     ma__free_from_callbacks(pBufferList, &pContext->allocationCallbacks);
24395     return isSupported;
24396 }
24397
24398 static ma_bool32 ma_does_AudioObject_support_playback(ma_context* pContext, AudioObjectID deviceObjectID)
24399 {
24400     return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeOutput);
24401 }
24402
24403 static ma_bool32 ma_does_AudioObject_support_capture(ma_context* pContext, AudioObjectID deviceObjectID)
24404 {
24405     return ma_does_AudioObject_support_scope(pContext, deviceObjectID, kAudioObjectPropertyScopeInput);
24406 }
24407
24408
24409 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(). */
24410 {
24411     AudioObjectPropertyAddress propAddress;
24412     UInt32 dataSize;
24413     OSStatus status;
24414     AudioStreamRangedDescription* pDescriptions;
24415
24416     MA_ASSERT(pContext != NULL);
24417     MA_ASSERT(pDescriptionCount != NULL);
24418     MA_ASSERT(ppDescriptions != NULL);
24419
24420     /*
24421     TODO: Experiment with kAudioStreamPropertyAvailablePhysicalFormats instead of (or in addition to) kAudioStreamPropertyAvailableVirtualFormats. My
24422           MacBook Pro uses s24/32 format, however, which miniaudio does not currently support.
24423     */
24424     propAddress.mSelector = kAudioStreamPropertyAvailableVirtualFormats; /*kAudioStreamPropertyAvailablePhysicalFormats;*/
24425     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
24426     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24427
24428     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
24429     if (status != noErr) {
24430         return ma_result_from_OSStatus(status);
24431     }
24432
24433     pDescriptions = (AudioStreamRangedDescription*)ma_malloc(dataSize, &pContext->allocationCallbacks);
24434     if (pDescriptions == NULL) {
24435         return MA_OUT_OF_MEMORY;
24436     }
24437
24438     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pDescriptions);
24439     if (status != noErr) {
24440         ma_free(pDescriptions, &pContext->allocationCallbacks);
24441         return ma_result_from_OSStatus(status);
24442     }
24443
24444     *pDescriptionCount = dataSize / sizeof(*pDescriptions);
24445     *ppDescriptions = pDescriptions;
24446     return MA_SUCCESS;
24447 }
24448
24449
24450 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(). */
24451 {
24452     AudioObjectPropertyAddress propAddress;
24453     UInt32 dataSize;
24454     OSStatus status;
24455     AudioChannelLayout* pChannelLayout;
24456
24457     MA_ASSERT(pContext != NULL);
24458     MA_ASSERT(ppChannelLayout != NULL);
24459
24460     *ppChannelLayout = NULL;    /* Safety. */
24461
24462     propAddress.mSelector = kAudioDevicePropertyPreferredChannelLayout;
24463     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
24464     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24465
24466     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
24467     if (status != noErr) {
24468         return ma_result_from_OSStatus(status);
24469     }
24470
24471     pChannelLayout = (AudioChannelLayout*)ma_malloc(dataSize, &pContext->allocationCallbacks);
24472     if (pChannelLayout == NULL) {
24473         return MA_OUT_OF_MEMORY;
24474     }
24475
24476     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pChannelLayout);
24477     if (status != noErr) {
24478         ma_free(pChannelLayout, &pContext->allocationCallbacks);
24479         return ma_result_from_OSStatus(status);
24480     }
24481
24482     *ppChannelLayout = pChannelLayout;
24483     return MA_SUCCESS;
24484 }
24485
24486 static ma_result ma_get_AudioObject_channel_count(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pChannelCount)
24487 {
24488     AudioChannelLayout* pChannelLayout;
24489     ma_result result;
24490
24491     MA_ASSERT(pContext != NULL);
24492     MA_ASSERT(pChannelCount != NULL);
24493
24494     *pChannelCount = 0; /* Safety. */
24495
24496     result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout);
24497     if (result != MA_SUCCESS) {
24498         return result;
24499     }
24500
24501     if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
24502         *pChannelCount = pChannelLayout->mNumberChannelDescriptions;
24503     } else if (pChannelLayout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
24504         *pChannelCount = ma_count_set_bits(pChannelLayout->mChannelBitmap);
24505     } else {
24506         *pChannelCount = AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag);
24507     }
24508
24509     ma_free(pChannelLayout, &pContext->allocationCallbacks);
24510     return MA_SUCCESS;
24511 }
24512
24513 #if 0
24514 static ma_result ma_get_AudioObject_channel_map(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap)
24515 {
24516     AudioChannelLayout* pChannelLayout;
24517     ma_result result;
24518
24519     MA_ASSERT(pContext != NULL);
24520
24521     result = ma_get_AudioObject_channel_layout(pContext, deviceObjectID, deviceType, &pChannelLayout);
24522     if (result != MA_SUCCESS) {
24523         return result;  /* Rather than always failing here, would it be more robust to simply assume a default? */
24524     }
24525
24526     result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap);
24527     if (result != MA_SUCCESS) {
24528         ma_free(pChannelLayout, &pContext->allocationCallbacks);
24529         return result;
24530     }
24531
24532     ma_free(pChannelLayout, &pContext->allocationCallbacks);
24533     return result;
24534 }
24535 #endif
24536
24537 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(). */
24538 {
24539     AudioObjectPropertyAddress propAddress;
24540     UInt32 dataSize;
24541     OSStatus status;
24542     AudioValueRange* pSampleRateRanges;
24543
24544     MA_ASSERT(pContext != NULL);
24545     MA_ASSERT(pSampleRateRangesCount != NULL);
24546     MA_ASSERT(ppSampleRateRanges != NULL);
24547
24548     /* Safety. */
24549     *pSampleRateRangesCount = 0;
24550     *ppSampleRateRanges = NULL;
24551
24552     propAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
24553     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
24554     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24555
24556     status = ((ma_AudioObjectGetPropertyDataSize_proc)pContext->coreaudio.AudioObjectGetPropertyDataSize)(deviceObjectID, &propAddress, 0, NULL, &dataSize);
24557     if (status != noErr) {
24558         return ma_result_from_OSStatus(status);
24559     }
24560
24561     pSampleRateRanges = (AudioValueRange*)ma_malloc(dataSize, &pContext->allocationCallbacks);
24562     if (pSampleRateRanges == NULL) {
24563         return MA_OUT_OF_MEMORY;
24564     }
24565
24566     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, pSampleRateRanges);
24567     if (status != noErr) {
24568         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
24569         return ma_result_from_OSStatus(status);
24570     }
24571
24572     *pSampleRateRangesCount = dataSize / sizeof(*pSampleRateRanges);
24573     *ppSampleRateRanges = pSampleRateRanges;
24574     return MA_SUCCESS;
24575 }
24576
24577 #if 0
24578 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)
24579 {
24580     UInt32 sampleRateRangeCount;
24581     AudioValueRange* pSampleRateRanges;
24582     ma_result result;
24583
24584     MA_ASSERT(pContext != NULL);
24585     MA_ASSERT(pSampleRateOut != NULL);
24586
24587     *pSampleRateOut = 0;    /* Safety. */
24588
24589     result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
24590     if (result != MA_SUCCESS) {
24591         return result;
24592     }
24593
24594     if (sampleRateRangeCount == 0) {
24595         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
24596         return MA_ERROR;   /* Should never hit this case should we? */
24597     }
24598
24599     if (sampleRateIn == 0) {
24600         /* Search in order of miniaudio's preferred priority. */
24601         UInt32 iMALSampleRate;
24602         for (iMALSampleRate = 0; iMALSampleRate < ma_countof(g_maStandardSampleRatePriorities); ++iMALSampleRate) {
24603             ma_uint32 malSampleRate = g_maStandardSampleRatePriorities[iMALSampleRate];
24604             UInt32 iCASampleRate;
24605             for (iCASampleRate = 0; iCASampleRate < sampleRateRangeCount; ++iCASampleRate) {
24606                 AudioValueRange caSampleRate = pSampleRateRanges[iCASampleRate];
24607                 if (caSampleRate.mMinimum <= malSampleRate && caSampleRate.mMaximum >= malSampleRate) {
24608                     *pSampleRateOut = malSampleRate;
24609                     ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
24610                     return MA_SUCCESS;
24611                 }
24612             }
24613         }
24614
24615         /*
24616         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
24617         case we just fall back to the first one reported by Core Audio.
24618         */
24619         MA_ASSERT(sampleRateRangeCount > 0);
24620
24621         *pSampleRateOut = pSampleRateRanges[0].mMinimum;
24622         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
24623         return MA_SUCCESS;
24624     } else {
24625         /* Find the closest match to this sample rate. */
24626         UInt32 currentAbsoluteDifference = INT32_MAX;
24627         UInt32 iCurrentClosestRange = (UInt32)-1;
24628         UInt32 iRange;
24629         for (iRange = 0; iRange < sampleRateRangeCount; ++iRange) {
24630             if (pSampleRateRanges[iRange].mMinimum <= sampleRateIn && pSampleRateRanges[iRange].mMaximum >= sampleRateIn) {
24631                 *pSampleRateOut = sampleRateIn;
24632                 ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
24633                 return MA_SUCCESS;
24634             } else {
24635                 UInt32 absoluteDifference;
24636                 if (pSampleRateRanges[iRange].mMinimum > sampleRateIn) {
24637                     absoluteDifference = pSampleRateRanges[iRange].mMinimum - sampleRateIn;
24638                 } else {
24639                     absoluteDifference = sampleRateIn - pSampleRateRanges[iRange].mMaximum;
24640                 }
24641
24642                 if (currentAbsoluteDifference > absoluteDifference) {
24643                     currentAbsoluteDifference = absoluteDifference;
24644                     iCurrentClosestRange = iRange;
24645                 }
24646             }
24647         }
24648
24649         MA_ASSERT(iCurrentClosestRange != (UInt32)-1);
24650
24651         *pSampleRateOut = pSampleRateRanges[iCurrentClosestRange].mMinimum;
24652         ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
24653         return MA_SUCCESS;
24654     }
24655
24656     /* Should never get here, but it would mean we weren't able to find any suitable sample rates. */
24657     /*ma_free(pSampleRateRanges, &pContext->allocationCallbacks);*/
24658     /*return MA_ERROR;*/
24659 }
24660 #endif
24661
24662 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)
24663 {
24664     AudioObjectPropertyAddress propAddress;
24665     AudioValueRange bufferSizeRange;
24666     UInt32 dataSize;
24667     OSStatus status;
24668
24669     MA_ASSERT(pContext != NULL);
24670     MA_ASSERT(pBufferSizeInFramesOut != NULL);
24671
24672     *pBufferSizeInFramesOut = 0;    /* Safety. */
24673
24674     propAddress.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
24675     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
24676     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24677
24678     dataSize = sizeof(bufferSizeRange);
24679     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &bufferSizeRange);
24680     if (status != noErr) {
24681         return ma_result_from_OSStatus(status);
24682     }
24683
24684     /* This is just a clamp. */
24685     if (bufferSizeInFramesIn < bufferSizeRange.mMinimum) {
24686         *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMinimum;
24687     } else if (bufferSizeInFramesIn > bufferSizeRange.mMaximum) {
24688         *pBufferSizeInFramesOut = (ma_uint32)bufferSizeRange.mMaximum;
24689     } else {
24690         *pBufferSizeInFramesOut = bufferSizeInFramesIn;
24691     }
24692
24693     return MA_SUCCESS;
24694 }
24695
24696 static ma_result ma_set_AudioObject_buffer_size_in_frames(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_uint32* pPeriodSizeInOut)
24697 {
24698     ma_result result;
24699     ma_uint32 chosenBufferSizeInFrames;
24700     AudioObjectPropertyAddress propAddress;
24701     UInt32 dataSize;
24702     OSStatus status;
24703
24704     MA_ASSERT(pContext != NULL);
24705
24706     result = ma_get_AudioObject_closest_buffer_size_in_frames(pContext, deviceObjectID, deviceType, *pPeriodSizeInOut, &chosenBufferSizeInFrames);
24707     if (result != MA_SUCCESS) {
24708         return result;
24709     }
24710
24711     /* Try setting the size of the buffer... If this fails we just use whatever is currently set. */
24712     propAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
24713     propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
24714     propAddress.mElement  = kAudioObjectPropertyElementMaster;
24715
24716     ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(chosenBufferSizeInFrames), &chosenBufferSizeInFrames);
24717
24718     /* Get the actual size of the buffer. */
24719     dataSize = sizeof(*pPeriodSizeInOut);
24720     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(deviceObjectID, &propAddress, 0, NULL, &dataSize, &chosenBufferSizeInFrames);
24721     if (status != noErr) {
24722         return ma_result_from_OSStatus(status);
24723     }
24724
24725     *pPeriodSizeInOut = chosenBufferSizeInFrames;
24726     return MA_SUCCESS;
24727 }
24728
24729 static ma_result ma_find_default_AudioObjectID(ma_context* pContext, ma_device_type deviceType, AudioObjectID* pDeviceObjectID)
24730 {
24731     AudioObjectPropertyAddress propAddressDefaultDevice;
24732     UInt32 defaultDeviceObjectIDSize = sizeof(AudioObjectID);
24733     AudioObjectID defaultDeviceObjectID;
24734     OSStatus status;
24735
24736     MA_ASSERT(pContext != NULL);
24737     MA_ASSERT(pDeviceObjectID != NULL);
24738
24739     /* Safety. */
24740     *pDeviceObjectID = 0;
24741
24742     propAddressDefaultDevice.mScope = kAudioObjectPropertyScopeGlobal;
24743     propAddressDefaultDevice.mElement = kAudioObjectPropertyElementMaster;
24744     if (deviceType == ma_device_type_playback) {
24745         propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
24746     } else {
24747         propAddressDefaultDevice.mSelector = kAudioHardwarePropertyDefaultInputDevice;
24748     }
24749
24750     defaultDeviceObjectIDSize = sizeof(AudioObjectID);
24751     status = ((ma_AudioObjectGetPropertyData_proc)pContext->coreaudio.AudioObjectGetPropertyData)(kAudioObjectSystemObject, &propAddressDefaultDevice, 0, NULL, &defaultDeviceObjectIDSize, &defaultDeviceObjectID);
24752     if (status == noErr) {
24753         *pDeviceObjectID = defaultDeviceObjectID;
24754         return MA_SUCCESS;
24755     }
24756
24757     /* If we get here it means we couldn't find the device. */
24758     return MA_NO_DEVICE;
24759 }
24760
24761 static ma_result ma_find_AudioObjectID(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, AudioObjectID* pDeviceObjectID)
24762 {
24763     MA_ASSERT(pContext != NULL);
24764     MA_ASSERT(pDeviceObjectID != NULL);
24765
24766     /* Safety. */
24767     *pDeviceObjectID = 0;
24768
24769     if (pDeviceID == NULL) {
24770         /* Default device. */
24771         return ma_find_default_AudioObjectID(pContext, deviceType, pDeviceObjectID);
24772     } else {
24773         /* Explicit device. */
24774         UInt32 deviceCount;
24775         AudioObjectID* pDeviceObjectIDs;
24776         ma_result result;
24777         UInt32 iDevice;
24778
24779         result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs);
24780         if (result != MA_SUCCESS) {
24781             return result;
24782         }
24783
24784         for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
24785             AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice];
24786
24787             char uid[256];
24788             if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(uid), uid) != MA_SUCCESS) {
24789                 continue;
24790             }
24791
24792             if (deviceType == ma_device_type_playback) {
24793                 if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) {
24794                     if (strcmp(uid, pDeviceID->coreaudio) == 0) {
24795                         *pDeviceObjectID = deviceObjectID;
24796                         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
24797                         return MA_SUCCESS;
24798                     }
24799                 }
24800             } else {
24801                 if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) {
24802                     if (strcmp(uid, pDeviceID->coreaudio) == 0) {
24803                         *pDeviceObjectID = deviceObjectID;
24804                         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
24805                         return MA_SUCCESS;
24806                     }
24807                 }
24808             }
24809         }
24810
24811         ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
24812     }
24813
24814     /* If we get here it means we couldn't find the device. */
24815     return MA_NO_DEVICE;
24816 }
24817
24818
24819 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)
24820 {
24821     UInt32 deviceFormatDescriptionCount;
24822     AudioStreamRangedDescription* pDeviceFormatDescriptions;
24823     ma_result result;
24824     ma_uint32 desiredSampleRate;
24825     ma_uint32 desiredChannelCount;
24826     ma_format desiredFormat;
24827     AudioStreamBasicDescription bestDeviceFormatSoFar;
24828     ma_bool32 hasSupportedFormat;
24829     UInt32 iFormat;
24830
24831     result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &deviceFormatDescriptionCount, &pDeviceFormatDescriptions);
24832     if (result != MA_SUCCESS) {
24833         return result;
24834     }
24835
24836     desiredSampleRate = sampleRate;
24837     if (desiredSampleRate == 0) {
24838         desiredSampleRate = pOrigFormat->mSampleRate;
24839     }
24840
24841     desiredChannelCount = channels;
24842     if (desiredChannelCount == 0) {
24843         desiredChannelCount = pOrigFormat->mChannelsPerFrame;
24844     }
24845
24846     desiredFormat = format;
24847     if (desiredFormat == ma_format_unknown) {
24848         result = ma_format_from_AudioStreamBasicDescription(pOrigFormat, &desiredFormat);
24849         if (result != MA_SUCCESS || desiredFormat == ma_format_unknown) {
24850             desiredFormat = g_maFormatPriorities[0];
24851         }
24852     }
24853
24854     /*
24855     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
24856     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.
24857     */
24858     MA_ZERO_OBJECT(&bestDeviceFormatSoFar);
24859
24860     hasSupportedFormat = MA_FALSE;
24861     for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) {
24862         ma_format format;
24863         ma_result formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &format);
24864         if (formatResult == MA_SUCCESS && format != ma_format_unknown) {
24865             hasSupportedFormat = MA_TRUE;
24866             bestDeviceFormatSoFar = pDeviceFormatDescriptions[iFormat].mFormat;
24867             break;
24868         }
24869     }
24870
24871     if (!hasSupportedFormat) {
24872         ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks);
24873         return MA_FORMAT_NOT_SUPPORTED;
24874     }
24875
24876
24877     for (iFormat = 0; iFormat < deviceFormatDescriptionCount; ++iFormat) {
24878         AudioStreamBasicDescription thisDeviceFormat = pDeviceFormatDescriptions[iFormat].mFormat;
24879         ma_format thisSampleFormat;
24880         ma_result formatResult;
24881         ma_format bestSampleFormatSoFar;
24882
24883         /* If the format is not supported by miniaudio we need to skip this one entirely. */
24884         formatResult = ma_format_from_AudioStreamBasicDescription(&pDeviceFormatDescriptions[iFormat].mFormat, &thisSampleFormat);
24885         if (formatResult != MA_SUCCESS || thisSampleFormat == ma_format_unknown) {
24886             continue;   /* The format is not supported by miniaudio. Skip. */
24887         }
24888
24889         ma_format_from_AudioStreamBasicDescription(&bestDeviceFormatSoFar, &bestSampleFormatSoFar);
24890
24891         /* Getting here means the format is supported by miniaudio which makes this format a candidate. */
24892         if (thisDeviceFormat.mSampleRate != desiredSampleRate) {
24893             /*
24894             The sample rate does not match, but this format could still be usable, although it's a very low priority. If the best format
24895             so far has an equal sample rate we can just ignore this one.
24896             */
24897             if (bestDeviceFormatSoFar.mSampleRate == desiredSampleRate) {
24898                 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. */
24899             } else {
24900                 /* In this case, neither the best format so far nor this one have the same sample rate. Check the channel count next. */
24901                 if (thisDeviceFormat.mChannelsPerFrame != desiredChannelCount) {
24902                     /* This format has a different sample rate _and_ a different channel count. */
24903                     if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
24904                         continue;   /* No change to the best format. */
24905                     } else {
24906                         /*
24907                         Both this format and the best so far have different sample rates and different channel counts. Whichever has the
24908                         best format is the new best.
24909                         */
24910                         if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
24911                             bestDeviceFormatSoFar = thisDeviceFormat;
24912                             continue;
24913                         } else {
24914                             continue;   /* No change to the best format. */
24915                         }
24916                     }
24917                 } else {
24918                     /* This format has a different sample rate but the desired channel count. */
24919                     if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
24920                         /* Both this format and the best so far have the desired channel count. Whichever has the best format is the new best. */
24921                         if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
24922                             bestDeviceFormatSoFar = thisDeviceFormat;
24923                             continue;
24924                         } else {
24925                             continue;   /* No change to the best format for now. */
24926                         }
24927                     } else {
24928                         /* This format has the desired channel count, but the best so far does not. We have a new best. */
24929                         bestDeviceFormatSoFar = thisDeviceFormat;
24930                         continue;
24931                     }
24932                 }
24933             }
24934         } else {
24935             /*
24936             The sample rates match which makes this format a very high priority contender. If the best format so far has a different
24937             sample rate it needs to be replaced with this one.
24938             */
24939             if (bestDeviceFormatSoFar.mSampleRate != desiredSampleRate) {
24940                 bestDeviceFormatSoFar = thisDeviceFormat;
24941                 continue;
24942             } else {
24943                 /* In this case both this format and the best format so far have the same sample rate. Check the channel count next. */
24944                 if (thisDeviceFormat.mChannelsPerFrame == desiredChannelCount) {
24945                     /*
24946                     In this case this format has the same channel count as what the client is requesting. If the best format so far has
24947                     a different count, this one becomes the new best.
24948                     */
24949                     if (bestDeviceFormatSoFar.mChannelsPerFrame != desiredChannelCount) {
24950                         bestDeviceFormatSoFar = thisDeviceFormat;
24951                         continue;
24952                     } else {
24953                         /* In this case both this format and the best so far have the ideal sample rate and channel count. Check the format. */
24954                         if (thisSampleFormat == desiredFormat) {
24955                             bestDeviceFormatSoFar = thisDeviceFormat;
24956                             break;  /* Found the exact match. */
24957                         } else {
24958                             /* The formats are different. The new best format is the one with the highest priority format according to miniaudio. */
24959                             if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
24960                                 bestDeviceFormatSoFar = thisDeviceFormat;
24961                                 continue;
24962                             } else {
24963                                 continue;   /* No change to the best format for now. */
24964                             }
24965                         }
24966                     }
24967                 } else {
24968                     /*
24969                     In this case the channel count is different to what the client has requested. If the best so far has the same channel
24970                     count as the requested count then it remains the best.
24971                     */
24972                     if (bestDeviceFormatSoFar.mChannelsPerFrame == desiredChannelCount) {
24973                         continue;
24974                     } else {
24975                         /*
24976                         This is the case where both have the same sample rate (good) but different channel counts. Right now both have about
24977                         the same priority, but we need to compare the format now.
24978                         */
24979                         if (thisSampleFormat == bestSampleFormatSoFar) {
24980                             if (ma_get_format_priority_index(thisSampleFormat) < ma_get_format_priority_index(bestSampleFormatSoFar)) {
24981                                 bestDeviceFormatSoFar = thisDeviceFormat;
24982                                 continue;
24983                             } else {
24984                                 continue;   /* No change to the best format for now. */
24985                             }
24986                         }
24987                     }
24988                 }
24989             }
24990         }
24991     }
24992
24993     *pFormat = bestDeviceFormatSoFar;
24994
24995     ma_free(pDeviceFormatDescriptions, &pContext->allocationCallbacks);
24996     return MA_SUCCESS;
24997 }
24998
24999 static ma_result ma_get_AudioUnit_channel_map(ma_context* pContext, AudioUnit audioUnit, ma_device_type deviceType, ma_channel* pChannelMap, size_t channelMapCap)
25000 {
25001     AudioUnitScope deviceScope;
25002     AudioUnitElement deviceBus;
25003     UInt32 channelLayoutSize;
25004     OSStatus status;
25005     AudioChannelLayout* pChannelLayout;
25006     ma_result result;
25007
25008     MA_ASSERT(pContext != NULL);
25009
25010     if (deviceType == ma_device_type_playback) {
25011         deviceScope = kAudioUnitScope_Input;
25012         deviceBus = MA_COREAUDIO_OUTPUT_BUS;
25013     } else {
25014         deviceScope = kAudioUnitScope_Output;
25015         deviceBus = MA_COREAUDIO_INPUT_BUS;
25016     }
25017
25018     status = ((ma_AudioUnitGetPropertyInfo_proc)pContext->coreaudio.AudioUnitGetPropertyInfo)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, &channelLayoutSize, NULL);
25019     if (status != noErr) {
25020         return ma_result_from_OSStatus(status);
25021     }
25022
25023     pChannelLayout = (AudioChannelLayout*)ma__malloc_from_callbacks(channelLayoutSize, &pContext->allocationCallbacks);
25024     if (pChannelLayout == NULL) {
25025         return MA_OUT_OF_MEMORY;
25026     }
25027
25028     status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_AudioChannelLayout, deviceScope, deviceBus, pChannelLayout, &channelLayoutSize);
25029     if (status != noErr) {
25030         ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
25031         return ma_result_from_OSStatus(status);
25032     }
25033
25034     result = ma_get_channel_map_from_AudioChannelLayout(pChannelLayout, pChannelMap, channelMapCap);
25035     if (result != MA_SUCCESS) {
25036         ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
25037         return result;
25038     }
25039
25040     ma__free_from_callbacks(pChannelLayout, &pContext->allocationCallbacks);
25041     return MA_SUCCESS;
25042 }
25043 #endif /* MA_APPLE_DESKTOP */
25044
25045
25046 #if !defined(MA_APPLE_DESKTOP)
25047 static void ma_AVAudioSessionPortDescription_to_device_info(AVAudioSessionPortDescription* pPortDesc, ma_device_info* pInfo)
25048 {
25049     MA_ZERO_OBJECT(pInfo);
25050     ma_strncpy_s(pInfo->name,         sizeof(pInfo->name),         [pPortDesc.portName UTF8String], (size_t)-1);
25051     ma_strncpy_s(pInfo->id.coreaudio, sizeof(pInfo->id.coreaudio), [pPortDesc.UID      UTF8String], (size_t)-1);
25052 }
25053 #endif
25054
25055 static ma_result ma_context_enumerate_devices__coreaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
25056 {
25057 #if defined(MA_APPLE_DESKTOP)
25058     UInt32 deviceCount;
25059     AudioObjectID* pDeviceObjectIDs;
25060     AudioObjectID defaultDeviceObjectIDPlayback;
25061     AudioObjectID defaultDeviceObjectIDCapture;
25062     ma_result result;
25063     UInt32 iDevice;
25064
25065     ma_find_default_AudioObjectID(pContext, ma_device_type_playback, &defaultDeviceObjectIDPlayback);   /* OK if this fails. */
25066     ma_find_default_AudioObjectID(pContext, ma_device_type_capture,  &defaultDeviceObjectIDCapture);    /* OK if this fails. */
25067
25068     result = ma_get_device_object_ids__coreaudio(pContext, &deviceCount, &pDeviceObjectIDs);
25069     if (result != MA_SUCCESS) {
25070         return result;
25071     }
25072
25073     for (iDevice = 0; iDevice < deviceCount; ++iDevice) {
25074         AudioObjectID deviceObjectID = pDeviceObjectIDs[iDevice];
25075         ma_device_info info;
25076
25077         MA_ZERO_OBJECT(&info);
25078         if (ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(info.id.coreaudio), info.id.coreaudio) != MA_SUCCESS) {
25079             continue;
25080         }
25081         if (ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(info.name), info.name) != MA_SUCCESS) {
25082             continue;
25083         }
25084
25085         if (ma_does_AudioObject_support_playback(pContext, deviceObjectID)) {
25086             if (deviceObjectID == defaultDeviceObjectIDPlayback) {
25087                 info.isDefault = MA_TRUE;
25088             }
25089
25090             if (!callback(pContext, ma_device_type_playback, &info, pUserData)) {
25091                 break;
25092             }
25093         }
25094         if (ma_does_AudioObject_support_capture(pContext, deviceObjectID)) {
25095             if (deviceObjectID == defaultDeviceObjectIDCapture) {
25096                 info.isDefault = MA_TRUE;
25097             }
25098
25099             if (!callback(pContext, ma_device_type_capture, &info, pUserData)) {
25100                 break;
25101             }
25102         }
25103     }
25104
25105     ma_free(pDeviceObjectIDs, &pContext->allocationCallbacks);
25106 #else
25107     ma_device_info info;
25108     NSArray *pInputs  = [[[AVAudioSession sharedInstance] currentRoute] inputs];
25109     NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs];
25110
25111     for (AVAudioSessionPortDescription* pPortDesc in pOutputs) {
25112         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, &info);
25113         if (!callback(pContext, ma_device_type_playback, &info, pUserData)) {
25114             return MA_SUCCESS;
25115         }
25116     }
25117
25118     for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
25119         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, &info);
25120         if (!callback(pContext, ma_device_type_capture, &info, pUserData)) {
25121             return MA_SUCCESS;
25122         }
25123     }
25124 #endif
25125
25126     return MA_SUCCESS;
25127 }
25128
25129 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)
25130 {
25131     ma_result result;
25132
25133     MA_ASSERT(pContext != NULL);
25134
25135 #if defined(MA_APPLE_DESKTOP)
25136     /* Desktop */
25137     {
25138         AudioObjectID deviceObjectID;
25139         AudioObjectID defaultDeviceObjectID;
25140         UInt32 streamDescriptionCount;
25141         AudioStreamRangedDescription* pStreamDescriptions;
25142         UInt32 iStreamDescription;
25143         UInt32 sampleRateRangeCount;
25144         AudioValueRange* pSampleRateRanges;
25145
25146         ma_find_default_AudioObjectID(pContext, deviceType, &defaultDeviceObjectID);     /* OK if this fails. */
25147
25148         result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
25149         if (result != MA_SUCCESS) {
25150             return result;
25151         }
25152
25153         result = ma_get_AudioObject_uid(pContext, deviceObjectID, sizeof(pDeviceInfo->id.coreaudio), pDeviceInfo->id.coreaudio);
25154         if (result != MA_SUCCESS) {
25155             return result;
25156         }
25157
25158         result = ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pDeviceInfo->name), pDeviceInfo->name);
25159         if (result != MA_SUCCESS) {
25160             return result;
25161         }
25162
25163         if (deviceObjectID == defaultDeviceObjectID) {
25164             pDeviceInfo->isDefault = MA_TRUE;
25165         }
25166         
25167         /*
25168         There could be a large number of permutations here. Fortunately there is only a single channel count
25169         being reported which reduces this quite a bit. For sample rates we're only reporting those that are
25170         one of miniaudio's recognized "standard" rates. If there are still more formats than can fit into
25171         our fixed sized array we'll just need to truncate them. This is unlikely and will probably only happen
25172         if some driver performs software data conversion and therefore reports every possible format and
25173         sample rate.
25174         */
25175         pDeviceInfo->nativeDataFormatCount = 0;
25176         
25177         /* Formats. */
25178         {
25179             ma_format uniqueFormats[ma_format_count];
25180             ma_uint32 uniqueFormatCount = 0;
25181             ma_uint32 channels;
25182             
25183             /* Channels. */
25184             result = ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &channels);
25185             if (result != MA_SUCCESS) {
25186                 return result;
25187             }
25188             
25189             /* Formats. */
25190             result = ma_get_AudioObject_stream_descriptions(pContext, deviceObjectID, deviceType, &streamDescriptionCount, &pStreamDescriptions);
25191             if (result != MA_SUCCESS) {
25192                 return result;
25193             }
25194
25195             for (iStreamDescription = 0; iStreamDescription < streamDescriptionCount; ++iStreamDescription) {
25196                 ma_format format;
25197                 ma_bool32 hasFormatBeenHandled = MA_FALSE;
25198                 ma_uint32 iOutputFormat;
25199                 ma_uint32 iSampleRate;
25200
25201                 result = ma_format_from_AudioStreamBasicDescription(&pStreamDescriptions[iStreamDescription].mFormat, &format);
25202                 if (result != MA_SUCCESS) {
25203                     continue;
25204                 }
25205
25206                 MA_ASSERT(format != ma_format_unknown);
25207
25208                 /* Make sure the format isn't already in the output list. */
25209                 for (iOutputFormat = 0; iOutputFormat < uniqueFormatCount; ++iOutputFormat) {
25210                     if (uniqueFormats[iOutputFormat] == format) {
25211                         hasFormatBeenHandled = MA_TRUE;
25212                         break;
25213                     }
25214                 }
25215                 
25216                 /* If we've already handled this format just skip it. */
25217                 if (hasFormatBeenHandled) {
25218                     continue;
25219                 }
25220                 
25221                 uniqueFormatCount += 1;
25222                 
25223
25224                 /* Sample Rates */
25225                 result = ma_get_AudioObject_sample_rates(pContext, deviceObjectID, deviceType, &sampleRateRangeCount, &pSampleRateRanges);
25226                 if (result != MA_SUCCESS) {
25227                     return result;
25228                 }
25229                 
25230                 /*
25231                 Annoyingly Core Audio reports a sample rate range. We just get all the standard rates that are
25232                 between this range.
25233                 */
25234                 for (iSampleRate = 0; iSampleRate < sampleRateRangeCount; ++iSampleRate) {
25235                     ma_uint32 iStandardSampleRate;
25236                     for (iStandardSampleRate = 0; iStandardSampleRate < ma_countof(g_maStandardSampleRatePriorities); iStandardSampleRate += 1) {
25237                         ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iStandardSampleRate];
25238                         if (standardSampleRate >= pSampleRateRanges[iSampleRate].mMinimum && standardSampleRate <= pSampleRateRanges[iSampleRate].mMaximum) {
25239                             /* We have a new data format. Add it to the list. */
25240                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
25241                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
25242                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = standardSampleRate;
25243                             pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
25244                             pDeviceInfo->nativeDataFormatCount += 1;
25245                             
25246                             if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) {
25247                                 break;  /* No more room for any more formats. */
25248                             }
25249                         }
25250                     }
25251                 }
25252                 
25253                 ma_free(pSampleRateRanges, &pContext->allocationCallbacks);
25254
25255                 if (pDeviceInfo->nativeDataFormatCount >= ma_countof(pDeviceInfo->nativeDataFormats)) {
25256                     break;  /* No more room for any more formats. */
25257                 }
25258             }
25259
25260             ma_free(pStreamDescriptions, &pContext->allocationCallbacks);
25261         }
25262     }
25263 #else
25264     /* Mobile */
25265     {
25266         AudioComponentDescription desc;
25267         AudioComponent component;
25268         AudioUnit audioUnit;
25269         OSStatus status;
25270         AudioUnitScope formatScope;
25271         AudioUnitElement formatElement;
25272         AudioStreamBasicDescription bestFormat;
25273         UInt32 propSize;
25274
25275         /* We want to ensure we use a consistent device name to device enumeration. */
25276         if (pDeviceID != NULL) {
25277             ma_bool32 found = MA_FALSE;
25278             if (deviceType == ma_device_type_playback) {
25279                 NSArray *pOutputs = [[[AVAudioSession sharedInstance] currentRoute] outputs];
25280                 for (AVAudioSessionPortDescription* pPortDesc in pOutputs) {
25281                     if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
25282                         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo);
25283                         found = MA_TRUE;
25284                         break;
25285                     }
25286                 }
25287             } else {
25288                 NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
25289                 for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
25290                     if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
25291                         ma_AVAudioSessionPortDescription_to_device_info(pPortDesc, pDeviceInfo);
25292                         found = MA_TRUE;
25293                         break;
25294                     }
25295                 }
25296             }
25297
25298             if (!found) {
25299                 return MA_DOES_NOT_EXIST;
25300             }
25301         } else {
25302             if (deviceType == ma_device_type_playback) {
25303                 ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
25304             } else {
25305                 ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
25306             }
25307         }
25308
25309
25310         /*
25311         Retrieving device information is more annoying on mobile than desktop. For simplicity I'm locking this down to whatever format is
25312         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
25313         retrieve from the AVAudioSession shared instance.
25314         */
25315         desc.componentType = kAudioUnitType_Output;
25316         desc.componentSubType = kAudioUnitSubType_RemoteIO;
25317         desc.componentManufacturer = kAudioUnitManufacturer_Apple;
25318         desc.componentFlags = 0;
25319         desc.componentFlagsMask = 0;
25320
25321         component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
25322         if (component == NULL) {
25323             return MA_FAILED_TO_INIT_BACKEND;
25324         }
25325
25326         status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(component, &audioUnit);
25327         if (status != noErr) {
25328             return ma_result_from_OSStatus(status);
25329         }
25330
25331         formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
25332         formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
25333
25334         propSize = sizeof(bestFormat);
25335         status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize);
25336         if (status != noErr) {
25337             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
25338             return ma_result_from_OSStatus(status);
25339         }
25340
25341         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
25342         audioUnit = NULL;
25343
25344         /* Only a single format is being reported for iOS. */
25345         pDeviceInfo->nativeDataFormatCount = 1;
25346         
25347         result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->nativeDataFormats[0].format);
25348         if (result != MA_SUCCESS) {
25349             return result;
25350         }
25351         
25352         pDeviceInfo->nativeDataFormats[0].channels = bestFormat.mChannelsPerFrame;
25353
25354         /*
25355         It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do
25356         this we just get the shared instance and inspect.
25357         */
25358         @autoreleasepool {
25359             AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
25360             MA_ASSERT(pAudioSession != NULL);
25361
25362             pDeviceInfo->nativeDataFormats[0].sampleRate = (ma_uint32)pAudioSession.sampleRate;
25363         }
25364     }
25365 #endif
25366
25367     (void)pDeviceInfo; /* Unused. */
25368     return MA_SUCCESS;
25369 }
25370
25371 static AudioBufferList* ma_allocate_AudioBufferList__coreaudio(ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout, const ma_allocation_callbacks* pAllocationCallbacks)
25372 {
25373     AudioBufferList* pBufferList;
25374     UInt32 audioBufferSizeInBytes;
25375     size_t allocationSize;
25376
25377     MA_ASSERT(sizeInFrames > 0);
25378     MA_ASSERT(format != ma_format_unknown);
25379     MA_ASSERT(channels > 0);
25380
25381     allocationSize = sizeof(AudioBufferList) - sizeof(AudioBuffer);  /* Subtract sizeof(AudioBuffer) because that part is dynamically sized. */
25382     if (layout == ma_stream_layout_interleaved) {
25383         /* Interleaved case. This is the simple case because we just have one buffer. */
25384         allocationSize += sizeof(AudioBuffer) * 1;
25385     } else {
25386         /* Non-interleaved case. This is the more complex case because there's more than one buffer. */
25387         allocationSize += sizeof(AudioBuffer) * channels;
25388     }
25389
25390     allocationSize += sizeInFrames * ma_get_bytes_per_frame(format, channels);
25391
25392     pBufferList = (AudioBufferList*)ma__malloc_from_callbacks(allocationSize, pAllocationCallbacks);
25393     if (pBufferList == NULL) {
25394         return NULL;
25395     }
25396
25397     audioBufferSizeInBytes = (UInt32)(sizeInFrames * ma_get_bytes_per_sample(format));
25398
25399     if (layout == ma_stream_layout_interleaved) {
25400         pBufferList->mNumberBuffers = 1;
25401         pBufferList->mBuffers[0].mNumberChannels = channels;
25402         pBufferList->mBuffers[0].mDataByteSize   = audioBufferSizeInBytes * channels;
25403         pBufferList->mBuffers[0].mData           = (ma_uint8*)pBufferList + sizeof(AudioBufferList);
25404     } else {
25405         ma_uint32 iBuffer;
25406         pBufferList->mNumberBuffers = channels;
25407         for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
25408             pBufferList->mBuffers[iBuffer].mNumberChannels = 1;
25409             pBufferList->mBuffers[iBuffer].mDataByteSize   = audioBufferSizeInBytes;
25410             pBufferList->mBuffers[iBuffer].mData           = (ma_uint8*)pBufferList + ((sizeof(AudioBufferList) - sizeof(AudioBuffer)) + (sizeof(AudioBuffer) * channels)) + (audioBufferSizeInBytes * iBuffer);
25411         }
25412     }
25413
25414     return pBufferList;
25415 }
25416
25417 static ma_result ma_device_realloc_AudioBufferList__coreaudio(ma_device* pDevice, ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout)
25418 {
25419     MA_ASSERT(pDevice != NULL);
25420     MA_ASSERT(format != ma_format_unknown);
25421     MA_ASSERT(channels > 0);
25422
25423     /* Only resize the buffer if necessary. */
25424     if (pDevice->coreaudio.audioBufferCapInFrames < sizeInFrames) {
25425         AudioBufferList* pNewAudioBufferList;
25426
25427         pNewAudioBufferList = ma_allocate_AudioBufferList__coreaudio(sizeInFrames, format, channels, layout, &pDevice->pContext->allocationCallbacks);
25428         if (pNewAudioBufferList != NULL) {
25429             return MA_OUT_OF_MEMORY;
25430         }
25431
25432         /* At this point we'll have a new AudioBufferList and we can free the old one. */
25433         ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
25434         pDevice->coreaudio.pAudioBufferList = pNewAudioBufferList;
25435         pDevice->coreaudio.audioBufferCapInFrames = sizeInFrames;
25436     }
25437
25438     /* Getting here means the capacity of the audio is fine. */
25439     return MA_SUCCESS;
25440 }
25441
25442
25443 static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pBufferList)
25444 {
25445     ma_device* pDevice = (ma_device*)pUserData;
25446     ma_stream_layout layout;
25447
25448     MA_ASSERT(pDevice != NULL);
25449
25450 #if defined(MA_DEBUG_OUTPUT)
25451     printf("INFO: Output Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pBufferList->mNumberBuffers);
25452 #endif
25453
25454     /* 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. */
25455     layout = ma_stream_layout_interleaved;
25456     if (pBufferList->mBuffers[0].mNumberChannels != pDevice->playback.internalChannels) {
25457         layout = ma_stream_layout_deinterleaved;
25458     }
25459
25460     if (layout == ma_stream_layout_interleaved) {
25461         /* For now we can assume everything is interleaved. */
25462         UInt32 iBuffer;
25463         for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
25464             if (pBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->playback.internalChannels) {
25465                 ma_uint32 frameCountForThisBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
25466                 if (frameCountForThisBuffer > 0) {
25467                     ma_device_handle_backend_data_callback(pDevice, pBufferList->mBuffers[iBuffer].mData, NULL, frameCountForThisBuffer);
25468                 }
25469
25470             #if defined(MA_DEBUG_OUTPUT)
25471                 printf("  frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize);
25472             #endif
25473             } else {
25474                 /*
25475                 This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
25476                 not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams. We just
25477                 output silence here.
25478                 */
25479                 MA_ZERO_MEMORY(pBufferList->mBuffers[iBuffer].mData, pBufferList->mBuffers[iBuffer].mDataByteSize);
25480
25481             #if defined(MA_DEBUG_OUTPUT)
25482                 printf("  WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pBufferList->mBuffers[iBuffer].mNumberChannels, pBufferList->mBuffers[iBuffer].mDataByteSize);
25483             #endif
25484             }
25485         }
25486     } else {
25487         /* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */
25488         MA_ASSERT(pDevice->playback.internalChannels <= MA_MAX_CHANNELS);   /* This should heve been validated at initialization time. */
25489
25490         /*
25491         For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
25492         very strange has happened and we're not going to support it.
25493         */
25494         if ((pBufferList->mNumberBuffers % pDevice->playback.internalChannels) == 0) {
25495             ma_uint8 tempBuffer[4096];
25496             UInt32 iBuffer;
25497
25498             for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; iBuffer += pDevice->playback.internalChannels) {
25499                 ma_uint32 frameCountPerBuffer = pBufferList->mBuffers[iBuffer].mDataByteSize / ma_get_bytes_per_sample(pDevice->playback.internalFormat);
25500                 ma_uint32 framesRemaining = frameCountPerBuffer;
25501
25502                 while (framesRemaining > 0) {
25503                     void* ppDeinterleavedBuffers[MA_MAX_CHANNELS];
25504                     ma_uint32 iChannel;
25505                     ma_uint32 framesToRead = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
25506                     if (framesToRead > framesRemaining) {
25507                         framesToRead = framesRemaining;
25508                     }
25509                     
25510                     ma_device_handle_backend_data_callback(pDevice, tempBuffer, NULL, framesToRead);
25511
25512                     for (iChannel = 0; iChannel < pDevice->playback.internalChannels; ++iChannel) {
25513                         ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pBufferList->mBuffers[iBuffer+iChannel].mData, (frameCountPerBuffer - framesRemaining) * ma_get_bytes_per_sample(pDevice->playback.internalFormat));
25514                     }
25515
25516                     ma_deinterleave_pcm_frames(pDevice->playback.internalFormat, pDevice->playback.internalChannels, framesToRead, tempBuffer, ppDeinterleavedBuffers);
25517
25518                     framesRemaining -= framesToRead;
25519                 }
25520             }
25521         }
25522     }
25523
25524     (void)pActionFlags;
25525     (void)pTimeStamp;
25526     (void)busNumber;
25527     (void)frameCount;
25528
25529     return noErr;
25530 }
25531
25532 static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFlags* pActionFlags, const AudioTimeStamp* pTimeStamp, UInt32 busNumber, UInt32 frameCount, AudioBufferList* pUnusedBufferList)
25533 {
25534     ma_device* pDevice = (ma_device*)pUserData;
25535     AudioBufferList* pRenderedBufferList;
25536     ma_result result;
25537     ma_stream_layout layout;
25538     ma_uint32 iBuffer;
25539     OSStatus status;
25540
25541     MA_ASSERT(pDevice != NULL);
25542
25543     pRenderedBufferList = (AudioBufferList*)pDevice->coreaudio.pAudioBufferList;
25544     MA_ASSERT(pRenderedBufferList);
25545
25546     /* 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. */
25547     layout = ma_stream_layout_interleaved;
25548     if (pRenderedBufferList->mBuffers[0].mNumberChannels != pDevice->capture.internalChannels) {
25549         layout = ma_stream_layout_deinterleaved;
25550     }
25551
25552 #if defined(MA_DEBUG_OUTPUT)
25553     printf("INFO: Input Callback: busNumber=%d, frameCount=%d, mNumberBuffers=%d\n", busNumber, frameCount, pRenderedBufferList->mNumberBuffers);
25554 #endif
25555
25556     /*
25557     There has been a situation reported where frame count passed into this function is greater than the capacity of
25558     our capture buffer. There doesn't seem to be a reliable way to determine what the maximum frame count will be,
25559     so we need to instead resort to dynamically reallocating our buffer to ensure it's large enough to capture the
25560     number of frames requested by this callback.
25561     */
25562     result = ma_device_realloc_AudioBufferList__coreaudio(pDevice, frameCount, pDevice->capture.internalFormat, pDevice->capture.internalChannels, layout);
25563     if (result != MA_SUCCESS) {
25564     #if defined(MA_DEBUG_OUTPUT)
25565         printf("Failed to allocate AudioBufferList for capture.");
25566     #endif
25567         return noErr;
25568     }
25569
25570     /*
25571     When you call AudioUnitRender(), Core Audio tries to be helpful by setting the mDataByteSize to the number of bytes
25572     that were actually rendered. The problem with this is that the next call can fail with -50 due to the size no longer
25573     being set to the capacity of the buffer, but instead the size in bytes of the previous render. This will cause a
25574     problem when a future call to this callback specifies a larger number of frames.
25575
25576     To work around this we need to explicitly set the size of each buffer to their respective size in bytes.
25577     */
25578     for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
25579         pRenderedBufferList->mBuffers[iBuffer].mDataByteSize = pDevice->coreaudio.audioBufferCapInFrames * ma_get_bytes_per_sample(pDevice->capture.internalFormat) * pRenderedBufferList->mBuffers[iBuffer].mNumberChannels;
25580     }
25581
25582     status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList);
25583     if (status != noErr) {
25584     #if defined(MA_DEBUG_OUTPUT)
25585         printf("  ERROR: AudioUnitRender() failed with %d\n", status);
25586     #endif
25587         return status;
25588     }
25589
25590     if (layout == ma_stream_layout_interleaved) {
25591         for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) {
25592             if (pRenderedBufferList->mBuffers[iBuffer].mNumberChannels == pDevice->capture.internalChannels) {
25593                 ma_device_handle_backend_data_callback(pDevice, NULL, pRenderedBufferList->mBuffers[iBuffer].mData, frameCount);
25594
25595             #if defined(MA_DEBUG_OUTPUT)
25596                 printf("  mDataByteSize=%d\n", pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
25597             #endif
25598             } else {
25599                 /*
25600                 This case is where the number of channels in the output buffer do not match our internal channels. It could mean that it's
25601                 not interleaved, in which case we can't handle right now since miniaudio does not yet support non-interleaved streams.
25602                 */
25603                 ma_uint8 silentBuffer[4096];
25604                 ma_uint32 framesRemaining;
25605
25606                 MA_ZERO_MEMORY(silentBuffer, sizeof(silentBuffer));
25607
25608                 framesRemaining = frameCount;
25609                 while (framesRemaining > 0) {
25610                     ma_uint32 framesToSend = sizeof(silentBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
25611                     if (framesToSend > framesRemaining) {
25612                         framesToSend = framesRemaining;
25613                     }
25614                     
25615                     ma_device_handle_backend_data_callback(pDevice, NULL, silentBuffer, framesToSend);
25616
25617                     framesRemaining -= framesToSend;
25618                 }
25619
25620             #if defined(MA_DEBUG_OUTPUT)
25621                 printf("  WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", frameCount, pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);
25622             #endif
25623             }
25624         }
25625     } else {
25626         /* 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. */
25627         MA_ASSERT(pDevice->capture.internalChannels <= MA_MAX_CHANNELS);    /* This should have been validated at initialization time. */
25628
25629         /*
25630         For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
25631         very strange has happened and we're not going to support it.
25632         */
25633         if ((pRenderedBufferList->mNumberBuffers % pDevice->capture.internalChannels) == 0) {
25634             ma_uint8 tempBuffer[4096];
25635             for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; iBuffer += pDevice->capture.internalChannels) {
25636                 ma_uint32 framesRemaining = frameCount;
25637                 while (framesRemaining > 0) {
25638                     void* ppDeinterleavedBuffers[MA_MAX_CHANNELS];
25639                     ma_uint32 iChannel;
25640                     ma_uint32 framesToSend = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
25641                     if (framesToSend > framesRemaining) {
25642                         framesToSend = framesRemaining;
25643                     }
25644
25645                     for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
25646                         ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pRenderedBufferList->mBuffers[iBuffer+iChannel].mData, (frameCount - framesRemaining) * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
25647                     }
25648
25649                     ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer);
25650                     ma_device_handle_backend_data_callback(pDevice, NULL, tempBuffer, framesToSend);
25651
25652                     framesRemaining -= framesToSend;
25653                 }
25654             }
25655         }
25656     }
25657
25658     (void)pActionFlags;
25659     (void)pTimeStamp;
25660     (void)busNumber;
25661     (void)frameCount;
25662     (void)pUnusedBufferList;
25663
25664     return noErr;
25665 }
25666
25667 static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element)
25668 {
25669     ma_device* pDevice = (ma_device*)pUserData;
25670     MA_ASSERT(pDevice != NULL);
25671
25672     /*
25673     There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like
25674     AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit)
25675     can try waiting on the same lock. I'm going to try working around this by not calling any Core
25676     Audio APIs in the callback when the device has been stopped or uninitialized.
25677     */
25678     if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED || ma_device_get_state(pDevice) == MA_STATE_STOPPING || ma_device_get_state(pDevice) == MA_STATE_STOPPED) {
25679         ma_stop_proc onStop = pDevice->onStop;
25680         if (onStop) {
25681             onStop(pDevice);
25682         }
25683
25684         ma_event_signal(&pDevice->coreaudio.stopEvent);
25685     } else {
25686         UInt32 isRunning;
25687         UInt32 isRunningSize = sizeof(isRunning);
25688         OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize);
25689         if (status != noErr) {
25690             return; /* Don't really know what to do in this case... just ignore it, I suppose... */
25691         }
25692
25693         if (!isRunning) {
25694             ma_stop_proc onStop;
25695
25696             /*
25697             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:
25698
25699             1) When the device is unplugged, this will be called _before_ the default device change notification.
25700             2) When the device is changed via the default device change notification, this will be called _after_ the switch.
25701
25702             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.
25703             */
25704             if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) ||
25705                 ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isDefaultCaptureDevice)) {
25706                 /*
25707                 It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
25708                 via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
25709                 device to be seamless to the client (we don't want them receiving the onStop event and thinking that the device has stopped when it
25710                 hasn't!).
25711                 */
25712                 if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
25713                     ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
25714                     return;
25715                 }
25716
25717                 /*
25718                 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
25719                 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
25720                 likely be successful in switching to the new device.
25721
25722                 TODO: Try to predict if Core Audio will switch devices. If not, the onStop callback needs to be posted.
25723                 */
25724                 return;
25725             }
25726
25727             /* Getting here means we need to stop the device. */
25728             onStop = pDevice->onStop;
25729             if (onStop) {
25730                 onStop(pDevice);
25731             }
25732         }
25733     }
25734
25735     (void)propertyID; /* Unused. */
25736 }
25737
25738 #if defined(MA_APPLE_DESKTOP)
25739 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. */
25740 static ma_uint32   g_DeviceTrackingInitCounter_CoreAudio = 0;
25741 static ma_mutex    g_DeviceTrackingMutex_CoreAudio;
25742 static ma_device** g_ppTrackedDevices_CoreAudio = NULL;
25743 static ma_uint32   g_TrackedDeviceCap_CoreAudio = 0;
25744 static ma_uint32   g_TrackedDeviceCount_CoreAudio = 0;
25745
25746 static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UInt32 addressCount, const AudioObjectPropertyAddress* pAddresses, void* pUserData)
25747 {
25748     ma_device_type deviceType;
25749
25750     /* Not sure if I really need to check this, but it makes me feel better. */
25751     if (addressCount == 0) {
25752         return noErr;
25753     }
25754
25755     if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultOutputDevice) {
25756         deviceType = ma_device_type_playback;
25757     } else if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultInputDevice) {
25758         deviceType = ma_device_type_capture;
25759     } else {
25760         return noErr;   /* Should never hit this. */
25761     }
25762
25763     ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
25764     {
25765         ma_uint32 iDevice;
25766         for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
25767             ma_result reinitResult;
25768             ma_device* pDevice;
25769
25770             pDevice = g_ppTrackedDevices_CoreAudio[iDevice];
25771             if (pDevice->type == deviceType || pDevice->type == ma_device_type_duplex) {
25772                 if (deviceType == ma_device_type_playback) {
25773                     pDevice->coreaudio.isSwitchingPlaybackDevice = MA_TRUE;
25774                     reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE);
25775                     pDevice->coreaudio.isSwitchingPlaybackDevice = MA_FALSE;
25776                 } else {
25777                     pDevice->coreaudio.isSwitchingCaptureDevice = MA_TRUE;
25778                     reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE);
25779                     pDevice->coreaudio.isSwitchingCaptureDevice = MA_FALSE;
25780                 }
25781
25782                 if (reinitResult == MA_SUCCESS) {
25783                     ma_device__post_init_setup(pDevice, deviceType);
25784
25785                     /* Restart the device if required. If this fails we need to stop the device entirely. */
25786                     if (ma_device_get_state(pDevice) == MA_STATE_STARTED) {
25787                         OSStatus status;
25788                         if (deviceType == ma_device_type_playback) {
25789                             status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
25790                             if (status != noErr) {
25791                                 if (pDevice->type == ma_device_type_duplex) {
25792                                     ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
25793                                 }
25794                                 ma_device__set_state(pDevice, MA_STATE_STOPPED);
25795                             }
25796                         } else if (deviceType == ma_device_type_capture) {
25797                             status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
25798                             if (status != noErr) {
25799                                 if (pDevice->type == ma_device_type_duplex) {
25800                                     ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
25801                                 }
25802                                 ma_device__set_state(pDevice, MA_STATE_STOPPED);
25803                             }
25804                         }
25805                     }
25806                 }
25807             }
25808         }
25809     }
25810     ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
25811
25812     /* Unused parameters. */
25813     (void)objectID;
25814     (void)pUserData;
25815
25816     return noErr;
25817 }
25818
25819 static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContext)
25820 {
25821     MA_ASSERT(pContext != NULL);
25822
25823     ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
25824     {
25825         /* Don't do anything if we've already initializd device tracking. */
25826         if (g_DeviceTrackingInitCounter_CoreAudio == 0) {
25827             AudioObjectPropertyAddress propAddress;
25828             propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
25829             propAddress.mElement  = kAudioObjectPropertyElementMaster;
25830
25831             ma_mutex_init(&g_DeviceTrackingMutex_CoreAudio);
25832
25833             propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
25834             ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
25835
25836             propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
25837             ((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
25838
25839             g_DeviceTrackingInitCounter_CoreAudio += 1;
25840         }
25841     }
25842     ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
25843
25844     return MA_SUCCESS;
25845 }
25846
25847 static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pContext)
25848 {
25849     MA_ASSERT(pContext != NULL);
25850
25851     ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
25852     {
25853         g_DeviceTrackingInitCounter_CoreAudio -= 1;
25854
25855         if (g_DeviceTrackingInitCounter_CoreAudio == 0) {
25856             AudioObjectPropertyAddress propAddress;
25857             propAddress.mScope    = kAudioObjectPropertyScopeGlobal;
25858             propAddress.mElement  = kAudioObjectPropertyElementMaster;
25859
25860             propAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
25861             ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
25862
25863             propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
25864             ((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
25865
25866             /* At this point there should be no tracked devices. If not there's an error somewhere. */
25867             if (g_ppTrackedDevices_CoreAudio != NULL) {
25868                 ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active.", MA_INVALID_OPERATION);
25869             }
25870
25871             ma_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio);
25872         }
25873     }
25874     ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
25875
25876     return MA_SUCCESS;
25877 }
25878
25879 static ma_result ma_device__track__coreaudio(ma_device* pDevice)
25880 {
25881     MA_ASSERT(pDevice != NULL);
25882
25883     ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
25884     {
25885         /* Allocate memory if required. */
25886         if (g_TrackedDeviceCap_CoreAudio <= g_TrackedDeviceCount_CoreAudio) {
25887             ma_uint32 oldCap;
25888             ma_uint32 newCap;
25889             ma_device** ppNewDevices;
25890
25891             oldCap = g_TrackedDeviceCap_CoreAudio;
25892             newCap = g_TrackedDeviceCap_CoreAudio * 2;
25893             if (newCap == 0) {
25894                 newCap = 1;
25895             }
25896
25897             ppNewDevices = (ma_device**)ma__realloc_from_callbacks(g_ppTrackedDevices_CoreAudio, sizeof(*g_ppTrackedDevices_CoreAudio)*newCap, sizeof(*g_ppTrackedDevices_CoreAudio)*oldCap, &pDevice->pContext->allocationCallbacks);
25898             if (ppNewDevices == NULL) {
25899                 ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
25900                 return MA_OUT_OF_MEMORY;
25901             }
25902
25903             g_ppTrackedDevices_CoreAudio = ppNewDevices;
25904             g_TrackedDeviceCap_CoreAudio = newCap;
25905         }
25906
25907         g_ppTrackedDevices_CoreAudio[g_TrackedDeviceCount_CoreAudio] = pDevice;
25908         g_TrackedDeviceCount_CoreAudio += 1;
25909     }
25910     ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
25911
25912     return MA_SUCCESS;
25913 }
25914
25915 static ma_result ma_device__untrack__coreaudio(ma_device* pDevice)
25916 {
25917     MA_ASSERT(pDevice != NULL);
25918
25919     ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
25920     {
25921         ma_uint32 iDevice;
25922         for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
25923             if (g_ppTrackedDevices_CoreAudio[iDevice] == pDevice) {
25924                 /* We've found the device. We now need to remove it from the list. */
25925                 ma_uint32 jDevice;
25926                 for (jDevice = iDevice; jDevice < g_TrackedDeviceCount_CoreAudio-1; jDevice += 1) {
25927                     g_ppTrackedDevices_CoreAudio[jDevice] = g_ppTrackedDevices_CoreAudio[jDevice+1];
25928                 }
25929
25930                 g_TrackedDeviceCount_CoreAudio -= 1;
25931
25932                 /* If there's nothing else in the list we need to free memory. */
25933                 if (g_TrackedDeviceCount_CoreAudio == 0) {
25934                     ma__free_from_callbacks(g_ppTrackedDevices_CoreAudio, &pDevice->pContext->allocationCallbacks);
25935                     g_ppTrackedDevices_CoreAudio = NULL;
25936                     g_TrackedDeviceCap_CoreAudio = 0;
25937                 }
25938
25939                 break;
25940             }
25941         }
25942     }
25943     ma_mutex_unlock(&g_DeviceTrackingMutex_CoreAudio);
25944
25945     return MA_SUCCESS;
25946 }
25947 #endif
25948
25949 #if defined(MA_APPLE_MOBILE)
25950 @interface ma_router_change_handler:NSObject {
25951     ma_device* m_pDevice;
25952 }
25953 @end
25954
25955 @implementation ma_router_change_handler
25956 -(id)init:(ma_device*)pDevice
25957 {
25958     self = [super init];
25959     m_pDevice = pDevice;
25960
25961     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handle_route_change:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
25962
25963     return self;
25964 }
25965
25966 -(void)dealloc
25967 {
25968     [self remove_handler];
25969 }
25970
25971 -(void)remove_handler
25972 {
25973     [[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
25974 }
25975
25976 -(void)handle_route_change:(NSNotification*)pNotification
25977 {
25978     AVAudioSession* pSession = [AVAudioSession sharedInstance];
25979
25980     NSInteger reason = [[[pNotification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
25981     switch (reason)
25982     {
25983         case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
25984         {
25985         #if defined(MA_DEBUG_OUTPUT)
25986             printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOldDeviceUnavailable\n");
25987         #endif
25988         } break;
25989
25990         case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
25991         {
25992         #if defined(MA_DEBUG_OUTPUT)
25993             printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNewDeviceAvailable\n");
25994         #endif
25995         } break;
25996
25997         case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
25998         {
25999         #if defined(MA_DEBUG_OUTPUT)
26000             printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory\n");
26001         #endif
26002         } break;
26003
26004         case AVAudioSessionRouteChangeReasonWakeFromSleep:
26005         {
26006         #if defined(MA_DEBUG_OUTPUT)
26007             printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonWakeFromSleep\n");
26008         #endif
26009         } break;
26010
26011         case AVAudioSessionRouteChangeReasonOverride:
26012         {
26013         #if defined(MA_DEBUG_OUTPUT)
26014             printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonOverride\n");
26015         #endif
26016         } break;
26017
26018         case AVAudioSessionRouteChangeReasonCategoryChange:
26019         {
26020         #if defined(MA_DEBUG_OUTPUT)
26021             printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonCategoryChange\n");
26022         #endif
26023         } break;
26024
26025         case AVAudioSessionRouteChangeReasonUnknown:
26026         default:
26027         {
26028         #if defined(MA_DEBUG_OUTPUT)
26029             printf("[Core Audio] Route Changed: AVAudioSessionRouteChangeReasonUnknown\n");
26030         #endif
26031         } break;
26032     }
26033
26034 #if defined(MA_DEBUG_OUTPUT)
26035     printf("[Core Audio] Changing Route. inputNumberChannels=%d; outputNumberOfChannels=%d\n", (int)pSession.inputNumberOfChannels, (int)pSession.outputNumberOfChannels);
26036 #endif
26037
26038     ma_uint32 previousState = ma_device_get_state(m_pDevice);
26039
26040     if (previousState == MA_STATE_STARTED) {
26041         ma_device_stop(m_pDevice);
26042     }
26043
26044     if (m_pDevice->type == ma_device_type_capture || m_pDevice->type == ma_device_type_duplex) {
26045         m_pDevice->capture.internalChannels   = (ma_uint32)pSession.inputNumberOfChannels;
26046         m_pDevice->capture.internalSampleRate = (ma_uint32)pSession.sampleRate;
26047         ma_device__post_init_setup(m_pDevice, ma_device_type_capture);
26048     }
26049     if (m_pDevice->type == ma_device_type_playback || m_pDevice->type == ma_device_type_duplex) {
26050         m_pDevice->playback.internalChannels   = (ma_uint32)pSession.outputNumberOfChannels;
26051         m_pDevice->playback.internalSampleRate = (ma_uint32)pSession.sampleRate;
26052         ma_device__post_init_setup(m_pDevice, ma_device_type_playback);
26053     }
26054
26055     if (previousState == MA_STATE_STARTED) {
26056         ma_device_start(m_pDevice);
26057     }
26058 }
26059 @end
26060 #endif
26061
26062 static ma_result ma_device_uninit__coreaudio(ma_device* pDevice)
26063 {
26064     MA_ASSERT(pDevice != NULL);
26065     MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED);
26066
26067 #if defined(MA_APPLE_DESKTOP)
26068     /*
26069     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
26070     just gracefully ignore it.
26071     */
26072     ma_device__untrack__coreaudio(pDevice);
26073 #endif
26074 #if defined(MA_APPLE_MOBILE)
26075     if (pDevice->coreaudio.pRouteChangeHandler != NULL) {
26076         ma_router_change_handler* pRouteChangeHandler = (__bridge_transfer ma_router_change_handler*)pDevice->coreaudio.pRouteChangeHandler;
26077         [pRouteChangeHandler remove_handler];
26078     }
26079 #endif
26080
26081     if (pDevice->coreaudio.audioUnitCapture != NULL) {
26082         ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
26083     }
26084     if (pDevice->coreaudio.audioUnitPlayback != NULL) {
26085         ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
26086     }
26087
26088     if (pDevice->coreaudio.pAudioBufferList) {
26089         ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
26090     }
26091
26092     return MA_SUCCESS;
26093 }
26094
26095 typedef struct
26096 {
26097     ma_bool32 allowNominalSampleRateChange;
26098
26099     /* Input. */
26100     ma_format formatIn;
26101     ma_uint32 channelsIn;
26102     ma_uint32 sampleRateIn;
26103     ma_channel channelMapIn[MA_MAX_CHANNELS];
26104     ma_uint32 periodSizeInFramesIn;
26105     ma_uint32 periodSizeInMillisecondsIn;
26106     ma_uint32 periodsIn;
26107     ma_share_mode shareMode;
26108     ma_performance_profile performanceProfile;
26109     ma_bool32 registerStopEvent;
26110
26111     /* Output. */
26112 #if defined(MA_APPLE_DESKTOP)
26113     AudioObjectID deviceObjectID;
26114 #endif
26115     AudioComponent component;
26116     AudioUnit audioUnit;
26117     AudioBufferList* pAudioBufferList;  /* Only used for input devices. */
26118     ma_format formatOut;
26119     ma_uint32 channelsOut;
26120     ma_uint32 sampleRateOut;
26121     ma_channel channelMapOut[MA_MAX_CHANNELS];
26122     ma_uint32 periodSizeInFramesOut;
26123     ma_uint32 periodsOut;
26124     char deviceName[256];
26125 } ma_device_init_internal_data__coreaudio;
26126
26127 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. */
26128 {
26129     ma_result result;
26130     OSStatus status;
26131     UInt32 enableIOFlag;
26132     AudioStreamBasicDescription bestFormat;
26133     UInt32 actualPeriodSizeInFrames;
26134     AURenderCallbackStruct callbackInfo;
26135 #if defined(MA_APPLE_DESKTOP)
26136     AudioObjectID deviceObjectID;
26137 #else
26138     UInt32 actualPeriodSizeInFramesSize = sizeof(actualPeriodSizeInFrames);
26139 #endif
26140
26141     /* This API should only be used for a single device type: playback or capture. No full-duplex mode. */
26142     if (deviceType == ma_device_type_duplex) {
26143         return MA_INVALID_ARGS;
26144     }
26145
26146     MA_ASSERT(pContext != NULL);
26147     MA_ASSERT(deviceType == ma_device_type_playback || deviceType == ma_device_type_capture);
26148
26149 #if defined(MA_APPLE_DESKTOP)
26150     pData->deviceObjectID = 0;
26151 #endif
26152     pData->component = NULL;
26153     pData->audioUnit = NULL;
26154     pData->pAudioBufferList = NULL;
26155
26156 #if defined(MA_APPLE_DESKTOP)
26157     result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
26158     if (result != MA_SUCCESS) {
26159         return result;
26160     }
26161
26162     pData->deviceObjectID = deviceObjectID;
26163 #endif
26164
26165     /* Core audio doesn't really use the notion of a period so we can leave this unmodified, but not too over the top. */
26166     pData->periodsOut = pData->periodsIn;
26167     if (pData->periodsOut == 0) {
26168         pData->periodsOut = MA_DEFAULT_PERIODS;
26169     }
26170     if (pData->periodsOut > 16) {
26171         pData->periodsOut = 16;
26172     }
26173
26174
26175     /* Audio unit. */
26176     status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pContext->coreaudio.component, (AudioUnit*)&pData->audioUnit);
26177     if (status != noErr) {
26178         return ma_result_from_OSStatus(status);
26179     }
26180
26181
26182     /* 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. */
26183     enableIOFlag = 1;
26184     if (deviceType == ma_device_type_capture) {
26185         enableIOFlag = 0;
26186     }
26187
26188     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
26189     if (status != noErr) {
26190         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26191         return ma_result_from_OSStatus(status);
26192     }
26193
26194     enableIOFlag = (enableIOFlag == 0) ? 1 : 0;
26195     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
26196     if (status != noErr) {
26197         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26198         return ma_result_from_OSStatus(status);
26199     }
26200
26201
26202     /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */
26203 #if defined(MA_APPLE_DESKTOP)
26204     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceObjectID, sizeof(deviceObjectID));
26205     if (status != noErr) {
26206         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26207         return ma_result_from_OSStatus(result);
26208     }
26209 #else
26210     /*
26211     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
26212     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.
26213     */
26214     if (pDeviceID != NULL) {
26215         if (deviceType == ma_device_type_capture) {
26216             ma_bool32 found = MA_FALSE;
26217             NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
26218             for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
26219                 if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
26220                     [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil];
26221                     found = MA_TRUE;
26222                     break;
26223                 }
26224             }
26225
26226             if (found == MA_FALSE) {
26227                 return MA_DOES_NOT_EXIST;
26228             }
26229         }
26230     }
26231 #endif
26232
26233     /*
26234     Format. This is the hardest part of initialization because there's a few variables to take into account.
26235       1) The format must be supported by the device.
26236       2) The format must be supported miniaudio.
26237       3) There's a priority that miniaudio prefers.
26238
26239     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
26240     most important property is the sample rate. miniaudio can do format conversion for any sample rate and channel count, but cannot do the same
26241     for the sample data format. If the sample data format is not supported by miniaudio it must be ignored completely.
26242
26243     On mobile platforms this is a bit different. We just force the use of whatever the audio unit's current format is set to.
26244     */
26245     {
26246         AudioStreamBasicDescription origFormat;
26247         UInt32 origFormatSize = sizeof(origFormat);
26248         AudioUnitScope   formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
26249         AudioUnitElement formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;
26250
26251         if (deviceType == ma_device_type_playback) {
26252             status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize);
26253         } else {
26254             status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize);
26255         }
26256         if (status != noErr) {
26257             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26258             return ma_result_from_OSStatus(status);
26259         }
26260
26261     #if defined(MA_APPLE_DESKTOP)
26262         result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, &origFormat, &bestFormat);
26263         if (result != MA_SUCCESS) {
26264             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26265             return result;
26266         }
26267
26268         /*
26269         Technical Note TN2091: Device input using the HAL Output Audio Unit
26270             https://developer.apple.com/library/archive/technotes/tn2091/_index.html
26271
26272         This documentation says the following:
26273
26274             The internal AudioConverter can handle any *simple* conversion. Typically, this means that a client can specify ANY
26275             variant of the PCM formats. Consequently, the device's sample rate should match the desired sample rate. If sample rate
26276             conversion is needed, it can be accomplished by buffering the input and converting the data on a separate thread with
26277             another AudioConverter.
26278
26279         The important part here is the mention that it can handle *simple* conversions, which does *not* include sample rate. We
26280         therefore want to ensure the sample rate stays consistent. This document is specifically for input, but I'm going to play it
26281         safe and apply the same rule to output as well.
26282
26283         I have tried going against the documentation by setting the sample rate anyway, but this just results in AudioUnitRender()
26284         returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but
26285         this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format.
26286
26287         Something that does seem to work, however, has been setting the nominal sample rate on the deivce object. The problem with
26288         this, however, is that it actually changes the sample rate at the operating system level and not just the application. This
26289         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
26290         configuration option. When the `coreaudio.allowNominalSampleRateChange` config option is set to true, changing the sample
26291         rate will be allowed. Otherwise it'll be fixed to the current sample rate. To check the system-defined sample rate, run
26292         the Audio MIDI Setup program that comes installed on macOS and observe how the sample rate changes as the sample rate is
26293         changed by miniaudio.
26294         */
26295         if (pData->allowNominalSampleRateChange) {
26296             AudioValueRange sampleRateRange;
26297             AudioObjectPropertyAddress propAddress;
26298
26299             sampleRateRange.mMinimum = bestFormat.mSampleRate;
26300             sampleRateRange.mMaximum = bestFormat.mSampleRate;
26301
26302             propAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
26303             propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
26304             propAddress.mElement  = kAudioObjectPropertyElementMaster;
26305
26306             status = ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(sampleRateRange), &sampleRateRange);
26307             if (status != noErr) {
26308                 bestFormat.mSampleRate = origFormat.mSampleRate;
26309             }
26310         } else {
26311             bestFormat.mSampleRate = origFormat.mSampleRate;
26312         }
26313
26314         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
26315         if (status != noErr) {
26316             /* We failed to set the format, so fall back to the current format of the audio unit. */
26317             bestFormat = origFormat;
26318         }
26319     #else
26320         bestFormat = origFormat;
26321
26322         /*
26323         Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try
26324         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
26325         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
26326         can tell, it looks like the sample rate is shared between playback and capture for everything.
26327         */
26328         @autoreleasepool {
26329             AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
26330             MA_ASSERT(pAudioSession != NULL);
26331
26332             [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil];
26333             bestFormat.mSampleRate = pAudioSession.sampleRate;
26334
26335             /*
26336             I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with
26337             AVAudioSession outputNumberOfChannels. I'm going to try using the AVAudioSession values instead.
26338             */
26339             if (deviceType == ma_device_type_playback) {
26340                 bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.outputNumberOfChannels;
26341             }
26342             if (deviceType == ma_device_type_capture) {
26343                 bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.inputNumberOfChannels;
26344             }
26345         }
26346
26347         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
26348         if (status != noErr) {
26349             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26350             return ma_result_from_OSStatus(status);
26351         }
26352     #endif
26353
26354         result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pData->formatOut);
26355         if (result != MA_SUCCESS) {
26356             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26357             return result;
26358         }
26359
26360         if (pData->formatOut == ma_format_unknown) {
26361             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26362             return MA_FORMAT_NOT_SUPPORTED;
26363         }
26364
26365         pData->channelsOut   = bestFormat.mChannelsPerFrame;
26366         pData->sampleRateOut = bestFormat.mSampleRate;
26367     }
26368
26369     /* Clamp the channel count for safety. */
26370     if (pData->channelsOut > MA_MAX_CHANNELS) {
26371         pData->channelsOut = MA_MAX_CHANNELS;
26372     }
26373
26374     /*
26375     Internal channel map. This is weird in my testing. If I use the AudioObject to get the
26376     channel map, the channel descriptions are set to "Unknown" for some reason. To work around
26377     this it looks like retrieving it from the AudioUnit will work. However, and this is where
26378     it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore
26379     I'm going to fall back to a default assumption in these cases.
26380     */
26381 #if defined(MA_APPLE_DESKTOP)
26382     result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut, pData->channelsOut);
26383     if (result != MA_SUCCESS) {
26384     #if 0
26385         /* Try falling back to the channel map from the AudioObject. */
26386         result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut, pData->channelsOut);
26387         if (result != MA_SUCCESS) {
26388             return result;
26389         }
26390     #else
26391         /* Fall back to default assumptions. */
26392         ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut);
26393     #endif
26394     }
26395 #else
26396     /* TODO: Figure out how to get the channel map using AVAudioSession. */
26397     ma_get_standard_channel_map(ma_standard_channel_map_default, pData->channelsOut, pData->channelMapOut);
26398 #endif
26399
26400
26401     /* Buffer size. Not allowing this to be configurable on iOS. */
26402     if (pData->periodSizeInFramesIn == 0) {
26403         if (pData->periodSizeInMillisecondsIn == 0) {
26404             if (pData->performanceProfile == ma_performance_profile_low_latency) {
26405                 actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, pData->sampleRateOut);
26406             } else {
26407                 actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, pData->sampleRateOut);
26408             }
26409         } else {
26410             actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut);
26411         }
26412     } else {
26413         actualPeriodSizeInFrames = pData->periodSizeInFramesIn;
26414     }
26415
26416 #if defined(MA_APPLE_DESKTOP)
26417     result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames);
26418     if (result != MA_SUCCESS) {
26419         return result;
26420     }
26421 #else
26422     /*
26423     I don't know how to configure buffer sizes on iOS so for now we're not allowing it to be configured. Instead we're
26424     just going to set it to the value of kAudioUnitProperty_MaximumFramesPerSlice.
26425     */
26426     status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, &actualPeriodSizeInFramesSize);
26427     if (status != noErr) {
26428         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26429         return ma_result_from_OSStatus(status);
26430     }
26431 #endif
26432
26433
26434     /*
26435     During testing I discovered that the buffer size can be too big. You'll get an error like this:
26436
26437       kAudioUnitErr_TooManyFramesToProcess : inFramesToProcess=4096, mMaxFramesPerSlice=512
26438
26439     Note how inFramesToProcess is smaller than mMaxFramesPerSlice. To fix, we need to set kAudioUnitProperty_MaximumFramesPerSlice to that
26440     of the size of our buffer, or do it the other way around and set our buffer size to the kAudioUnitProperty_MaximumFramesPerSlice.
26441     */
26442     status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &actualPeriodSizeInFrames, sizeof(actualPeriodSizeInFrames));
26443     if (status != noErr) {
26444         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26445         return ma_result_from_OSStatus(status);
26446     }
26447
26448     pData->periodSizeInFramesOut = (ma_uint32)actualPeriodSizeInFrames;
26449
26450     /* We need a buffer list if this is an input device. We render into this in the input callback. */
26451     if (deviceType == ma_device_type_capture) {
26452         ma_bool32 isInterleaved = (bestFormat.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
26453         AudioBufferList* pBufferList;
26454
26455         pBufferList = ma_allocate_AudioBufferList__coreaudio(pData->periodSizeInFramesOut, pData->formatOut, pData->channelsOut, (isInterleaved) ? ma_stream_layout_interleaved : ma_stream_layout_deinterleaved, &pContext->allocationCallbacks);
26456         if (pBufferList == NULL) {
26457             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26458             return MA_OUT_OF_MEMORY;
26459         }
26460
26461         pData->pAudioBufferList = pBufferList;
26462     }
26463
26464     /* Callbacks. */
26465     callbackInfo.inputProcRefCon = pDevice_DoNotReference;
26466     if (deviceType == ma_device_type_playback) {
26467         callbackInfo.inputProc = ma_on_output__coreaudio;
26468         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &callbackInfo, sizeof(callbackInfo));
26469         if (status != noErr) {
26470             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26471             return ma_result_from_OSStatus(status);
26472         }
26473     } else {
26474         callbackInfo.inputProc = ma_on_input__coreaudio;
26475         status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callbackInfo, sizeof(callbackInfo));
26476         if (status != noErr) {
26477             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26478             return ma_result_from_OSStatus(status);
26479         }
26480     }
26481
26482     /* We need to listen for stop events. */
26483     if (pData->registerStopEvent) {
26484         status = ((ma_AudioUnitAddPropertyListener_proc)pContext->coreaudio.AudioUnitAddPropertyListener)(pData->audioUnit, kAudioOutputUnitProperty_IsRunning, on_start_stop__coreaudio, pDevice_DoNotReference);
26485         if (status != noErr) {
26486             ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26487             return ma_result_from_OSStatus(status);
26488         }
26489     }
26490
26491     /* Initialize the audio unit. */
26492     status = ((ma_AudioUnitInitialize_proc)pContext->coreaudio.AudioUnitInitialize)(pData->audioUnit);
26493     if (status != noErr) {
26494         ma__free_from_callbacks(pData->pAudioBufferList, &pContext->allocationCallbacks);
26495         pData->pAudioBufferList = NULL;
26496         ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
26497         return ma_result_from_OSStatus(status);
26498     }
26499
26500     /* Grab the name. */
26501 #if defined(MA_APPLE_DESKTOP)
26502     ma_get_AudioObject_name(pContext, deviceObjectID, sizeof(pData->deviceName), pData->deviceName);
26503 #else
26504     if (deviceType == ma_device_type_playback) {
26505         ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_PLAYBACK_DEVICE_NAME);
26506     } else {
26507         ma_strcpy_s(pData->deviceName, sizeof(pData->deviceName), MA_DEFAULT_CAPTURE_DEVICE_NAME);
26508     }
26509 #endif
26510
26511     return result;
26512 }
26513
26514 #if defined(MA_APPLE_DESKTOP)
26515 static ma_result ma_device_reinit_internal__coreaudio(ma_device* pDevice, ma_device_type deviceType, ma_bool32 disposePreviousAudioUnit)
26516 {
26517     ma_device_init_internal_data__coreaudio data;
26518     ma_result result;
26519
26520     /* This should only be called for playback or capture, not duplex. */
26521     if (deviceType == ma_device_type_duplex) {
26522         return MA_INVALID_ARGS;
26523     }
26524
26525     data.allowNominalSampleRateChange = MA_FALSE;   /* Don't change the nominal sample rate when switching devices. */
26526
26527     if (deviceType == ma_device_type_capture) {
26528         data.formatIn               = pDevice->capture.format;
26529         data.channelsIn             = pDevice->capture.channels;
26530         data.sampleRateIn           = pDevice->sampleRate;
26531         MA_COPY_MEMORY(data.channelMapIn, pDevice->capture.channelMap, sizeof(pDevice->capture.channelMap));
26532         data.shareMode              = pDevice->capture.shareMode;
26533         data.performanceProfile     = pDevice->coreaudio.originalPerformanceProfile;
26534         data.registerStopEvent      = MA_TRUE;
26535
26536         if (disposePreviousAudioUnit) {
26537             ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
26538             ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
26539         }
26540         if (pDevice->coreaudio.pAudioBufferList) {
26541             ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
26542         }
26543     } else if (deviceType == ma_device_type_playback) {
26544         data.formatIn               = pDevice->playback.format;
26545         data.channelsIn             = pDevice->playback.channels;
26546         data.sampleRateIn           = pDevice->sampleRate;
26547         MA_COPY_MEMORY(data.channelMapIn, pDevice->playback.channelMap, sizeof(pDevice->playback.channelMap));
26548         data.shareMode              = pDevice->playback.shareMode;
26549         data.performanceProfile     = pDevice->coreaudio.originalPerformanceProfile;
26550         data.registerStopEvent      = (pDevice->type != ma_device_type_duplex);
26551
26552         if (disposePreviousAudioUnit) {
26553             ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
26554             ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
26555         }
26556     }
26557     data.periodSizeInFramesIn       = pDevice->coreaudio.originalPeriodSizeInFrames;
26558     data.periodSizeInMillisecondsIn = pDevice->coreaudio.originalPeriodSizeInMilliseconds;
26559     data.periodsIn                  = pDevice->coreaudio.originalPeriods;
26560
26561     /* Need at least 3 periods for duplex. */
26562     if (data.periodsIn < 3 && pDevice->type == ma_device_type_duplex) {
26563         data.periodsIn = 3;
26564     }
26565
26566     result = ma_device_init_internal__coreaudio(pDevice->pContext, deviceType, NULL, &data, (void*)pDevice);
26567     if (result != MA_SUCCESS) {
26568         return result;
26569     }
26570
26571     if (deviceType == ma_device_type_capture) {
26572     #if defined(MA_APPLE_DESKTOP)
26573         pDevice->coreaudio.deviceObjectIDCapture     = (ma_uint32)data.deviceObjectID;
26574     #endif
26575         pDevice->coreaudio.audioUnitCapture          = (ma_ptr)data.audioUnit;
26576         pDevice->coreaudio.pAudioBufferList          = (ma_ptr)data.pAudioBufferList;
26577         pDevice->coreaudio.audioBufferCapInFrames    = data.periodSizeInFramesOut;
26578
26579         pDevice->capture.internalFormat              = data.formatOut;
26580         pDevice->capture.internalChannels            = data.channelsOut;
26581         pDevice->capture.internalSampleRate          = data.sampleRateOut;
26582         MA_COPY_MEMORY(pDevice->capture.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
26583         pDevice->capture.internalPeriodSizeInFrames  = data.periodSizeInFramesOut;
26584         pDevice->capture.internalPeriods             = data.periodsOut;
26585     } else if (deviceType == ma_device_type_playback) {
26586     #if defined(MA_APPLE_DESKTOP)
26587         pDevice->coreaudio.deviceObjectIDPlayback    = (ma_uint32)data.deviceObjectID;
26588     #endif
26589         pDevice->coreaudio.audioUnitPlayback         = (ma_ptr)data.audioUnit;
26590
26591         pDevice->playback.internalFormat             = data.formatOut;
26592         pDevice->playback.internalChannels           = data.channelsOut;
26593         pDevice->playback.internalSampleRate         = data.sampleRateOut;
26594         MA_COPY_MEMORY(pDevice->playback.internalChannelMap, data.channelMapOut, sizeof(data.channelMapOut));
26595         pDevice->playback.internalPeriodSizeInFrames = data.periodSizeInFramesOut;
26596         pDevice->playback.internalPeriods            = data.periodsOut;
26597     }
26598
26599     return MA_SUCCESS;
26600 }
26601 #endif /* MA_APPLE_DESKTOP */
26602
26603 static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
26604 {
26605     ma_result result;
26606
26607     MA_ASSERT(pDevice != NULL);
26608     MA_ASSERT(pConfig != NULL);
26609
26610     if (pConfig->deviceType == ma_device_type_loopback) {
26611         return MA_DEVICE_TYPE_NOT_SUPPORTED;
26612     }
26613
26614     /* No exclusive mode with the Core Audio backend for now. */
26615     if (((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive) ||
26616         ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive)) {
26617         return MA_SHARE_MODE_NOT_SUPPORTED;
26618     }
26619
26620     /* Capture needs to be initialized first. */
26621     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
26622         ma_device_init_internal_data__coreaudio data;
26623         data.allowNominalSampleRateChange = pConfig->coreaudio.allowNominalSampleRateChange;
26624         data.formatIn                     = pDescriptorCapture->format;
26625         data.channelsIn                   = pDescriptorCapture->channels;
26626         data.sampleRateIn                 = pDescriptorCapture->sampleRate;
26627         MA_COPY_MEMORY(data.channelMapIn, pDescriptorCapture->channelMap, sizeof(pDescriptorCapture->channelMap));
26628         data.periodSizeInFramesIn         = pDescriptorCapture->periodSizeInFrames;
26629         data.periodSizeInMillisecondsIn   = pDescriptorCapture->periodSizeInMilliseconds;
26630         data.periodsIn                    = pDescriptorCapture->periodCount;
26631         data.shareMode                    = pDescriptorCapture->shareMode;
26632         data.performanceProfile           = pConfig->performanceProfile;
26633         data.registerStopEvent            = MA_TRUE;
26634
26635         /* Need at least 3 periods for duplex. */
26636         if (data.periodsIn < 3 && pConfig->deviceType == ma_device_type_duplex) {
26637             data.periodsIn = 3;
26638         }
26639
26640         result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_capture, pDescriptorCapture->pDeviceID, &data, (void*)pDevice);
26641         if (result != MA_SUCCESS) {
26642             return result;
26643         }
26644
26645         pDevice->coreaudio.isDefaultCaptureDevice           = (pConfig->capture.pDeviceID == NULL);
26646     #if defined(MA_APPLE_DESKTOP)
26647         pDevice->coreaudio.deviceObjectIDCapture            = (ma_uint32)data.deviceObjectID;
26648     #endif
26649         pDevice->coreaudio.audioUnitCapture                 = (ma_ptr)data.audioUnit;
26650         pDevice->coreaudio.pAudioBufferList                 = (ma_ptr)data.pAudioBufferList;
26651         pDevice->coreaudio.audioBufferCapInFrames           = data.periodSizeInFramesOut;
26652         pDevice->coreaudio.originalPeriodSizeInFrames       = pDescriptorCapture->periodSizeInFrames;
26653         pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds;
26654         pDevice->coreaudio.originalPeriods                  = pDescriptorCapture->periodCount;
26655         pDevice->coreaudio.originalPerformanceProfile       = pConfig->performanceProfile;
26656
26657         pDescriptorCapture->format                          = data.formatOut;
26658         pDescriptorCapture->channels                        = data.channelsOut;
26659         pDescriptorCapture->sampleRate                      = data.sampleRateOut;
26660         MA_COPY_MEMORY(pDescriptorCapture->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
26661         pDescriptorCapture->periodSizeInFrames              = data.periodSizeInFramesOut;
26662         pDescriptorCapture->periodCount                     = data.periodsOut;
26663
26664     #if defined(MA_APPLE_DESKTOP)
26665         /*
26666         If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
26667         switch the device in the background.
26668         */
26669         if (pConfig->capture.pDeviceID == NULL) {
26670             ma_device__track__coreaudio(pDevice);
26671         }
26672     #endif
26673     }
26674
26675     /* Playback. */
26676     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
26677         ma_device_init_internal_data__coreaudio data;
26678         data.allowNominalSampleRateChange   = pConfig->coreaudio.allowNominalSampleRateChange;
26679         data.formatIn                       = pDescriptorPlayback->format;
26680         data.channelsIn                     = pDescriptorPlayback->channels;
26681         data.sampleRateIn                   = pDescriptorPlayback->sampleRate;
26682         MA_COPY_MEMORY(data.channelMapIn, pDescriptorPlayback->channelMap, sizeof(pDescriptorPlayback->channelMap));
26683         data.shareMode                      = pDescriptorPlayback->shareMode;
26684         data.performanceProfile             = pConfig->performanceProfile;
26685
26686         /* In full-duplex mode we want the playback buffer to be the same size as the capture buffer. */
26687         if (pConfig->deviceType == ma_device_type_duplex) {
26688             data.periodSizeInFramesIn       = pDescriptorCapture->periodSizeInFrames;
26689             data.periodsIn                  = pDescriptorCapture->periodCount;
26690             data.registerStopEvent          = MA_FALSE;
26691         } else {
26692             data.periodSizeInFramesIn       = pDescriptorPlayback->periodSizeInFrames;
26693             data.periodSizeInMillisecondsIn = pDescriptorPlayback->periodSizeInMilliseconds;
26694             data.periodsIn                  = pDescriptorPlayback->periodCount;
26695             data.registerStopEvent          = MA_TRUE;
26696         }
26697
26698         result = ma_device_init_internal__coreaudio(pDevice->pContext, ma_device_type_playback, pDescriptorPlayback->pDeviceID, &data, (void*)pDevice);
26699         if (result != MA_SUCCESS) {
26700             if (pConfig->deviceType == ma_device_type_duplex) {
26701                 ((ma_AudioComponentInstanceDispose_proc)pDevice->pContext->coreaudio.AudioComponentInstanceDispose)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
26702                 if (pDevice->coreaudio.pAudioBufferList) {
26703                     ma__free_from_callbacks(pDevice->coreaudio.pAudioBufferList, &pDevice->pContext->allocationCallbacks);
26704                 }
26705             }
26706             return result;
26707         }
26708
26709         pDevice->coreaudio.isDefaultPlaybackDevice          = (pConfig->playback.pDeviceID == NULL);
26710     #if defined(MA_APPLE_DESKTOP)
26711         pDevice->coreaudio.deviceObjectIDPlayback           = (ma_uint32)data.deviceObjectID;
26712     #endif
26713         pDevice->coreaudio.audioUnitPlayback                = (ma_ptr)data.audioUnit;
26714         pDevice->coreaudio.originalPeriodSizeInFrames       = pDescriptorPlayback->periodSizeInFrames;
26715         pDevice->coreaudio.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds;
26716         pDevice->coreaudio.originalPeriods                  = pDescriptorPlayback->periodCount;
26717         pDevice->coreaudio.originalPerformanceProfile       = pConfig->performanceProfile;
26718
26719         pDescriptorPlayback->format                         = data.formatOut;
26720         pDescriptorPlayback->channels                       = data.channelsOut;
26721         pDescriptorPlayback->sampleRate                     = data.sampleRateOut;
26722         MA_COPY_MEMORY(pDescriptorPlayback->channelMap, data.channelMapOut, sizeof(data.channelMapOut));
26723         pDescriptorPlayback->periodSizeInFrames             = data.periodSizeInFramesOut;
26724         pDescriptorPlayback->periodCount                    = data.periodsOut;
26725
26726     #if defined(MA_APPLE_DESKTOP)
26727         /*
26728         If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly
26729         switch the device in the background.
26730         */
26731         if (pDescriptorPlayback->pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pDescriptorCapture->pDeviceID != NULL)) {
26732             ma_device__track__coreaudio(pDevice);
26733         }
26734     #endif
26735     }
26736
26737     
26738
26739     /*
26740     When stopping the device, a callback is called on another thread. We need to wait for this callback
26741     before returning from ma_device_stop(). This event is used for this.
26742     */
26743     ma_event_init(&pDevice->coreaudio.stopEvent);
26744
26745     /*
26746     We need to detect when a route has changed so we can update the data conversion pipeline accordingly. This is done
26747     differently on non-Desktop Apple platforms.
26748     */
26749 #if defined(MA_APPLE_MOBILE)
26750     pDevice->coreaudio.pRouteChangeHandler = (__bridge_retained void*)[[ma_router_change_handler alloc] init:pDevice];
26751 #endif
26752
26753     return MA_SUCCESS;
26754 }
26755
26756
26757 static ma_result ma_device_start__coreaudio(ma_device* pDevice)
26758 {
26759     MA_ASSERT(pDevice != NULL);
26760
26761     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
26762         OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
26763         if (status != noErr) {
26764             return ma_result_from_OSStatus(status);
26765         }
26766     }
26767
26768     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
26769         OSStatus status = ((ma_AudioOutputUnitStart_proc)pDevice->pContext->coreaudio.AudioOutputUnitStart)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
26770         if (status != noErr) {
26771             if (pDevice->type == ma_device_type_duplex) {
26772                 ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
26773             }
26774             return ma_result_from_OSStatus(status);
26775         }
26776     }
26777
26778     return MA_SUCCESS;
26779 }
26780
26781 static ma_result ma_device_stop__coreaudio(ma_device* pDevice)
26782 {
26783     MA_ASSERT(pDevice != NULL);
26784
26785     /* It's not clear from the documentation whether or not AudioOutputUnitStop() actually drains the device or not. */
26786
26787     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
26788         OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitCapture);
26789         if (status != noErr) {
26790             return ma_result_from_OSStatus(status);
26791         }
26792     }
26793
26794     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
26795         OSStatus status = ((ma_AudioOutputUnitStop_proc)pDevice->pContext->coreaudio.AudioOutputUnitStop)((AudioUnit)pDevice->coreaudio.audioUnitPlayback);
26796         if (status != noErr) {
26797             return ma_result_from_OSStatus(status);
26798         }
26799     }
26800
26801     /* We need to wait for the callback to finish before returning. */
26802     ma_event_wait(&pDevice->coreaudio.stopEvent);
26803     return MA_SUCCESS;
26804 }
26805
26806
26807 static ma_result ma_context_uninit__coreaudio(ma_context* pContext)
26808 {
26809     MA_ASSERT(pContext != NULL);
26810     MA_ASSERT(pContext->backend == ma_backend_coreaudio);
26811
26812 #if defined(MA_APPLE_MOBILE)
26813     if (!pContext->coreaudio.noAudioSessionDeactivate) {
26814         if (![[AVAudioSession sharedInstance] setActive:false error:nil]) {
26815             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to deactivate audio session.", MA_FAILED_TO_INIT_BACKEND);
26816         }
26817     }
26818 #endif
26819
26820 #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
26821     ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
26822     ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
26823     ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
26824 #endif
26825
26826 #if !defined(MA_APPLE_MOBILE)
26827     ma_context__uninit_device_tracking__coreaudio(pContext);
26828 #endif
26829
26830     (void)pContext;
26831     return MA_SUCCESS;
26832 }
26833
26834 #if defined(MA_APPLE_MOBILE)
26835 static AVAudioSessionCategory ma_to_AVAudioSessionCategory(ma_ios_session_category category)
26836 {
26837     /* The "default" and "none" categories are treated different and should not be used as an input into this function. */
26838     MA_ASSERT(category != ma_ios_session_category_default);
26839     MA_ASSERT(category != ma_ios_session_category_none);
26840
26841     switch (category) {
26842         case ma_ios_session_category_ambient:         return AVAudioSessionCategoryAmbient;
26843         case ma_ios_session_category_solo_ambient:    return AVAudioSessionCategorySoloAmbient;
26844         case ma_ios_session_category_playback:        return AVAudioSessionCategoryPlayback;
26845         case ma_ios_session_category_record:          return AVAudioSessionCategoryRecord;
26846         case ma_ios_session_category_play_and_record: return AVAudioSessionCategoryPlayAndRecord;
26847         case ma_ios_session_category_multi_route:     return AVAudioSessionCategoryMultiRoute;
26848         case ma_ios_session_category_none:            return AVAudioSessionCategoryAmbient;
26849         case ma_ios_session_category_default:         return AVAudioSessionCategoryAmbient;
26850         default:                                      return AVAudioSessionCategoryAmbient;
26851     }
26852 }
26853 #endif
26854
26855 static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
26856 {
26857 #if !defined(MA_APPLE_MOBILE)
26858     ma_result result;
26859 #endif
26860
26861     MA_ASSERT(pConfig != NULL);
26862     MA_ASSERT(pContext != NULL);
26863
26864 #if defined(MA_APPLE_MOBILE)
26865     @autoreleasepool {
26866         AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
26867         AVAudioSessionCategoryOptions options = pConfig->coreaudio.sessionCategoryOptions;
26868
26869         MA_ASSERT(pAudioSession != NULL);
26870
26871         if (pConfig->coreaudio.sessionCategory == ma_ios_session_category_default) {
26872             /*
26873             I'm going to use trial and error to determine our default session category. First we'll try PlayAndRecord. If that fails
26874             we'll try Playback and if that fails we'll try record. If all of these fail we'll just not set the category.
26875             */
26876         #if !defined(MA_APPLE_TV) && !defined(MA_APPLE_WATCH)
26877             options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
26878         #endif
26879
26880             if ([pAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord withOptions:options error:nil]) {
26881                 /* Using PlayAndRecord */
26882             } else if ([pAudioSession setCategory: AVAudioSessionCategoryPlayback withOptions:options error:nil]) {
26883                 /* Using Playback */
26884             } else if ([pAudioSession setCategory: AVAudioSessionCategoryRecord withOptions:options error:nil]) {
26885                 /* Using Record */
26886             } else {
26887                 /* Leave as default? */
26888             }
26889         } else {
26890             if (pConfig->coreaudio.sessionCategory != ma_ios_session_category_none) {
26891                 if (![pAudioSession setCategory: ma_to_AVAudioSessionCategory(pConfig->coreaudio.sessionCategory) withOptions:options error:nil]) {
26892                     return MA_INVALID_OPERATION;    /* Failed to set session category. */
26893                 }
26894             }
26895         }
26896
26897         if (!pConfig->coreaudio.noAudioSessionActivate) {
26898             if (![pAudioSession setActive:true error:nil]) {
26899                 return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to activate audio session.", MA_FAILED_TO_INIT_BACKEND);
26900             }
26901         }
26902     }
26903 #endif
26904
26905 #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
26906     pContext->coreaudio.hCoreFoundation = ma_dlopen(pContext, "CoreFoundation.framework/CoreFoundation");
26907     if (pContext->coreaudio.hCoreFoundation == NULL) {
26908         return MA_API_NOT_FOUND;
26909     }
26910
26911     pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFStringGetCString");
26912     pContext->coreaudio.CFRelease          = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFRelease");
26913
26914
26915     pContext->coreaudio.hCoreAudio = ma_dlopen(pContext, "CoreAudio.framework/CoreAudio");
26916     if (pContext->coreaudio.hCoreAudio == NULL) {
26917         ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
26918         return MA_API_NOT_FOUND;
26919     }
26920
26921     pContext->coreaudio.AudioObjectGetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData");
26922     pContext->coreaudio.AudioObjectGetPropertyDataSize    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize");
26923     pContext->coreaudio.AudioObjectSetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData");
26924     pContext->coreaudio.AudioObjectAddPropertyListener    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener");
26925     pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener");
26926
26927     /*
26928     It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still
26929     defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback.
26930     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
26931     AudioToolbox.
26932     */
26933     pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit");
26934     if (pContext->coreaudio.hAudioUnit == NULL) {
26935         ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
26936         ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
26937         return MA_API_NOT_FOUND;
26938     }
26939
26940     if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) {
26941         /* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */
26942         ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
26943         pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox");
26944         if (pContext->coreaudio.hAudioUnit == NULL) {
26945             ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
26946             ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
26947             return MA_API_NOT_FOUND;
26948         }
26949     }
26950
26951     pContext->coreaudio.AudioComponentFindNext            = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext");
26952     pContext->coreaudio.AudioComponentInstanceDispose     = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose");
26953     pContext->coreaudio.AudioComponentInstanceNew         = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew");
26954     pContext->coreaudio.AudioOutputUnitStart              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart");
26955     pContext->coreaudio.AudioOutputUnitStop               = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop");
26956     pContext->coreaudio.AudioUnitAddPropertyListener      = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener");
26957     pContext->coreaudio.AudioUnitGetPropertyInfo          = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo");
26958     pContext->coreaudio.AudioUnitGetProperty              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty");
26959     pContext->coreaudio.AudioUnitSetProperty              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty");
26960     pContext->coreaudio.AudioUnitInitialize               = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize");
26961     pContext->coreaudio.AudioUnitRender                   = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender");
26962 #else
26963     pContext->coreaudio.CFStringGetCString                = (ma_proc)CFStringGetCString;
26964     pContext->coreaudio.CFRelease                         = (ma_proc)CFRelease;
26965
26966     #if defined(MA_APPLE_DESKTOP)
26967     pContext->coreaudio.AudioObjectGetPropertyData        = (ma_proc)AudioObjectGetPropertyData;
26968     pContext->coreaudio.AudioObjectGetPropertyDataSize    = (ma_proc)AudioObjectGetPropertyDataSize;
26969     pContext->coreaudio.AudioObjectSetPropertyData        = (ma_proc)AudioObjectSetPropertyData;
26970     pContext->coreaudio.AudioObjectAddPropertyListener    = (ma_proc)AudioObjectAddPropertyListener;
26971     pContext->coreaudio.AudioObjectRemovePropertyListener = (ma_proc)AudioObjectRemovePropertyListener;
26972     #endif
26973
26974     pContext->coreaudio.AudioComponentFindNext            = (ma_proc)AudioComponentFindNext;
26975     pContext->coreaudio.AudioComponentInstanceDispose     = (ma_proc)AudioComponentInstanceDispose;
26976     pContext->coreaudio.AudioComponentInstanceNew         = (ma_proc)AudioComponentInstanceNew;
26977     pContext->coreaudio.AudioOutputUnitStart              = (ma_proc)AudioOutputUnitStart;
26978     pContext->coreaudio.AudioOutputUnitStop               = (ma_proc)AudioOutputUnitStop;
26979     pContext->coreaudio.AudioUnitAddPropertyListener      = (ma_proc)AudioUnitAddPropertyListener;
26980     pContext->coreaudio.AudioUnitGetPropertyInfo          = (ma_proc)AudioUnitGetPropertyInfo;
26981     pContext->coreaudio.AudioUnitGetProperty              = (ma_proc)AudioUnitGetProperty;
26982     pContext->coreaudio.AudioUnitSetProperty              = (ma_proc)AudioUnitSetProperty;
26983     pContext->coreaudio.AudioUnitInitialize               = (ma_proc)AudioUnitInitialize;
26984     pContext->coreaudio.AudioUnitRender                   = (ma_proc)AudioUnitRender;
26985 #endif
26986
26987     /* Audio component. */
26988     {
26989         AudioComponentDescription desc;
26990         desc.componentType         = kAudioUnitType_Output;
26991     #if defined(MA_APPLE_DESKTOP)
26992         desc.componentSubType      = kAudioUnitSubType_HALOutput;
26993     #else
26994         desc.componentSubType      = kAudioUnitSubType_RemoteIO;
26995     #endif
26996         desc.componentManufacturer = kAudioUnitManufacturer_Apple;
26997         desc.componentFlags        = 0;
26998         desc.componentFlagsMask    = 0;
26999
27000         pContext->coreaudio.component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
27001         if (pContext->coreaudio.component == NULL) {
27002         #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
27003             ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
27004             ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
27005             ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
27006         #endif
27007             return MA_FAILED_TO_INIT_BACKEND;
27008         }
27009     }
27010
27011 #if !defined(MA_APPLE_MOBILE)
27012     result = ma_context__init_device_tracking__coreaudio(pContext);
27013     if (result != MA_SUCCESS) {
27014     #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
27015         ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
27016         ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
27017         ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
27018     #endif
27019         return result;
27020     }
27021 #endif
27022
27023     pContext->coreaudio.noAudioSessionDeactivate = pConfig->coreaudio.noAudioSessionDeactivate;
27024     
27025     pCallbacks->onContextInit             = ma_context_init__coreaudio;
27026     pCallbacks->onContextUninit           = ma_context_uninit__coreaudio;
27027     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__coreaudio;
27028     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__coreaudio;
27029     pCallbacks->onDeviceInit              = ma_device_init__coreaudio;
27030     pCallbacks->onDeviceUninit            = ma_device_uninit__coreaudio;
27031     pCallbacks->onDeviceStart             = ma_device_start__coreaudio;
27032     pCallbacks->onDeviceStop              = ma_device_stop__coreaudio;
27033     pCallbacks->onDeviceRead              = NULL;
27034     pCallbacks->onDeviceWrite             = NULL;
27035     pCallbacks->onDeviceDataLoop          = NULL;
27036
27037     return MA_SUCCESS;
27038 }
27039 #endif  /* Core Audio */
27040
27041
27042
27043 /******************************************************************************
27044
27045 sndio Backend
27046
27047 ******************************************************************************/
27048 #ifdef MA_HAS_SNDIO
27049 #include <fcntl.h>
27050
27051 /*
27052 Only supporting OpenBSD. This did not work very well at all on FreeBSD when I tried it. Not sure if this is due
27053 to miniaudio's implementation or if it's some kind of system configuration issue, but basically the default device
27054 just doesn't emit any sound, or at times you'll hear tiny pieces. I will consider enabling this when there's
27055 demand for it or if I can get it tested and debugged more thoroughly.
27056 */
27057 #if 0
27058 #if defined(__NetBSD__) || defined(__OpenBSD__)
27059 #include <sys/audioio.h>
27060 #endif
27061 #if defined(__FreeBSD__) || defined(__DragonFly__)
27062 #include <sys/soundcard.h>
27063 #endif
27064 #endif
27065
27066 #define MA_SIO_DEVANY   "default"
27067 #define MA_SIO_PLAY     1
27068 #define MA_SIO_REC      2
27069 #define MA_SIO_NENC     8
27070 #define MA_SIO_NCHAN    8
27071 #define MA_SIO_NRATE    16
27072 #define MA_SIO_NCONF    4
27073
27074 struct ma_sio_hdl; /* <-- Opaque */
27075
27076 struct ma_sio_par
27077 {
27078     unsigned int bits;
27079     unsigned int bps;
27080     unsigned int sig;
27081     unsigned int le;
27082     unsigned int msb;
27083     unsigned int rchan;
27084     unsigned int pchan;
27085     unsigned int rate;
27086     unsigned int bufsz;
27087     unsigned int xrun;
27088     unsigned int round;
27089     unsigned int appbufsz;
27090     int __pad[3];
27091     unsigned int __magic;
27092 };
27093
27094 struct ma_sio_enc
27095 {
27096     unsigned int bits;
27097     unsigned int bps;
27098     unsigned int sig;
27099     unsigned int le;
27100     unsigned int msb;
27101 };
27102
27103 struct ma_sio_conf
27104 {
27105     unsigned int enc;
27106     unsigned int rchan;
27107     unsigned int pchan;
27108     unsigned int rate;
27109 };
27110
27111 struct ma_sio_cap
27112 {
27113     struct ma_sio_enc enc[MA_SIO_NENC];
27114     unsigned int rchan[MA_SIO_NCHAN];
27115     unsigned int pchan[MA_SIO_NCHAN];
27116     unsigned int rate[MA_SIO_NRATE];
27117     int __pad[7];
27118     unsigned int nconf;
27119     struct ma_sio_conf confs[MA_SIO_NCONF];
27120 };
27121
27122 typedef struct ma_sio_hdl* (* ma_sio_open_proc)   (const char*, unsigned int, int);
27123 typedef void               (* ma_sio_close_proc)  (struct ma_sio_hdl*);
27124 typedef int                (* ma_sio_setpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*);
27125 typedef int                (* ma_sio_getpar_proc) (struct ma_sio_hdl*, struct ma_sio_par*);
27126 typedef int                (* ma_sio_getcap_proc) (struct ma_sio_hdl*, struct ma_sio_cap*);
27127 typedef size_t             (* ma_sio_write_proc)  (struct ma_sio_hdl*, const void*, size_t);
27128 typedef size_t             (* ma_sio_read_proc)   (struct ma_sio_hdl*, void*, size_t);
27129 typedef int                (* ma_sio_start_proc)  (struct ma_sio_hdl*);
27130 typedef int                (* ma_sio_stop_proc)   (struct ma_sio_hdl*);
27131 typedef int                (* ma_sio_initpar_proc)(struct ma_sio_par*);
27132
27133 static ma_uint32 ma_get_standard_sample_rate_priority_index__sndio(ma_uint32 sampleRate)   /* Lower = higher priority */
27134 {
27135     ma_uint32 i;
27136     for (i = 0; i < ma_countof(g_maStandardSampleRatePriorities); ++i) {
27137         if (g_maStandardSampleRatePriorities[i] == sampleRate) {
27138             return i;
27139         }
27140     }
27141
27142     return (ma_uint32)-1;
27143 }
27144
27145 static ma_format ma_format_from_sio_enc__sndio(unsigned int bits, unsigned int bps, unsigned int sig, unsigned int le, unsigned int msb)
27146 {
27147     /* We only support native-endian right now. */
27148     if ((ma_is_little_endian() && le == 0) || (ma_is_big_endian() && le == 1)) {
27149         return ma_format_unknown;
27150     }
27151
27152     if (bits ==  8 && bps == 1 && sig == 0) {
27153         return ma_format_u8;
27154     }
27155     if (bits == 16 && bps == 2 && sig == 1) {
27156         return ma_format_s16;
27157     }
27158     if (bits == 24 && bps == 3 && sig == 1) {
27159         return ma_format_s24;
27160     }
27161     if (bits == 24 && bps == 4 && sig == 1 && msb == 0) {
27162         /*return ma_format_s24_32;*/
27163     }
27164     if (bits == 32 && bps == 4 && sig == 1) {
27165         return ma_format_s32;
27166     }
27167
27168     return ma_format_unknown;
27169 }
27170
27171 static ma_format ma_find_best_format_from_sio_cap__sndio(struct ma_sio_cap* caps)
27172 {
27173     ma_format bestFormat;
27174     unsigned int iConfig;
27175
27176     MA_ASSERT(caps != NULL);
27177
27178     bestFormat = ma_format_unknown;
27179     for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
27180         unsigned int iEncoding;
27181         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
27182             unsigned int bits;
27183             unsigned int bps;
27184             unsigned int sig;
27185             unsigned int le;
27186             unsigned int msb;
27187             ma_format format;
27188
27189             if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
27190                 continue;
27191             }
27192
27193             bits = caps->enc[iEncoding].bits;
27194             bps  = caps->enc[iEncoding].bps;
27195             sig  = caps->enc[iEncoding].sig;
27196             le   = caps->enc[iEncoding].le;
27197             msb  = caps->enc[iEncoding].msb;
27198             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
27199             if (format == ma_format_unknown) {
27200                 continue;   /* Format not supported. */
27201             }
27202
27203             if (bestFormat == ma_format_unknown) {
27204                 bestFormat = format;
27205             } else {
27206                 if (ma_get_format_priority_index(bestFormat) > ma_get_format_priority_index(format)) {    /* <-- Lower = better. */
27207                     bestFormat = format;
27208                 }
27209             }
27210         }
27211     }
27212
27213     return bestFormat;
27214 }
27215
27216 static ma_uint32 ma_find_best_channels_from_sio_cap__sndio(struct ma_sio_cap* caps, ma_device_type deviceType, ma_format requiredFormat)
27217 {
27218     ma_uint32 maxChannels;
27219     unsigned int iConfig;
27220
27221     MA_ASSERT(caps != NULL);
27222     MA_ASSERT(requiredFormat != ma_format_unknown);
27223
27224     /* Just pick whatever configuration has the most channels. */
27225     maxChannels = 0;
27226     for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
27227         /* The encoding should be of requiredFormat. */
27228         unsigned int iEncoding;
27229         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
27230             unsigned int iChannel;
27231             unsigned int bits;
27232             unsigned int bps;
27233             unsigned int sig;
27234             unsigned int le;
27235             unsigned int msb;
27236             ma_format format;
27237
27238             if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
27239                 continue;
27240             }
27241
27242             bits = caps->enc[iEncoding].bits;
27243             bps  = caps->enc[iEncoding].bps;
27244             sig  = caps->enc[iEncoding].sig;
27245             le   = caps->enc[iEncoding].le;
27246             msb  = caps->enc[iEncoding].msb;
27247             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
27248             if (format != requiredFormat) {
27249                 continue;
27250             }
27251
27252             /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */
27253             for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
27254                 unsigned int chan = 0;
27255                 unsigned int channels;
27256
27257                 if (deviceType == ma_device_type_playback) {
27258                     chan = caps->confs[iConfig].pchan;
27259                 } else {
27260                     chan = caps->confs[iConfig].rchan;
27261                 }
27262
27263                 if ((chan & (1UL << iChannel)) == 0) {
27264                     continue;
27265                 }
27266
27267                 if (deviceType == ma_device_type_playback) {
27268                     channels = caps->pchan[iChannel];
27269                 } else {
27270                     channels = caps->rchan[iChannel];
27271                 }
27272
27273                 if (maxChannels < channels) {
27274                     maxChannels = channels;
27275                 }
27276             }
27277         }
27278     }
27279
27280     return maxChannels;
27281 }
27282
27283 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)
27284 {
27285     ma_uint32 firstSampleRate;
27286     ma_uint32 bestSampleRate;
27287     unsigned int iConfig;
27288
27289     MA_ASSERT(caps != NULL);
27290     MA_ASSERT(requiredFormat != ma_format_unknown);
27291     MA_ASSERT(requiredChannels > 0);
27292     MA_ASSERT(requiredChannels <= MA_MAX_CHANNELS);
27293
27294     firstSampleRate = 0; /* <-- If the device does not support a standard rate we'll fall back to the first one that's found. */
27295     bestSampleRate  = 0;
27296
27297     for (iConfig = 0; iConfig < caps->nconf; iConfig += 1) {
27298         /* The encoding should be of requiredFormat. */
27299         unsigned int iEncoding;
27300         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
27301             unsigned int iChannel;
27302             unsigned int bits;
27303             unsigned int bps;
27304             unsigned int sig;
27305             unsigned int le;
27306             unsigned int msb;
27307             ma_format format;
27308
27309             if ((caps->confs[iConfig].enc & (1UL << iEncoding)) == 0) {
27310                 continue;
27311             }
27312
27313             bits = caps->enc[iEncoding].bits;
27314             bps  = caps->enc[iEncoding].bps;
27315             sig  = caps->enc[iEncoding].sig;
27316             le   = caps->enc[iEncoding].le;
27317             msb  = caps->enc[iEncoding].msb;
27318             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
27319             if (format != requiredFormat) {
27320                 continue;
27321             }
27322
27323             /* Getting here means the format is supported. Iterate over each channel count and grab the biggest one. */
27324             for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
27325                 unsigned int chan = 0;
27326                 unsigned int channels;
27327                 unsigned int iRate;
27328
27329                 if (deviceType == ma_device_type_playback) {
27330                     chan = caps->confs[iConfig].pchan;
27331                 } else {
27332                     chan = caps->confs[iConfig].rchan;
27333                 }
27334
27335                 if ((chan & (1UL << iChannel)) == 0) {
27336                     continue;
27337                 }
27338
27339                 if (deviceType == ma_device_type_playback) {
27340                     channels = caps->pchan[iChannel];
27341                 } else {
27342                     channels = caps->rchan[iChannel];
27343                 }
27344
27345                 if (channels != requiredChannels) {
27346                     continue;
27347                 }
27348
27349                 /* Getting here means we have found a compatible encoding/channel pair. */
27350                 for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) {
27351                     ma_uint32 rate = (ma_uint32)caps->rate[iRate];
27352                     ma_uint32 ratePriority;
27353
27354                     if (firstSampleRate == 0) {
27355                         firstSampleRate = rate;
27356                     }
27357
27358                     /* Disregard this rate if it's not a standard one. */
27359                     ratePriority = ma_get_standard_sample_rate_priority_index__sndio(rate);
27360                     if (ratePriority == (ma_uint32)-1) {
27361                         continue;
27362                     }
27363
27364                     if (ma_get_standard_sample_rate_priority_index__sndio(bestSampleRate) > ratePriority) {   /* Lower = better. */
27365                         bestSampleRate = rate;
27366                     }
27367                 }
27368             }
27369         }
27370     }
27371
27372     /* If a standard sample rate was not found just fall back to the first one that was iterated. */
27373     if (bestSampleRate == 0) {
27374         bestSampleRate = firstSampleRate;
27375     }
27376
27377     return bestSampleRate;
27378 }
27379
27380
27381 static ma_result ma_context_enumerate_devices__sndio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
27382 {
27383     ma_bool32 isTerminating = MA_FALSE;
27384     struct ma_sio_hdl* handle;
27385
27386     MA_ASSERT(pContext != NULL);
27387     MA_ASSERT(callback != NULL);
27388
27389     /* sndio doesn't seem to have a good device enumeration API, so I'm therefore only enumerating over default devices for now. */
27390
27391     /* Playback. */
27392     if (!isTerminating) {
27393         handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_PLAY, 0);
27394         if (handle != NULL) {
27395             /* Supports playback. */
27396             ma_device_info deviceInfo;
27397             MA_ZERO_OBJECT(&deviceInfo);
27398             ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), MA_SIO_DEVANY);
27399             ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME);
27400
27401             isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
27402
27403             ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
27404         }
27405     }
27406
27407     /* Capture. */
27408     if (!isTerminating) {
27409         handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(MA_SIO_DEVANY, MA_SIO_REC, 0);
27410         if (handle != NULL) {
27411             /* Supports capture. */
27412             ma_device_info deviceInfo;
27413             MA_ZERO_OBJECT(&deviceInfo);
27414             ma_strcpy_s(deviceInfo.id.sndio, sizeof(deviceInfo.id.sndio), "default");
27415             ma_strcpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME);
27416
27417             isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
27418
27419             ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
27420         }
27421     }
27422
27423     return MA_SUCCESS;
27424 }
27425
27426 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)
27427 {
27428     char devid[256];
27429     struct ma_sio_hdl* handle;
27430     struct ma_sio_cap caps;
27431     unsigned int iConfig;
27432
27433     MA_ASSERT(pContext != NULL);
27434
27435     /* We need to open the device before we can get information about it. */
27436     if (pDeviceID == NULL) {
27437         ma_strcpy_s(devid, sizeof(devid), MA_SIO_DEVANY);
27438         ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (deviceType == ma_device_type_playback) ? MA_DEFAULT_PLAYBACK_DEVICE_NAME : MA_DEFAULT_CAPTURE_DEVICE_NAME);
27439     } else {
27440         ma_strcpy_s(devid, sizeof(devid), pDeviceID->sndio);
27441         ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), devid);
27442     }
27443
27444     handle = ((ma_sio_open_proc)pContext->sndio.sio_open)(devid, (deviceType == ma_device_type_playback) ? MA_SIO_PLAY : MA_SIO_REC, 0);
27445     if (handle == NULL) {
27446         return MA_NO_DEVICE;
27447     }
27448
27449     if (((ma_sio_getcap_proc)pContext->sndio.sio_getcap)(handle, &caps) == 0) {
27450         return MA_ERROR;
27451     }
27452
27453     pDeviceInfo->nativeDataFormatCount = 0;
27454
27455     for (iConfig = 0; iConfig < caps.nconf; iConfig += 1) {
27456         /*
27457         The main thing we care about is that the encoding is supported by miniaudio. If it is, we want to give
27458         preference to some formats over others.
27459         */
27460         unsigned int iEncoding;
27461         unsigned int iChannel;
27462         unsigned int iRate;
27463
27464         for (iEncoding = 0; iEncoding < MA_SIO_NENC; iEncoding += 1) {
27465             unsigned int bits;
27466             unsigned int bps;
27467             unsigned int sig;
27468             unsigned int le;
27469             unsigned int msb;
27470             ma_format format;
27471
27472             if ((caps.confs[iConfig].enc & (1UL << iEncoding)) == 0) {
27473                 continue;
27474             }
27475
27476             bits = caps.enc[iEncoding].bits;
27477             bps  = caps.enc[iEncoding].bps;
27478             sig  = caps.enc[iEncoding].sig;
27479             le   = caps.enc[iEncoding].le;
27480             msb  = caps.enc[iEncoding].msb;
27481             format = ma_format_from_sio_enc__sndio(bits, bps, sig, le, msb);
27482             if (format == ma_format_unknown) {
27483                 continue;   /* Format not supported. */
27484             }
27485
27486
27487             /* Channels. */
27488             for (iChannel = 0; iChannel < MA_SIO_NCHAN; iChannel += 1) {
27489                 unsigned int chan = 0;
27490                 unsigned int channels;
27491
27492                 if (deviceType == ma_device_type_playback) {
27493                     chan = caps.confs[iConfig].pchan;
27494                 } else {
27495                     chan = caps.confs[iConfig].rchan;
27496                 }
27497
27498                 if ((chan & (1UL << iChannel)) == 0) {
27499                     continue;
27500                 }
27501
27502                 if (deviceType == ma_device_type_playback) {
27503                     channels = caps.pchan[iChannel];
27504                 } else {
27505                     channels = caps.rchan[iChannel];
27506                 }
27507
27508
27509                 /* Sample Rates. */
27510                 for (iRate = 0; iRate < MA_SIO_NRATE; iRate += 1) {
27511                     if ((caps.confs[iConfig].rate & (1UL << iRate)) != 0) {
27512                         ma_device_info_add_native_data_format(pDeviceInfo, format, channels, caps.rate[iRate], 0);
27513                     }
27514                 }
27515             }
27516         }
27517     }
27518
27519     ((ma_sio_close_proc)pContext->sndio.sio_close)(handle);
27520     return MA_SUCCESS;
27521 }
27522
27523 static ma_result ma_device_uninit__sndio(ma_device* pDevice)
27524 {
27525     MA_ASSERT(pDevice != NULL);
27526
27527     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27528         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
27529     }
27530
27531     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27532         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);
27533     }
27534
27535     return MA_SUCCESS;
27536 }
27537
27538 static ma_result ma_device_init_handle__sndio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
27539 {
27540     const char* pDeviceName;
27541     ma_ptr handle;
27542     int openFlags = 0;
27543     struct ma_sio_cap caps;
27544     struct ma_sio_par par;
27545     const ma_device_id* pDeviceID;
27546     ma_format format;
27547     ma_uint32 channels;
27548     ma_uint32 sampleRate;
27549     ma_format internalFormat;
27550     ma_uint32 internalChannels;
27551     ma_uint32 internalSampleRate;
27552     ma_uint32 internalPeriodSizeInFrames;
27553     ma_uint32 internalPeriods;
27554
27555     MA_ASSERT(pConfig    != NULL);
27556     MA_ASSERT(deviceType != ma_device_type_duplex);
27557     MA_ASSERT(pDevice    != NULL);
27558
27559     if (deviceType == ma_device_type_capture) {
27560         openFlags  = MA_SIO_REC;
27561     } else {
27562         openFlags = MA_SIO_PLAY;
27563     }
27564
27565     pDeviceID  = pDescriptor->pDeviceID;
27566     format     = pDescriptor->format;
27567     channels   = pDescriptor->channels;
27568     sampleRate = pDescriptor->sampleRate;
27569
27570     pDeviceName = MA_SIO_DEVANY;
27571     if (pDeviceID != NULL) {
27572         pDeviceName = pDeviceID->sndio;
27573     }
27574
27575     handle = (ma_ptr)((ma_sio_open_proc)pDevice->pContext->sndio.sio_open)(pDeviceName, openFlags, 0);
27576     if (handle == NULL) {
27577         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to open device.", MA_FAILED_TO_OPEN_BACKEND_DEVICE);
27578     }
27579
27580     /* We need to retrieve the device caps to determine the most appropriate format to use. */
27581     if (((ma_sio_getcap_proc)pDevice->pContext->sndio.sio_getcap)((struct ma_sio_hdl*)handle, &caps) == 0) {
27582         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
27583         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve device caps.", MA_ERROR);
27584     }
27585
27586     /*
27587     Note: sndio reports a huge range of available channels. This is inconvenient for us because there's no real
27588     way, as far as I can tell, to get the _actual_ channel count of the device. I'm therefore restricting this
27589     to the requested channels, regardless of whether or not the default channel count is requested.
27590
27591     For hardware devices, I'm suspecting only a single channel count will be reported and we can safely use the
27592     value returned by ma_find_best_channels_from_sio_cap__sndio().
27593     */
27594     if (deviceType == ma_device_type_capture) {
27595         if (format == ma_format_unknown) {
27596             format = ma_find_best_format_from_sio_cap__sndio(&caps);
27597         }
27598
27599         if (channels == 0) {
27600             if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
27601                 channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format);
27602             } else {
27603                 channels = MA_DEFAULT_CHANNELS;
27604             }
27605         }
27606     } else {
27607         if (format == ma_format_unknown) {
27608             format = ma_find_best_format_from_sio_cap__sndio(&caps);
27609         }
27610
27611         if (channels == 0) {
27612             if (strlen(pDeviceName) > strlen("rsnd/") && strncmp(pDeviceName, "rsnd/", strlen("rsnd/")) == 0) {
27613                 channels = ma_find_best_channels_from_sio_cap__sndio(&caps, deviceType, format);
27614             } else {
27615                 channels = MA_DEFAULT_CHANNELS;
27616             }
27617         }
27618     }
27619
27620     if (sampleRate == 0) {
27621         sampleRate = ma_find_best_sample_rate_from_sio_cap__sndio(&caps, pConfig->deviceType, format, channels);
27622     }
27623
27624
27625     ((ma_sio_initpar_proc)pDevice->pContext->sndio.sio_initpar)(&par);
27626     par.msb = 0;
27627     par.le  = ma_is_little_endian();
27628
27629     switch (format) {
27630         case ma_format_u8:
27631         {
27632             par.bits = 8;
27633             par.bps  = 1;
27634             par.sig  = 0;
27635         } break;
27636
27637         case ma_format_s24:
27638         {
27639             par.bits = 24;
27640             par.bps  = 3;
27641             par.sig  = 1;
27642         } break;
27643
27644         case ma_format_s32:
27645         {
27646             par.bits = 32;
27647             par.bps  = 4;
27648             par.sig  = 1;
27649         } break;
27650
27651         case ma_format_s16:
27652         case ma_format_f32:
27653         case ma_format_unknown:
27654         default:
27655         {
27656             par.bits = 16;
27657             par.bps  = 2;
27658             par.sig  = 1;
27659         } break;
27660     }
27661     
27662     if (deviceType == ma_device_type_capture) {
27663         par.rchan = channels;
27664     } else {
27665         par.pchan = channels;
27666     }
27667
27668     par.rate = sampleRate;
27669
27670     internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, par.rate, pConfig->performanceProfile);
27671
27672     par.round    = internalPeriodSizeInFrames;
27673     par.appbufsz = par.round * pDescriptor->periodCount;
27674
27675     if (((ma_sio_setpar_proc)pDevice->pContext->sndio.sio_setpar)((struct ma_sio_hdl*)handle, &par) == 0) {
27676         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
27677         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to set buffer size.", MA_FORMAT_NOT_SUPPORTED);
27678     }
27679
27680     if (((ma_sio_getpar_proc)pDevice->pContext->sndio.sio_getpar)((struct ma_sio_hdl*)handle, &par) == 0) {
27681         ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)handle);
27682         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to retrieve buffer size.", MA_FORMAT_NOT_SUPPORTED);
27683     }
27684
27685     internalFormat             = ma_format_from_sio_enc__sndio(par.bits, par.bps, par.sig, par.le, par.msb);
27686     internalChannels           = (deviceType == ma_device_type_capture) ? par.rchan : par.pchan;
27687     internalSampleRate         = par.rate;
27688     internalPeriods            = par.appbufsz / par.round;
27689     internalPeriodSizeInFrames = par.round;
27690
27691     if (deviceType == ma_device_type_capture) {
27692         pDevice->sndio.handleCapture  = handle;
27693     } else {
27694         pDevice->sndio.handlePlayback = handle;
27695     }
27696
27697     pDescriptor->format             = internalFormat;
27698     pDescriptor->channels           = internalChannels;
27699     pDescriptor->sampleRate         = internalSampleRate;
27700     ma_get_standard_channel_map(ma_standard_channel_map_sndio, pDevice->playback.internalChannels, pDevice->playback.internalChannelMap);
27701     pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames;
27702     pDescriptor->periodCount        = internalPeriods;
27703
27704 #ifdef MA_DEBUG_OUTPUT
27705     printf("DEVICE INFO\n");
27706     printf("    Format:      %s\n", ma_get_format_name(internalFormat));
27707     printf("    Channels:    %d\n", internalChannels);
27708     printf("    Sample Rate: %d\n", internalSampleRate);
27709     printf("    Period Size: %d\n", internalPeriodSizeInFrames);
27710     printf("    Periods:     %d\n", internalPeriods);
27711     printf("    appbufsz:    %d\n", par.appbufsz);
27712     printf("    round:       %d\n", par.round);
27713 #endif
27714
27715     return MA_SUCCESS;
27716 }
27717
27718 static ma_result ma_device_init__sndio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
27719 {
27720     MA_ASSERT(pDevice != NULL);
27721
27722     MA_ZERO_OBJECT(&pDevice->sndio);
27723
27724     if (pConfig->deviceType == ma_device_type_loopback) {
27725         return MA_DEVICE_TYPE_NOT_SUPPORTED;
27726     }
27727
27728     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
27729         ma_result result = ma_device_init_handle__sndio(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
27730         if (result != MA_SUCCESS) {
27731             return result;
27732         }
27733     }
27734
27735     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
27736         ma_result result = ma_device_init_handle__sndio(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
27737         if (result != MA_SUCCESS) {
27738             return result;
27739         }
27740     }
27741
27742     return MA_SUCCESS;
27743 }
27744
27745 static ma_result ma_device_start__sndio(ma_device* pDevice)
27746 {
27747     MA_ASSERT(pDevice != NULL);
27748
27749     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27750         ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
27751     }
27752
27753     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
27754         ((ma_sio_start_proc)pDevice->pContext->sndio.sio_start)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);   /* <-- Doesn't actually playback until data is written. */
27755     }
27756
27757     return MA_SUCCESS;
27758 }
27759
27760 static ma_result ma_device_stop__sndio(ma_device* pDevice)
27761 {
27762     MA_ASSERT(pDevice != NULL);
27763
27764     /*
27765     From the documentation:
27766
27767         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
27768         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
27769         buffer is drained. In no case are samples in the play buffer discarded.
27770
27771     Therefore, sio_stop() performs all of the necessary draining for us.
27772     */
27773
27774     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
27775         ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handleCapture);
27776     }
27777
27778     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
27779         ((ma_sio_stop_proc)pDevice->pContext->sndio.sio_stop)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback);
27780     }
27781
27782     return MA_SUCCESS;
27783 }
27784
27785 static ma_result ma_device_write__sndio(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
27786 {
27787     int result;
27788
27789     if (pFramesWritten != NULL) {
27790         *pFramesWritten = 0;
27791     }
27792
27793     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));
27794     if (result == 0) {
27795         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to send data from the client to the device.", MA_IO_ERROR);
27796     }
27797
27798     if (pFramesWritten != NULL) {
27799         *pFramesWritten = frameCount;
27800     }
27801
27802     return MA_SUCCESS;
27803 }
27804
27805 static ma_result ma_device_read__sndio(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
27806 {
27807     int result;
27808
27809     if (pFramesRead != NULL) {
27810         *pFramesRead = 0;
27811     }
27812
27813     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));
27814     if (result == 0) {
27815         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[sndio] Failed to read data from the device to be sent to the device.", MA_IO_ERROR);
27816     }
27817
27818     if (pFramesRead != NULL) {
27819         *pFramesRead = frameCount;
27820     }
27821
27822     return MA_SUCCESS;
27823 }
27824
27825 static ma_result ma_context_uninit__sndio(ma_context* pContext)
27826 {
27827     MA_ASSERT(pContext != NULL);
27828     MA_ASSERT(pContext->backend == ma_backend_sndio);
27829
27830     (void)pContext;
27831     return MA_SUCCESS;
27832 }
27833
27834 static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
27835 {
27836 #ifndef MA_NO_RUNTIME_LINKING
27837     const char* libsndioNames[] = {
27838         "libsndio.so"
27839     };
27840     size_t i;
27841
27842     for (i = 0; i < ma_countof(libsndioNames); ++i) {
27843         pContext->sndio.sndioSO = ma_dlopen(pContext, libsndioNames[i]);
27844         if (pContext->sndio.sndioSO != NULL) {
27845             break;
27846         }
27847     }
27848
27849     if (pContext->sndio.sndioSO == NULL) {
27850         return MA_NO_BACKEND;
27851     }
27852
27853     pContext->sndio.sio_open    = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_open");
27854     pContext->sndio.sio_close   = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_close");
27855     pContext->sndio.sio_setpar  = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_setpar");
27856     pContext->sndio.sio_getpar  = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getpar");
27857     pContext->sndio.sio_getcap  = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getcap");
27858     pContext->sndio.sio_write   = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_write");
27859     pContext->sndio.sio_read    = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_read");
27860     pContext->sndio.sio_start   = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_start");
27861     pContext->sndio.sio_stop    = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_stop");
27862     pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_initpar");
27863 #else
27864     pContext->sndio.sio_open    = sio_open;
27865     pContext->sndio.sio_close   = sio_close;
27866     pContext->sndio.sio_setpar  = sio_setpar;
27867     pContext->sndio.sio_getpar  = sio_getpar;
27868     pContext->sndio.sio_getcap  = sio_getcap;
27869     pContext->sndio.sio_write   = sio_write;
27870     pContext->sndio.sio_read    = sio_read;
27871     pContext->sndio.sio_start   = sio_start;
27872     pContext->sndio.sio_stop    = sio_stop;
27873     pContext->sndio.sio_initpar = sio_initpar;
27874 #endif
27875
27876     pCallbacks->onContextInit             = ma_context_init__sndio;
27877     pCallbacks->onContextUninit           = ma_context_uninit__sndio;
27878     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__sndio;
27879     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__sndio;
27880     pCallbacks->onDeviceInit              = ma_device_init__sndio;
27881     pCallbacks->onDeviceUninit            = ma_device_uninit__sndio;
27882     pCallbacks->onDeviceStart             = ma_device_start__sndio;
27883     pCallbacks->onDeviceStop              = ma_device_stop__sndio;
27884     pCallbacks->onDeviceRead              = ma_device_read__sndio;
27885     pCallbacks->onDeviceWrite             = ma_device_write__sndio;
27886     pCallbacks->onDeviceDataLoop          = NULL;
27887
27888     (void)pConfig;
27889     return MA_SUCCESS;
27890 }
27891 #endif  /* sndio */
27892
27893
27894
27895 /******************************************************************************
27896
27897 audio(4) Backend
27898
27899 ******************************************************************************/
27900 #ifdef MA_HAS_AUDIO4
27901 #include <fcntl.h>
27902 #include <poll.h>
27903 #include <errno.h>
27904 #include <sys/stat.h>
27905 #include <sys/types.h>
27906 #include <sys/ioctl.h>
27907 #include <sys/audioio.h>
27908
27909 #if defined(__OpenBSD__)
27910     #include <sys/param.h>
27911     #if defined(OpenBSD) && OpenBSD >= 201709
27912         #define MA_AUDIO4_USE_NEW_API
27913     #endif
27914 #endif
27915
27916 static void ma_construct_device_id__audio4(char* id, size_t idSize, const char* base, int deviceIndex)
27917 {
27918     size_t baseLen;
27919
27920     MA_ASSERT(id != NULL);
27921     MA_ASSERT(idSize > 0);
27922     MA_ASSERT(deviceIndex >= 0);
27923
27924     baseLen = strlen(base);
27925     MA_ASSERT(idSize > baseLen);
27926
27927     ma_strcpy_s(id, idSize, base);
27928     ma_itoa_s(deviceIndex, id+baseLen, idSize-baseLen, 10);
27929 }
27930
27931 static ma_result ma_extract_device_index_from_id__audio4(const char* id, const char* base, int* pIndexOut)
27932 {
27933     size_t idLen;
27934     size_t baseLen;
27935     const char* deviceIndexStr;
27936
27937     MA_ASSERT(id != NULL);
27938     MA_ASSERT(base != NULL);
27939     MA_ASSERT(pIndexOut != NULL);
27940
27941     idLen = strlen(id);
27942     baseLen = strlen(base);
27943     if (idLen <= baseLen) {
27944         return MA_ERROR;   /* Doesn't look like the id starts with the base. */
27945     }
27946
27947     if (strncmp(id, base, baseLen) != 0) {
27948         return MA_ERROR;   /* ID does not begin with base. */
27949     }
27950
27951     deviceIndexStr = id + baseLen;
27952     if (deviceIndexStr[0] == '\0') {
27953         return MA_ERROR;   /* No index specified in the ID. */
27954     }
27955
27956     if (pIndexOut) {
27957         *pIndexOut = atoi(deviceIndexStr);
27958     }
27959
27960     return MA_SUCCESS;
27961 }
27962
27963
27964 #if !defined(MA_AUDIO4_USE_NEW_API)    /* Old API */
27965 static ma_format ma_format_from_encoding__audio4(unsigned int encoding, unsigned int precision)
27966 {
27967     if (precision == 8 && (encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR || encoding == AUDIO_ENCODING_ULINEAR_LE || encoding == AUDIO_ENCODING_ULINEAR_BE)) {
27968         return ma_format_u8;
27969     } else {
27970         if (ma_is_little_endian() && encoding == AUDIO_ENCODING_SLINEAR_LE) {
27971             if (precision == 16) {
27972                 return ma_format_s16;
27973             } else if (precision == 24) {
27974                 return ma_format_s24;
27975             } else if (precision == 32) {
27976                 return ma_format_s32;
27977             }
27978         } else if (ma_is_big_endian() && encoding == AUDIO_ENCODING_SLINEAR_BE) {
27979             if (precision == 16) {
27980                 return ma_format_s16;
27981             } else if (precision == 24) {
27982                 return ma_format_s24;
27983             } else if (precision == 32) {
27984                 return ma_format_s32;
27985             }
27986         }
27987     }
27988
27989     return ma_format_unknown;  /* Encoding not supported. */
27990 }
27991
27992 static void ma_encoding_from_format__audio4(ma_format format, unsigned int* pEncoding, unsigned int* pPrecision)
27993 {
27994     MA_ASSERT(pEncoding  != NULL);
27995     MA_ASSERT(pPrecision != NULL);
27996
27997     switch (format)
27998     {
27999         case ma_format_u8:
28000         {
28001             *pEncoding = AUDIO_ENCODING_ULINEAR;
28002             *pPrecision = 8;
28003         } break;
28004
28005         case ma_format_s24:
28006         {
28007             *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
28008             *pPrecision = 24;
28009         } break;
28010
28011         case ma_format_s32:
28012         {
28013             *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
28014             *pPrecision = 32;
28015         } break;
28016
28017         case ma_format_s16:
28018         case ma_format_f32:
28019         case ma_format_unknown:
28020         default:
28021         {
28022             *pEncoding = (ma_is_little_endian()) ? AUDIO_ENCODING_SLINEAR_LE : AUDIO_ENCODING_SLINEAR_BE;
28023             *pPrecision = 16;
28024         } break;
28025     }
28026 }
28027
28028 static ma_format ma_format_from_prinfo__audio4(struct audio_prinfo* prinfo)
28029 {
28030     return ma_format_from_encoding__audio4(prinfo->encoding, prinfo->precision);
28031 }
28032
28033 static ma_format ma_best_format_from_fd__audio4(int fd, ma_format preferredFormat)
28034 {
28035     audio_encoding_t encoding;
28036     ma_uint32 iFormat;
28037     int counter = 0;
28038
28039     /* First check to see if the preferred format is supported. */
28040     if (preferredFormat != ma_format_unknown) {
28041         counter = 0;
28042         for (;;) {
28043             MA_ZERO_OBJECT(&encoding);
28044             encoding.index = counter;
28045             if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) {
28046                 break;
28047             }
28048
28049             if (preferredFormat == ma_format_from_encoding__audio4(encoding.encoding, encoding.precision)) {
28050                 return preferredFormat;  /* Found the preferred format. */
28051             }
28052
28053             /* Getting here means this encoding does not match our preferred format so we need to more on to the next encoding. */
28054             counter += 1;
28055         }
28056     }
28057
28058     /* Getting here means our preferred format is not supported, so fall back to our standard priorities. */
28059     for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); iFormat += 1) {
28060         ma_format format = g_maFormatPriorities[iFormat];
28061
28062         counter = 0;
28063         for (;;) {
28064             MA_ZERO_OBJECT(&encoding);
28065             encoding.index = counter;
28066             if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) {
28067                 break;
28068             }
28069
28070             if (format == ma_format_from_encoding__audio4(encoding.encoding, encoding.precision)) {
28071                 return format;  /* Found a workable format. */
28072             }
28073
28074             /* Getting here means this encoding does not match our preferred format so we need to more on to the next encoding. */
28075             counter += 1;
28076         }
28077     }
28078
28079     /* Getting here means not appropriate format was found. */
28080     return ma_format_unknown;
28081 }
28082 #else
28083 static ma_format ma_format_from_swpar__audio4(struct audio_swpar* par)
28084 {
28085     if (par->bits == 8 && par->bps == 1 && par->sig == 0) {
28086         return ma_format_u8;
28087     }
28088     if (par->bits == 16 && par->bps == 2 && par->sig == 1 && par->le == ma_is_little_endian()) {
28089         return ma_format_s16;
28090     }
28091     if (par->bits == 24 && par->bps == 3 && par->sig == 1 && par->le == ma_is_little_endian()) {
28092         return ma_format_s24;
28093     }
28094     if (par->bits == 32 && par->bps == 4 && par->sig == 1 && par->le == ma_is_little_endian()) {
28095         return ma_format_f32;
28096     }
28097
28098     /* Format not supported. */
28099     return ma_format_unknown;
28100 }
28101 #endif
28102
28103 static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext, ma_device_type deviceType, int fd, ma_device_info* pDeviceInfo)
28104 {
28105     audio_device_t fdDevice;
28106
28107     MA_ASSERT(pContext != NULL);
28108     MA_ASSERT(fd >= 0);
28109     MA_ASSERT(pDeviceInfo != NULL);
28110
28111     (void)pContext;
28112     (void)deviceType;
28113
28114     if (ioctl(fd, AUDIO_GETDEV, &fdDevice) < 0) {
28115         return MA_ERROR;   /* Failed to retrieve device info. */
28116     }
28117
28118     /* Name. */
28119     ma_strcpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), fdDevice.name);
28120
28121     #if !defined(MA_AUDIO4_USE_NEW_API)
28122     {
28123         audio_info_t fdInfo;
28124         int counter = 0;
28125         ma_uint32 channels;
28126         ma_uint32 sampleRate;
28127
28128         if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) {
28129             return MA_ERROR;
28130         }
28131
28132         if (deviceType == ma_device_type_playback) {
28133             channels   = fdInfo.play.channels;
28134             sampleRate = fdInfo.play.sample_rate;
28135         } else {
28136             channels   = fdInfo.record.channels;
28137             sampleRate = fdInfo.record.sample_rate;
28138         }
28139
28140         /* Supported formats. We get this by looking at the encodings. */
28141         pDeviceInfo->nativeDataFormatCount = 0;
28142         for (;;) {
28143             audio_encoding_t encoding;
28144             ma_format format;
28145
28146             MA_ZERO_OBJECT(&encoding);
28147             encoding.index = counter;
28148             if (ioctl(fd, AUDIO_GETENC, &encoding) < 0) {
28149                 break;
28150             }
28151
28152             format = ma_format_from_encoding__audio4(encoding.encoding, encoding.precision);
28153             if (format != ma_format_unknown) {
28154                 ma_device_info_add_native_data_format(pDeviceInfo, format, channels, sampleRate, 0);
28155             }
28156
28157             counter += 1;
28158         }
28159     }
28160     #else
28161     {
28162         struct audio_swpar fdPar;
28163         ma_format format;
28164         ma_uint32 channels;
28165         ma_uint32 sampleRate;
28166
28167         if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
28168             return MA_ERROR;
28169         }
28170
28171         format = ma_format_from_swpar__audio4(&fdPar);
28172         if (format == ma_format_unknown) {
28173             return MA_FORMAT_NOT_SUPPORTED;
28174         }
28175
28176         if (deviceType == ma_device_type_playback) {
28177             channels = fdPar.pchan;
28178         } else {
28179             channels = fdPar.rchan;
28180         }
28181
28182         sampleRate = fdPar.rate;
28183
28184         pDeviceInfo->nativeDataFormatCount = 0;
28185         ma_device_info_add_native_data_format(pDeviceInfo, format, channels, sampleRate, 0);
28186     }
28187     #endif
28188
28189     return MA_SUCCESS;
28190 }
28191
28192 static ma_result ma_context_enumerate_devices__audio4(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
28193 {
28194     const int maxDevices = 64;
28195     char devpath[256];
28196     int iDevice;
28197
28198     MA_ASSERT(pContext != NULL);
28199     MA_ASSERT(callback != NULL);
28200
28201     /*
28202     Every device will be named "/dev/audioN", with a "/dev/audioctlN" equivalent. We use the "/dev/audioctlN"
28203     version here since we can open it even when another process has control of the "/dev/audioN" device.
28204     */
28205     for (iDevice = 0; iDevice < maxDevices; ++iDevice) {
28206         struct stat st;
28207         int fd;
28208         ma_bool32 isTerminating = MA_FALSE;
28209
28210         ma_strcpy_s(devpath, sizeof(devpath), "/dev/audioctl");
28211         ma_itoa_s(iDevice, devpath+strlen(devpath), sizeof(devpath)-strlen(devpath), 10);
28212
28213         if (stat(devpath, &st) < 0) {
28214             break;
28215         }
28216
28217         /* The device exists, but we need to check if it's usable as playback and/or capture. */
28218
28219         /* Playback. */
28220         if (!isTerminating) {
28221             fd = open(devpath, O_RDONLY, 0);
28222             if (fd >= 0) {
28223                 /* Supports playback. */
28224                 ma_device_info deviceInfo;
28225                 MA_ZERO_OBJECT(&deviceInfo);
28226                 ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
28227                 if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_playback, fd, &deviceInfo) == MA_SUCCESS) {
28228                     isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
28229                 }
28230
28231                 close(fd);
28232             }
28233         }
28234
28235         /* Capture. */
28236         if (!isTerminating) {
28237             fd = open(devpath, O_WRONLY, 0);
28238             if (fd >= 0) {
28239                 /* Supports capture. */
28240                 ma_device_info deviceInfo;
28241                 MA_ZERO_OBJECT(&deviceInfo);
28242                 ma_construct_device_id__audio4(deviceInfo.id.audio4, sizeof(deviceInfo.id.audio4), "/dev/audio", iDevice);
28243                 if (ma_context_get_device_info_from_fd__audio4(pContext, ma_device_type_capture, fd, &deviceInfo) == MA_SUCCESS) {
28244                     isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
28245                 }
28246
28247                 close(fd);
28248             }
28249         }
28250
28251         if (isTerminating) {
28252             break;
28253         }
28254     }
28255
28256     return MA_SUCCESS;
28257 }
28258
28259 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)
28260 {
28261     int fd = -1;
28262     int deviceIndex = -1;
28263     char ctlid[256];
28264     ma_result result;
28265
28266     MA_ASSERT(pContext != NULL);
28267
28268     /*
28269     We need to open the "/dev/audioctlN" device to get the info. To do this we need to extract the number
28270     from the device ID which will be in "/dev/audioN" format.
28271     */
28272     if (pDeviceID == NULL) {
28273         /* Default device. */
28274         ma_strcpy_s(ctlid, sizeof(ctlid), "/dev/audioctl");
28275     } else {
28276         /* Specific device. We need to convert from "/dev/audioN" to "/dev/audioctlN". */
28277         result = ma_extract_device_index_from_id__audio4(pDeviceID->audio4, "/dev/audio", &deviceIndex);
28278         if (result != MA_SUCCESS) {
28279             return result;
28280         }
28281
28282         ma_construct_device_id__audio4(ctlid, sizeof(ctlid), "/dev/audioctl", deviceIndex);
28283     }
28284
28285     fd = open(ctlid, (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY, 0);
28286     if (fd == -1) {
28287         return MA_NO_DEVICE;
28288     }
28289
28290     if (deviceIndex == -1) {
28291         ma_strcpy_s(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio");
28292     } else {
28293         ma_construct_device_id__audio4(pDeviceInfo->id.audio4, sizeof(pDeviceInfo->id.audio4), "/dev/audio", deviceIndex);
28294     }
28295
28296     result = ma_context_get_device_info_from_fd__audio4(pContext, deviceType, fd, pDeviceInfo);
28297
28298     close(fd);
28299     return result;
28300 }
28301
28302 static ma_result ma_device_uninit__audio4(ma_device* pDevice)
28303 {
28304     MA_ASSERT(pDevice != NULL);
28305
28306     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28307         close(pDevice->audio4.fdCapture);
28308     }
28309
28310     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28311         close(pDevice->audio4.fdPlayback);
28312     }
28313
28314     return MA_SUCCESS;
28315 }
28316
28317 static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
28318 {
28319     const char* pDefaultDeviceNames[] = {
28320         "/dev/audio",
28321         "/dev/audio0"
28322     };
28323     int fd;
28324     int fdFlags = 0;
28325     ma_format internalFormat;
28326     ma_uint32 internalChannels;
28327     ma_uint32 internalSampleRate;
28328     ma_uint32 internalPeriodSizeInFrames;
28329     ma_uint32 internalPeriods;
28330
28331     MA_ASSERT(pConfig    != NULL);
28332     MA_ASSERT(deviceType != ma_device_type_duplex);
28333     MA_ASSERT(pDevice    != NULL);
28334
28335     /* The first thing to do is open the file. */
28336     if (deviceType == ma_device_type_capture) {
28337         fdFlags = O_RDONLY;
28338     } else {
28339         fdFlags = O_WRONLY;
28340     }
28341     /*fdFlags |= O_NONBLOCK;*/
28342
28343     if (pDescriptor->pDeviceID == NULL) {
28344         /* Default device. */
28345         size_t iDevice;
28346         for (iDevice = 0; iDevice < ma_countof(pDefaultDeviceNames); ++iDevice) {
28347             fd = open(pDefaultDeviceNames[iDevice], fdFlags, 0);
28348             if (fd != -1) {
28349                 break;
28350             }
28351         }
28352     } else {
28353         /* Specific device. */
28354         fd = open(pDescriptor->pDeviceID->audio4, fdFlags, 0);
28355     }
28356
28357     if (fd == -1) {
28358         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to open device.", ma_result_from_errno(errno));
28359     }
28360
28361     #if !defined(MA_AUDIO4_USE_NEW_API)    /* Old API */
28362     {
28363         audio_info_t fdInfo;
28364
28365         /*
28366         The documentation is a little bit unclear to me as to how it handles formats. It says the
28367         following:
28368
28369             Regardless of formats supported by underlying driver, the audio driver accepts the
28370             following formats.
28371
28372         By then the next sentence says this:
28373
28374             `encoding` and `precision` are one of the values obtained by AUDIO_GETENC.
28375
28376         It sounds like a direct contradiction to me. I'm going to play this safe any only use the
28377         best sample format returned by AUDIO_GETENC. If the requested format is supported we'll
28378         use that, but otherwise we'll just use our standard format priorities to pick an
28379         appropriate one.
28380         */
28381         AUDIO_INITINFO(&fdInfo);
28382
28383         /* We get the driver to do as much of the data conversion as possible. */
28384         if (deviceType == ma_device_type_capture) {
28385             fdInfo.mode = AUMODE_RECORD;
28386             ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd, pDescriptor->format), &fdInfo.record.encoding, &fdInfo.record.precision);
28387
28388             if (pDescriptor->channels != 0) {
28389                 fdInfo.record.channels = ma_clamp(pDescriptor->channels, 1, 12);    /* From the documentation: `channels` ranges from 1 to 12. */
28390             }
28391
28392             if (pDescriptor->sampleRate != 0) {
28393                 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`.) */
28394             }
28395         } else {
28396             fdInfo.mode = AUMODE_PLAY;
28397             ma_encoding_from_format__audio4(ma_best_format_from_fd__audio4(fd, pDescriptor->format), &fdInfo.play.encoding, &fdInfo.play.precision);
28398
28399             if (pDescriptor->channels != 0) {
28400                 fdInfo.play.channels = ma_clamp(pDescriptor->channels, 1, 12);    /* From the documentation: `channels` ranges from 1 to 12. */
28401             }
28402
28403             if (pDescriptor->sampleRate != 0) {
28404                 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`.) */
28405             }
28406         }
28407
28408         if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) {
28409             close(fd);
28410             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device format. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED);
28411         }
28412
28413         if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) {
28414             close(fd);
28415             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] AUDIO_GETINFO failed.", MA_FORMAT_NOT_SUPPORTED);
28416         }
28417
28418         if (deviceType == ma_device_type_capture) {
28419             internalFormat     = ma_format_from_prinfo__audio4(&fdInfo.record);
28420             internalChannels   = fdInfo.record.channels;
28421             internalSampleRate = fdInfo.record.sample_rate;
28422         } else {
28423             internalFormat     = ma_format_from_prinfo__audio4(&fdInfo.play);
28424             internalChannels   = fdInfo.play.channels;
28425             internalSampleRate = fdInfo.play.sample_rate;
28426         }
28427
28428         if (internalFormat == ma_format_unknown) {
28429             close(fd);
28430             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED);
28431         }
28432
28433         /* Buffer. */
28434         {
28435             ma_uint32 internalPeriodSizeInBytes;
28436
28437             internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile);
28438
28439             internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels);
28440             if (internalPeriodSizeInBytes < 16) {
28441                 internalPeriodSizeInBytes = 16;
28442             }
28443
28444             internalPeriods = pDescriptor->periodCount;
28445             if (internalPeriods < 2) {
28446                 internalPeriods = 2;
28447             }
28448
28449             /* What miniaudio calls a period, audio4 calls a block. */
28450             AUDIO_INITINFO(&fdInfo);
28451             fdInfo.hiwat     = internalPeriods;
28452             fdInfo.lowat     = internalPeriods-1;
28453             fdInfo.blocksize = internalPeriodSizeInBytes;
28454             if (ioctl(fd, AUDIO_SETINFO, &fdInfo) < 0) {
28455                 close(fd);
28456                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set internal buffer size. AUDIO_SETINFO failed.", MA_FORMAT_NOT_SUPPORTED);
28457             }
28458
28459             internalPeriods            = fdInfo.hiwat;
28460             internalPeriodSizeInFrames = fdInfo.blocksize / ma_get_bytes_per_frame(internalFormat, internalChannels);
28461         }
28462     }
28463     #else
28464     {
28465         struct audio_swpar fdPar;
28466
28467         /* 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. */
28468         if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
28469             close(fd);
28470             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve initial device parameters.", MA_FORMAT_NOT_SUPPORTED);
28471         }
28472
28473         internalFormat     = ma_format_from_swpar__audio4(&fdPar);
28474         internalChannels   = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan;
28475         internalSampleRate = fdPar.rate;
28476
28477         if (internalFormat == ma_format_unknown) {
28478             close(fd);
28479             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED);
28480         }
28481
28482         /* Buffer. */
28483         {
28484             ma_uint32 internalPeriodSizeInBytes;
28485
28486             internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile);
28487
28488             /* What miniaudio calls a period, audio4 calls a block. */
28489             internalPeriodSizeInBytes = internalPeriodSizeInFrames * ma_get_bytes_per_frame(internalFormat, internalChannels);
28490             if (internalPeriodSizeInBytes < 16) {
28491                 internalPeriodSizeInBytes = 16;
28492             }
28493
28494             fdPar.nblks = pDescriptor->periodCount;
28495             fdPar.round = internalPeriodSizeInBytes;
28496
28497             if (ioctl(fd, AUDIO_SETPAR, &fdPar) < 0) {
28498                 close(fd);
28499                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to set device parameters.", MA_FORMAT_NOT_SUPPORTED);
28500             }
28501
28502             if (ioctl(fd, AUDIO_GETPAR, &fdPar) < 0) {
28503                 close(fd);
28504                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to retrieve actual device parameters.", MA_FORMAT_NOT_SUPPORTED);
28505             }
28506         }
28507
28508         internalFormat             = ma_format_from_swpar__audio4(&fdPar);
28509         internalChannels           = (deviceType == ma_device_type_capture) ? fdPar.rchan : fdPar.pchan;
28510         internalSampleRate         = fdPar.rate;
28511         internalPeriods            = fdPar.nblks;
28512         internalPeriodSizeInFrames = fdPar.round / ma_get_bytes_per_frame(internalFormat, internalChannels);
28513     }
28514     #endif
28515
28516     if (internalFormat == ma_format_unknown) {
28517         close(fd);
28518         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] The device's internal device format is not supported by miniaudio. The device is unusable.", MA_FORMAT_NOT_SUPPORTED);
28519     }
28520
28521     if (deviceType == ma_device_type_capture) {
28522         pDevice->audio4.fdCapture  = fd;
28523     } else {
28524         pDevice->audio4.fdPlayback = fd;
28525     }
28526
28527     pDescriptor->format             = internalFormat;
28528     pDescriptor->channels           = internalChannels;
28529     pDescriptor->sampleRate         = internalSampleRate;
28530     ma_get_standard_channel_map(ma_standard_channel_map_sound4, internalChannels, pDescriptor->channelMap);
28531     pDescriptor->periodSizeInFrames = internalPeriodSizeInFrames;
28532     pDescriptor->periodCount        = internalPeriods;
28533
28534     return MA_SUCCESS;
28535 }
28536
28537 static ma_result ma_device_init__audio4(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
28538 {
28539     MA_ASSERT(pDevice != NULL);
28540
28541     MA_ZERO_OBJECT(&pDevice->audio4);
28542
28543     if (pConfig->deviceType == ma_device_type_loopback) {
28544         return MA_DEVICE_TYPE_NOT_SUPPORTED;
28545     }
28546
28547     pDevice->audio4.fdCapture  = -1;
28548     pDevice->audio4.fdPlayback = -1;
28549
28550     /*
28551     The version of the operating system dictates whether or not the device is exclusive or shared. NetBSD
28552     introduced in-kernel mixing which means it's shared. All other BSD flavours are exclusive as far as
28553     I'm aware.
28554     */
28555 #if defined(__NetBSD_Version__) && __NetBSD_Version__ >= 800000000
28556     /* NetBSD 8.0+ */
28557     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
28558         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
28559         return MA_SHARE_MODE_NOT_SUPPORTED;
28560     }
28561 #else
28562     /* All other flavors. */
28563 #endif
28564
28565     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
28566         ma_result result = ma_device_init_fd__audio4(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
28567         if (result != MA_SUCCESS) {
28568             return result;
28569         }
28570     }
28571
28572     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
28573         ma_result result = ma_device_init_fd__audio4(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
28574         if (result != MA_SUCCESS) {
28575             if (pConfig->deviceType == ma_device_type_duplex) {
28576                 close(pDevice->audio4.fdCapture);
28577             }
28578             return result;
28579         }
28580     }
28581
28582     return MA_SUCCESS;
28583 }
28584
28585 static ma_result ma_device_start__audio4(ma_device* pDevice)
28586 {
28587     MA_ASSERT(pDevice != NULL);
28588
28589     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28590         if (pDevice->audio4.fdCapture == -1) {
28591             return MA_INVALID_ARGS;
28592         }
28593     }
28594
28595     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28596         if (pDevice->audio4.fdPlayback == -1) {
28597             return MA_INVALID_ARGS;
28598         }
28599     }
28600
28601     return MA_SUCCESS;
28602 }
28603
28604 static ma_result ma_device_stop_fd__audio4(ma_device* pDevice, int fd)
28605 {
28606     if (fd == -1) {
28607         return MA_INVALID_ARGS;
28608     }
28609
28610 #if !defined(MA_AUDIO4_USE_NEW_API)
28611     if (ioctl(fd, AUDIO_FLUSH, 0) < 0) {
28612         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_FLUSH failed.", ma_result_from_errno(errno));
28613     }
28614 #else
28615     if (ioctl(fd, AUDIO_STOP, 0) < 0) {
28616         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to stop device. AUDIO_STOP failed.", ma_result_from_errno(errno));
28617     }
28618 #endif
28619
28620     return MA_SUCCESS;
28621 }
28622
28623 static ma_result ma_device_stop__audio4(ma_device* pDevice)
28624 {
28625     MA_ASSERT(pDevice != NULL);
28626
28627     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
28628         ma_result result;
28629
28630         result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdCapture);
28631         if (result != MA_SUCCESS) {
28632             return result;
28633         }
28634     }
28635
28636     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
28637         ma_result result;
28638
28639         /* 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. */
28640     #if !defined(MA_AUDIO4_USE_NEW_API)
28641         ioctl(pDevice->audio4.fdPlayback, AUDIO_DRAIN, 0);
28642     #endif
28643
28644         /* Here is where the device is stopped immediately. */
28645         result = ma_device_stop_fd__audio4(pDevice, pDevice->audio4.fdPlayback);
28646         if (result != MA_SUCCESS) {
28647             return result;
28648         }
28649     }
28650
28651     return MA_SUCCESS;
28652 }
28653
28654 static ma_result ma_device_write__audio4(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
28655 {
28656     int result;
28657
28658     if (pFramesWritten != NULL) {
28659         *pFramesWritten = 0;
28660     }
28661
28662     result = write(pDevice->audio4.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
28663     if (result < 0) {
28664         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to write data to the device.", ma_result_from_errno(errno));
28665     }
28666
28667     if (pFramesWritten != NULL) {
28668         *pFramesWritten = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
28669     }
28670
28671     return MA_SUCCESS;
28672 }
28673
28674 static ma_result ma_device_read__audio4(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
28675 {
28676     int result;
28677
28678     if (pFramesRead != NULL) {
28679         *pFramesRead = 0;
28680     }
28681
28682     result = read(pDevice->audio4.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
28683     if (result < 0) {
28684         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[audio4] Failed to read data from the device.", ma_result_from_errno(errno));
28685     }
28686
28687     if (pFramesRead != NULL) {
28688         *pFramesRead = (ma_uint32)result / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
28689     }
28690
28691     return MA_SUCCESS;
28692 }
28693
28694 static ma_result ma_context_uninit__audio4(ma_context* pContext)
28695 {
28696     MA_ASSERT(pContext != NULL);
28697     MA_ASSERT(pContext->backend == ma_backend_audio4);
28698
28699     (void)pContext;
28700     return MA_SUCCESS;
28701 }
28702
28703 static ma_result ma_context_init__audio4(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
28704 {
28705     MA_ASSERT(pContext != NULL);
28706
28707     (void)pConfig;
28708
28709     pCallbacks->onContextInit             = ma_context_init__audio4;
28710     pCallbacks->onContextUninit           = ma_context_uninit__audio4;
28711     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__audio4;
28712     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__audio4;
28713     pCallbacks->onDeviceInit              = ma_device_init__audio4;
28714     pCallbacks->onDeviceUninit            = ma_device_uninit__audio4;
28715     pCallbacks->onDeviceStart             = ma_device_start__audio4;
28716     pCallbacks->onDeviceStop              = ma_device_stop__audio4;
28717     pCallbacks->onDeviceRead              = ma_device_read__audio4;
28718     pCallbacks->onDeviceWrite             = ma_device_write__audio4;
28719     pCallbacks->onDeviceDataLoop          = NULL;
28720
28721     return MA_SUCCESS;
28722 }
28723 #endif  /* audio4 */
28724
28725
28726 /******************************************************************************
28727
28728 OSS Backend
28729
28730 ******************************************************************************/
28731 #ifdef MA_HAS_OSS
28732 #include <sys/ioctl.h>
28733 #include <unistd.h>
28734 #include <fcntl.h>
28735 #include <sys/soundcard.h>
28736
28737 #ifndef SNDCTL_DSP_HALT
28738 #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET
28739 #endif
28740
28741 #define MA_OSS_DEFAULT_DEVICE_NAME  "/dev/dsp"
28742
28743 static int ma_open_temp_device__oss()
28744 {
28745     /* The OSS sample code uses "/dev/mixer" as the device for getting system properties so I'm going to do the same. */
28746     int fd = open("/dev/mixer", O_RDONLY, 0);
28747     if (fd >= 0) {
28748         return fd;
28749     }
28750
28751     return -1;
28752 }
28753
28754 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)
28755 {
28756     const char* deviceName;
28757     int flags;
28758
28759     MA_ASSERT(pContext != NULL);
28760     MA_ASSERT(pfd != NULL);
28761     (void)pContext;
28762
28763     *pfd = -1;
28764
28765     /* This function should only be called for playback or capture, not duplex. */
28766     if (deviceType == ma_device_type_duplex) {
28767         return MA_INVALID_ARGS;
28768     }
28769
28770     deviceName = MA_OSS_DEFAULT_DEVICE_NAME;
28771     if (pDeviceID != NULL) {
28772         deviceName = pDeviceID->oss;
28773     }
28774
28775     flags = (deviceType == ma_device_type_playback) ? O_WRONLY : O_RDONLY;
28776     if (shareMode == ma_share_mode_exclusive) {
28777         flags |= O_EXCL;
28778     }
28779
28780     *pfd = open(deviceName, flags, 0);
28781     if (*pfd == -1) {
28782         return ma_result_from_errno(errno);
28783     }
28784
28785     return MA_SUCCESS;
28786 }
28787
28788 static ma_result ma_context_enumerate_devices__oss(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
28789 {
28790     int fd;
28791     oss_sysinfo si;
28792     int result;
28793
28794     MA_ASSERT(pContext != NULL);
28795     MA_ASSERT(callback != NULL);
28796
28797     fd = ma_open_temp_device__oss();
28798     if (fd == -1) {
28799         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND);
28800     }
28801
28802     result = ioctl(fd, SNDCTL_SYSINFO, &si);
28803     if (result != -1) {
28804         int iAudioDevice;
28805         for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) {
28806             oss_audioinfo ai;
28807             ai.dev = iAudioDevice;
28808             result = ioctl(fd, SNDCTL_AUDIOINFO, &ai);
28809             if (result != -1) {
28810                 if (ai.devnode[0] != '\0') {    /* <-- Can be blank, according to documentation. */
28811                     ma_device_info deviceInfo;
28812                     ma_bool32 isTerminating = MA_FALSE;
28813
28814                     MA_ZERO_OBJECT(&deviceInfo);
28815
28816                     /* ID */
28817                     ma_strncpy_s(deviceInfo.id.oss, sizeof(deviceInfo.id.oss), ai.devnode, (size_t)-1);
28818
28819                     /*
28820                     The human readable device name should be in the "ai.handle" variable, but it can
28821                     sometimes be empty in which case we just fall back to "ai.name" which is less user
28822                     friendly, but usually has a value.
28823                     */
28824                     if (ai.handle[0] != '\0') {
28825                         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.handle, (size_t)-1);
28826                     } else {
28827                         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), ai.name, (size_t)-1);
28828                     }
28829
28830                     /* The device can be both playback and capture. */
28831                     if (!isTerminating && (ai.caps & PCM_CAP_OUTPUT) != 0) {
28832                         isTerminating = !callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
28833                     }
28834                     if (!isTerminating && (ai.caps & PCM_CAP_INPUT) != 0) {
28835                         isTerminating = !callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
28836                     }
28837
28838                     if (isTerminating) {
28839                         break;
28840                     }
28841                 }
28842             }
28843         }
28844     } else {
28845         close(fd);
28846         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND);
28847     }
28848
28849     close(fd);
28850     return MA_SUCCESS;
28851 }
28852
28853 static void ma_context_add_native_data_format__oss(ma_context* pContext, oss_audioinfo* pAudioInfo, ma_format format, ma_device_info* pDeviceInfo)
28854 {
28855     unsigned int minChannels;
28856     unsigned int maxChannels;
28857     unsigned int iRate;
28858
28859     MA_ASSERT(pContext    != NULL);
28860     MA_ASSERT(pAudioInfo  != NULL);
28861     MA_ASSERT(pDeviceInfo != NULL);
28862
28863     /* If we support all channels we just report 0. */
28864     minChannels = ma_clamp(pAudioInfo->min_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
28865     maxChannels = ma_clamp(pAudioInfo->max_channels, MA_MIN_CHANNELS, MA_MAX_CHANNELS);
28866
28867     /*
28868     OSS has this annoying thing where sample rates can be reported in two ways. We prefer explicitness,
28869     which OSS has in the form of nrates/rates, however there are times where nrates can be 0, in which
28870     case we'll need to use min_rate and max_rate and report only standard rates.
28871     */
28872     if (pAudioInfo->nrates > 0) {
28873         for (iRate = 0; iRate < pAudioInfo->nrates; iRate += 1) {
28874             unsigned int rate = pAudioInfo->rates[iRate];
28875
28876             if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
28877                 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. */
28878             } else {
28879                 unsigned int iChannel;
28880                 for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
28881                      ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, rate, 0);
28882                 }
28883             }
28884         }
28885     } else {
28886         for (iRate = 0; iRate < ma_countof(g_maStandardSampleRatePriorities); iRate += 1) {
28887             ma_uint32 standardRate = g_maStandardSampleRatePriorities[iRate];
28888
28889             if (standardRate >= (ma_uint32)pAudioInfo->min_rate && standardRate <= (ma_uint32)pAudioInfo->max_rate) {
28890                 if (minChannels == MA_MIN_CHANNELS && maxChannels == MA_MAX_CHANNELS) {
28891                     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. */
28892                 } else {
28893                     unsigned int iChannel;
28894                     for (iChannel = minChannels; iChannel <= maxChannels; iChannel += 1) {
28895                          ma_device_info_add_native_data_format(pDeviceInfo, format, iChannel, standardRate, 0);
28896                     }
28897                 }
28898             }
28899         }
28900     }
28901 }
28902
28903 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)
28904 {
28905     ma_bool32 foundDevice;
28906     int fdTemp;
28907     oss_sysinfo si;
28908     int result;
28909
28910     MA_ASSERT(pContext != NULL);
28911
28912     /* Handle the default device a little differently. */
28913     if (pDeviceID == NULL) {
28914         if (deviceType == ma_device_type_playback) {
28915             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
28916         } else {
28917             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
28918         }
28919
28920         return MA_SUCCESS;
28921     }
28922
28923
28924     /* If we get here it means we are _not_ using the default device. */
28925     foundDevice = MA_FALSE;
28926
28927     fdTemp = ma_open_temp_device__oss();
28928     if (fdTemp == -1) {
28929         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open a temporary device for retrieving system information used for device enumeration.", MA_NO_BACKEND);
28930     }
28931
28932     result = ioctl(fdTemp, SNDCTL_SYSINFO, &si);
28933     if (result != -1) {
28934         int iAudioDevice;
28935         for (iAudioDevice = 0; iAudioDevice < si.numaudios; ++iAudioDevice) {
28936             oss_audioinfo ai;
28937             ai.dev = iAudioDevice;
28938             result = ioctl(fdTemp, SNDCTL_AUDIOINFO, &ai);
28939             if (result != -1) {
28940                 if (ma_strcmp(ai.devnode, pDeviceID->oss) == 0) {
28941                     /* It has the same name, so now just confirm the type. */
28942                     if ((deviceType == ma_device_type_playback && ((ai.caps & PCM_CAP_OUTPUT) != 0)) ||
28943                         (deviceType == ma_device_type_capture  && ((ai.caps & PCM_CAP_INPUT)  != 0))) {
28944                         unsigned int formatMask;
28945
28946                         /* ID */
28947                         ma_strncpy_s(pDeviceInfo->id.oss, sizeof(pDeviceInfo->id.oss), ai.devnode, (size_t)-1);
28948
28949                         /*
28950                         The human readable device name should be in the "ai.handle" variable, but it can
28951                         sometimes be empty in which case we just fall back to "ai.name" which is less user
28952                         friendly, but usually has a value.
28953                         */
28954                         if (ai.handle[0] != '\0') {
28955                             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.handle, (size_t)-1);
28956                         } else {
28957                             ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), ai.name, (size_t)-1);
28958                         }
28959
28960
28961                         pDeviceInfo->nativeDataFormatCount = 0;
28962
28963                         if (deviceType == ma_device_type_playback) {
28964                             formatMask = ai.oformats;
28965                         } else {
28966                             formatMask = ai.iformats;
28967                         }
28968
28969                         if (((formatMask & AFMT_S16_LE) != 0 && ma_is_little_endian()) || (AFMT_S16_BE && ma_is_big_endian())) {
28970                             ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s16, pDeviceInfo);
28971                         }
28972                         if (((formatMask & AFMT_S32_LE) != 0 && ma_is_little_endian()) || (AFMT_S32_BE && ma_is_big_endian())) {
28973                             ma_context_add_native_data_format__oss(pContext, &ai, ma_format_s32, pDeviceInfo);
28974                         }
28975                         if ((formatMask & AFMT_U8) != 0) {
28976                             ma_context_add_native_data_format__oss(pContext, &ai, ma_format_u8, pDeviceInfo);
28977                         }
28978
28979                         foundDevice = MA_TRUE;
28980                         break;
28981                     }
28982                 }
28983             }
28984         }
28985     } else {
28986         close(fdTemp);
28987         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve system information for device enumeration.", MA_NO_BACKEND);
28988     }
28989
28990
28991     close(fdTemp);
28992
28993     if (!foundDevice) {
28994         return MA_NO_DEVICE;
28995     }
28996
28997     return MA_SUCCESS;
28998 }
28999
29000 static ma_result ma_device_uninit__oss(ma_device* pDevice)
29001 {
29002     MA_ASSERT(pDevice != NULL);
29003
29004     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
29005         close(pDevice->oss.fdCapture);
29006     }
29007
29008     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
29009         close(pDevice->oss.fdPlayback);
29010     }
29011
29012     return MA_SUCCESS;
29013 }
29014
29015 static int ma_format_to_oss(ma_format format)
29016 {
29017     int ossFormat = AFMT_U8;
29018     switch (format) {
29019         case ma_format_s16: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break;
29020         case ma_format_s24: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break;
29021         case ma_format_s32: ossFormat = (ma_is_little_endian()) ? AFMT_S32_LE : AFMT_S32_BE; break;
29022         case ma_format_f32: ossFormat = (ma_is_little_endian()) ? AFMT_S16_LE : AFMT_S16_BE; break;
29023         case ma_format_u8:
29024         default: ossFormat = AFMT_U8; break;
29025     }
29026
29027     return ossFormat;
29028 }
29029
29030 static ma_format ma_format_from_oss(int ossFormat)
29031 {
29032     if (ossFormat == AFMT_U8) {
29033         return ma_format_u8;
29034     } else {
29035         if (ma_is_little_endian()) {
29036             switch (ossFormat) {
29037                 case AFMT_S16_LE: return ma_format_s16;
29038                 case AFMT_S32_LE: return ma_format_s32;
29039                 default: return ma_format_unknown;
29040             }
29041         } else {
29042             switch (ossFormat) {
29043                 case AFMT_S16_BE: return ma_format_s16;
29044                 case AFMT_S32_BE: return ma_format_s32;
29045                 default: return ma_format_unknown;
29046             }
29047         }
29048     }
29049
29050     return ma_format_unknown;
29051 }
29052
29053 static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptor, ma_device_type deviceType)
29054 {
29055     ma_result result;
29056     int ossResult;
29057     int fd;
29058     const ma_device_id* pDeviceID = NULL;
29059     ma_share_mode shareMode;
29060     int ossFormat;
29061     int ossChannels;
29062     int ossSampleRate;
29063     int ossFragment;
29064
29065     MA_ASSERT(pDevice != NULL);
29066     MA_ASSERT(pConfig != NULL);
29067     MA_ASSERT(deviceType != ma_device_type_duplex);
29068     
29069     pDeviceID     = pDescriptor->pDeviceID;
29070     shareMode     = pDescriptor->shareMode;
29071     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. */
29072     ossChannels   = (int)(pDescriptor->channels   > 0) ? pDescriptor->channels   : MA_DEFAULT_CHANNELS;
29073     ossSampleRate = (int)(pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE;
29074
29075     result = ma_context_open_device__oss(pDevice->pContext, deviceType, pDeviceID, shareMode, &fd);
29076     if (result != MA_SUCCESS) {
29077         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
29078     }
29079
29080     /*
29081     The OSS documantation is very clear about the order we should be initializing the device's properties:
29082       1) Format
29083       2) Channels
29084       3) Sample rate.
29085     */
29086
29087     /* Format. */
29088     ossResult = ioctl(fd, SNDCTL_DSP_SETFMT, &ossFormat);
29089     if (ossResult == -1) {
29090         close(fd);
29091         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set format.", MA_FORMAT_NOT_SUPPORTED);
29092     }
29093
29094     /* Channels. */
29095     ossResult = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossChannels);
29096     if (ossResult == -1) {
29097         close(fd);
29098         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set channel count.", MA_FORMAT_NOT_SUPPORTED);
29099     }
29100
29101     /* Sample Rate. */
29102     ossResult = ioctl(fd, SNDCTL_DSP_SPEED, &ossSampleRate);
29103     if (ossResult == -1) {
29104         close(fd);
29105         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set sample rate.", MA_FORMAT_NOT_SUPPORTED);
29106     }
29107
29108     /*
29109     Buffer.
29110
29111     The documentation says that the fragment settings should be set as soon as possible, but I'm not sure if
29112     it should be done before or after format/channels/rate.
29113
29114     OSS wants the fragment size in bytes and a power of 2. When setting, we specify the power, not the actual
29115     value.
29116     */
29117     {
29118         ma_uint32 periodSizeInFrames;
29119         ma_uint32 periodSizeInBytes;
29120         ma_uint32 ossFragmentSizePower;
29121
29122         periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, (ma_uint32)ossSampleRate, pConfig->performanceProfile);
29123
29124         periodSizeInBytes = ma_round_to_power_of_2(periodSizeInFrames * ma_get_bytes_per_frame(ma_format_from_oss(ossFormat), ossChannels));
29125         if (periodSizeInBytes < 16) {
29126             periodSizeInBytes = 16;
29127         }
29128
29129         ossFragmentSizePower = 4;
29130         periodSizeInBytes >>= 4;
29131         while (periodSizeInBytes >>= 1) {
29132             ossFragmentSizePower += 1;
29133         }
29134
29135         ossFragment = (int)((pConfig->periods << 16) | ossFragmentSizePower);
29136         ossResult = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossFragment);
29137         if (ossResult == -1) {
29138             close(fd);
29139             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to set fragment size and period count.", MA_FORMAT_NOT_SUPPORTED);
29140         }
29141     }
29142
29143     /* Internal settings. */
29144     if (deviceType == ma_device_type_capture) {
29145         pDevice->oss.fdCapture  = fd;
29146     } else {
29147         pDevice->oss.fdPlayback = fd;
29148     }
29149
29150     pDescriptor->format             = ma_format_from_oss(ossFormat);
29151     pDescriptor->channels           = ossChannels;
29152     pDescriptor->sampleRate         = ossSampleRate;
29153     ma_get_standard_channel_map(ma_standard_channel_map_sound4, pDescriptor->channels, pDescriptor->channelMap);
29154     pDescriptor->periodCount        = (ma_uint32)(ossFragment >> 16);
29155     pDescriptor->periodSizeInFrames = (ma_uint32)(1 << (ossFragment & 0xFFFF)) / ma_get_bytes_per_frame(pDescriptor->format, pDescriptor->channels);
29156
29157     if (pDescriptor->format == ma_format_unknown) {
29158         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] The device's internal format is not supported by miniaudio.", MA_FORMAT_NOT_SUPPORTED);
29159     }
29160
29161     return MA_SUCCESS;
29162 }
29163
29164 static ma_result ma_device_init__oss(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
29165 {
29166     MA_ASSERT(pDevice  != NULL);
29167     MA_ASSERT(pConfig  != NULL);
29168
29169     MA_ZERO_OBJECT(&pDevice->oss);
29170
29171     if (pConfig->deviceType == ma_device_type_loopback) {
29172         return MA_DEVICE_TYPE_NOT_SUPPORTED;
29173     }
29174
29175     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
29176         ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
29177         if (result != MA_SUCCESS) {
29178             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
29179         }
29180     }
29181
29182     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
29183         ma_result result = ma_device_init_fd__oss(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
29184         if (result != MA_SUCCESS) {
29185             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open device.", result);
29186         }
29187     }
29188
29189     return MA_SUCCESS;
29190 }
29191
29192 /*
29193 Note on Starting and Stopping
29194 =============================
29195 In the past I was using SNDCTL_DSP_HALT to stop the device, however this results in issues when
29196 trying to resume the device again. If we use SNDCTL_DSP_HALT, the next write() or read() will
29197 fail. Instead what we need to do is just not write or read to and from the device when the
29198 device is not running.
29199
29200 As a result, both the start and stop functions for OSS are just empty stubs. The starting and
29201 stopping logic is handled by ma_device_write__oss() and ma_device_read__oss(). These will check
29202 the device state, and if the device is stopped they will simply not do any kind of processing.
29203
29204 The downside to this technique is that I've noticed a fairly lengthy delay in stopping the
29205 device, up to a second. This is on a virtual machine, and as such might just be due to the
29206 virtual drivers, but I'm not fully sure. I am not sure how to work around this problem so for
29207 the moment that's just how it's going to have to be.
29208
29209 When starting the device, OSS will automatically start it when write() or read() is called.
29210 */
29211 static ma_result ma_device_start__oss(ma_device* pDevice)
29212 {
29213     MA_ASSERT(pDevice != NULL);
29214
29215     /* The device is automatically started with reading and writing. */
29216     (void)pDevice;
29217
29218     return MA_SUCCESS;
29219 }
29220
29221 static ma_result ma_device_stop__oss(ma_device* pDevice)
29222 {
29223     MA_ASSERT(pDevice != NULL);
29224
29225     /* See note above on why this is empty. */
29226     (void)pDevice;
29227
29228     return MA_SUCCESS;
29229 }
29230
29231 static ma_result ma_device_write__oss(ma_device* pDevice, const void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
29232 {
29233     int resultOSS;
29234     ma_uint32 deviceState;
29235
29236     if (pFramesWritten != NULL) {
29237         *pFramesWritten = 0;
29238     }
29239
29240     /* Don't do any processing if the device is stopped. */
29241     deviceState = ma_device_get_state(pDevice);
29242     if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) {
29243         return MA_SUCCESS;
29244     }
29245
29246     resultOSS = write(pDevice->oss.fdPlayback, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
29247     if (resultOSS < 0) {
29248         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to send data from the client to the device.", ma_result_from_errno(errno));
29249     }
29250
29251     if (pFramesWritten != NULL) {
29252         *pFramesWritten = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
29253     }
29254
29255     return MA_SUCCESS;
29256 }
29257
29258 static ma_result ma_device_read__oss(ma_device* pDevice, void* pPCMFrames, ma_uint32 frameCount, ma_uint32* pFramesRead)
29259 {
29260     int resultOSS;
29261     ma_uint32 deviceState;
29262
29263     if (pFramesRead != NULL) {
29264         *pFramesRead = 0;
29265     }
29266
29267     /* Don't do any processing if the device is stopped. */
29268     deviceState = ma_device_get_state(pDevice);
29269     if (deviceState != MA_STATE_STARTED && deviceState != MA_STATE_STARTING) {
29270         return MA_SUCCESS;
29271     }
29272
29273     resultOSS = read(pDevice->oss.fdCapture, pPCMFrames, frameCount * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels));
29274     if (resultOSS < 0) {
29275         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OSS] Failed to read data from the device to be sent to the client.", ma_result_from_errno(errno));
29276     }
29277
29278     if (pFramesRead != NULL) {
29279         *pFramesRead = (ma_uint32)resultOSS / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
29280     }
29281
29282     return MA_SUCCESS;
29283 }
29284
29285 static ma_result ma_context_uninit__oss(ma_context* pContext)
29286 {
29287     MA_ASSERT(pContext != NULL);
29288     MA_ASSERT(pContext->backend == ma_backend_oss);
29289
29290     (void)pContext;
29291     return MA_SUCCESS;
29292 }
29293
29294 static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
29295 {
29296     int fd;
29297     int ossVersion;
29298     int result;
29299
29300     MA_ASSERT(pContext != NULL);
29301
29302     (void)pConfig;
29303
29304     /* Try opening a temporary device first so we can get version information. This is closed at the end. */
29305     fd = ma_open_temp_device__oss();
29306     if (fd == -1) {
29307         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to open temporary device for retrieving system properties.", MA_NO_BACKEND);   /* Looks liks OSS isn't installed, or there are no available devices. */
29308     }
29309
29310     /* Grab the OSS version. */
29311     ossVersion = 0;
29312     result = ioctl(fd, OSS_GETVERSION, &ossVersion);
29313     if (result == -1) {
29314         close(fd);
29315         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[OSS] Failed to retrieve OSS version.", MA_NO_BACKEND);
29316     }
29317
29318     /* The file handle to temp device is no longer needed. Close ASAP. */
29319     close(fd);
29320
29321     pContext->oss.versionMajor = ((ossVersion & 0xFF0000) >> 16);
29322     pContext->oss.versionMinor = ((ossVersion & 0x00FF00) >> 8);
29323
29324     pCallbacks->onContextInit             = ma_context_init__oss;
29325     pCallbacks->onContextUninit           = ma_context_uninit__oss;
29326     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__oss;
29327     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__oss;
29328     pCallbacks->onDeviceInit              = ma_device_init__oss;
29329     pCallbacks->onDeviceUninit            = ma_device_uninit__oss;
29330     pCallbacks->onDeviceStart             = ma_device_start__oss;
29331     pCallbacks->onDeviceStop              = ma_device_stop__oss;
29332     pCallbacks->onDeviceRead              = ma_device_read__oss;
29333     pCallbacks->onDeviceWrite             = ma_device_write__oss;
29334     pCallbacks->onDeviceDataLoop          = NULL;
29335
29336     return MA_SUCCESS;
29337 }
29338 #endif  /* OSS */
29339
29340
29341 /******************************************************************************
29342
29343 AAudio Backend
29344
29345 ******************************************************************************/
29346 #ifdef MA_HAS_AAUDIO
29347
29348 /*#include <AAudio/AAudio.h>*/
29349
29350 typedef int32_t                                         ma_aaudio_result_t;
29351 typedef int32_t                                         ma_aaudio_direction_t;
29352 typedef int32_t                                         ma_aaudio_sharing_mode_t;
29353 typedef int32_t                                         ma_aaudio_format_t;
29354 typedef int32_t                                         ma_aaudio_stream_state_t;
29355 typedef int32_t                                         ma_aaudio_performance_mode_t;
29356 typedef int32_t                                         ma_aaudio_usage_t;
29357 typedef int32_t                                         ma_aaudio_content_type_t;
29358 typedef int32_t                                         ma_aaudio_input_preset_t;
29359 typedef int32_t                                         ma_aaudio_data_callback_result_t;
29360 typedef struct ma_AAudioStreamBuilder_t*                ma_AAudioStreamBuilder;
29361 typedef struct ma_AAudioStream_t*                       ma_AAudioStream;
29362
29363 #define MA_AAUDIO_UNSPECIFIED                           0
29364
29365 /* Result codes. miniaudio only cares about the success code. */
29366 #define MA_AAUDIO_OK                                    0
29367
29368 /* Directions. */
29369 #define MA_AAUDIO_DIRECTION_OUTPUT                      0
29370 #define MA_AAUDIO_DIRECTION_INPUT                       1
29371
29372 /* Sharing modes. */
29373 #define MA_AAUDIO_SHARING_MODE_EXCLUSIVE                0
29374 #define MA_AAUDIO_SHARING_MODE_SHARED                   1
29375
29376 /* Formats. */
29377 #define MA_AAUDIO_FORMAT_PCM_I16                        1
29378 #define MA_AAUDIO_FORMAT_PCM_FLOAT                      2
29379
29380 /* Stream states. */
29381 #define MA_AAUDIO_STREAM_STATE_UNINITIALIZED            0
29382 #define MA_AAUDIO_STREAM_STATE_UNKNOWN                  1
29383 #define MA_AAUDIO_STREAM_STATE_OPEN                     2
29384 #define MA_AAUDIO_STREAM_STATE_STARTING                 3
29385 #define MA_AAUDIO_STREAM_STATE_STARTED                  4
29386 #define MA_AAUDIO_STREAM_STATE_PAUSING                  5
29387 #define MA_AAUDIO_STREAM_STATE_PAUSED                   6
29388 #define MA_AAUDIO_STREAM_STATE_FLUSHING                 7
29389 #define MA_AAUDIO_STREAM_STATE_FLUSHED                  8
29390 #define MA_AAUDIO_STREAM_STATE_STOPPING                 9
29391 #define MA_AAUDIO_STREAM_STATE_STOPPED                  10
29392 #define MA_AAUDIO_STREAM_STATE_CLOSING                  11
29393 #define MA_AAUDIO_STREAM_STATE_CLOSED                   12
29394 #define MA_AAUDIO_STREAM_STATE_DISCONNECTED             13
29395
29396 /* Performance modes. */
29397 #define MA_AAUDIO_PERFORMANCE_MODE_NONE                 10
29398 #define MA_AAUDIO_PERFORMANCE_MODE_POWER_SAVING         11
29399 #define MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY          12
29400
29401 /* Usage types. */
29402 #define MA_AAUDIO_USAGE_MEDIA                           1
29403 #define MA_AAUDIO_USAGE_VOICE_COMMUNICATION             2
29404 #define MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING  3
29405 #define MA_AAUDIO_USAGE_ALARM                           4
29406 #define MA_AAUDIO_USAGE_NOTIFICATION                    5
29407 #define MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE           6
29408 #define MA_AAUDIO_USAGE_NOTIFICATION_EVENT              10
29409 #define MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY        11
29410 #define MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE  12
29411 #define MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION         13
29412 #define MA_AAUDIO_USAGE_GAME                            14
29413 #define MA_AAUDIO_USAGE_ASSISTANT                       16
29414 #define MA_AAUDIO_SYSTEM_USAGE_EMERGENCY                1000
29415 #define MA_AAUDIO_SYSTEM_USAGE_SAFETY                   1001
29416 #define MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS           1002
29417 #define MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT             1003
29418
29419 /* Content types. */
29420 #define MA_AAUDIO_CONTENT_TYPE_SPEECH                   1
29421 #define MA_AAUDIO_CONTENT_TYPE_MUSIC                    2
29422 #define MA_AAUDIO_CONTENT_TYPE_MOVIE                    3
29423 #define MA_AAUDIO_CONTENT_TYPE_SONIFICATION             4
29424
29425 /* Input presets. */
29426 #define MA_AAUDIO_INPUT_PRESET_GENERIC                  1
29427 #define MA_AAUDIO_INPUT_PRESET_CAMCORDER                5
29428 #define MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION        6
29429 #define MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION      7
29430 #define MA_AAUDIO_INPUT_PRESET_UNPROCESSED              9
29431 #define MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE        10
29432
29433 /* Callback results. */
29434 #define MA_AAUDIO_CALLBACK_RESULT_CONTINUE              0
29435 #define MA_AAUDIO_CALLBACK_RESULT_STOP                  1
29436
29437
29438 typedef ma_aaudio_data_callback_result_t (* ma_AAudioStream_dataCallback) (ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t numFrames);
29439 typedef void                             (* ma_AAudioStream_errorCallback)(ma_AAudioStream *pStream, void *pUserData, ma_aaudio_result_t error);
29440
29441 typedef ma_aaudio_result_t       (* MA_PFN_AAudio_createStreamBuilder)                   (ma_AAudioStreamBuilder** ppBuilder);
29442 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStreamBuilder_delete)                   (ma_AAudioStreamBuilder* pBuilder);
29443 typedef void                     (* MA_PFN_AAudioStreamBuilder_setDeviceId)              (ma_AAudioStreamBuilder* pBuilder, int32_t deviceId);
29444 typedef void                     (* MA_PFN_AAudioStreamBuilder_setDirection)             (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_direction_t direction);
29445 typedef void                     (* MA_PFN_AAudioStreamBuilder_setSharingMode)           (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_sharing_mode_t sharingMode);
29446 typedef void                     (* MA_PFN_AAudioStreamBuilder_setFormat)                (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_format_t format);
29447 typedef void                     (* MA_PFN_AAudioStreamBuilder_setChannelCount)          (ma_AAudioStreamBuilder* pBuilder, int32_t channelCount);
29448 typedef void                     (* MA_PFN_AAudioStreamBuilder_setSampleRate)            (ma_AAudioStreamBuilder* pBuilder, int32_t sampleRate);
29449 typedef void                     (* MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)(ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
29450 typedef void                     (* MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback) (ma_AAudioStreamBuilder* pBuilder, int32_t numFrames);
29451 typedef void                     (* MA_PFN_AAudioStreamBuilder_setDataCallback)          (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_dataCallback callback, void* pUserData);
29452 typedef void                     (* MA_PFN_AAudioStreamBuilder_setErrorCallback)         (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream_errorCallback callback, void* pUserData);
29453 typedef void                     (* MA_PFN_AAudioStreamBuilder_setPerformanceMode)       (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_performance_mode_t mode);
29454 typedef void                     (* MA_PFN_AAudioStreamBuilder_setUsage)                 (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_usage_t contentType);
29455 typedef void                     (* MA_PFN_AAudioStreamBuilder_setContentType)           (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_content_type_t contentType);
29456 typedef void                     (* MA_PFN_AAudioStreamBuilder_setInputPreset)           (ma_AAudioStreamBuilder* pBuilder, ma_aaudio_input_preset_t inputPreset);
29457 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStreamBuilder_openStream)               (ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream);
29458 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStream_close)                           (ma_AAudioStream* pStream);
29459 typedef ma_aaudio_stream_state_t (* MA_PFN_AAudioStream_getState)                        (ma_AAudioStream* pStream);
29460 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);
29461 typedef ma_aaudio_format_t       (* MA_PFN_AAudioStream_getFormat)                       (ma_AAudioStream* pStream);
29462 typedef int32_t                  (* MA_PFN_AAudioStream_getChannelCount)                 (ma_AAudioStream* pStream);
29463 typedef int32_t                  (* MA_PFN_AAudioStream_getSampleRate)                   (ma_AAudioStream* pStream);
29464 typedef int32_t                  (* MA_PFN_AAudioStream_getBufferCapacityInFrames)       (ma_AAudioStream* pStream);
29465 typedef int32_t                  (* MA_PFN_AAudioStream_getFramesPerDataCallback)        (ma_AAudioStream* pStream);
29466 typedef int32_t                  (* MA_PFN_AAudioStream_getFramesPerBurst)               (ma_AAudioStream* pStream);
29467 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStream_requestStart)                    (ma_AAudioStream* pStream);
29468 typedef ma_aaudio_result_t       (* MA_PFN_AAudioStream_requestStop)                     (ma_AAudioStream* pStream);
29469
29470 static ma_result ma_result_from_aaudio(ma_aaudio_result_t resultAA)
29471 {
29472     switch (resultAA)
29473     {
29474         case MA_AAUDIO_OK: return MA_SUCCESS;
29475         default: break;
29476     }
29477
29478     return MA_ERROR;
29479 }
29480
29481 static ma_aaudio_usage_t ma_to_usage__aaudio(ma_aaudio_usage usage)
29482 {
29483     switch (usage) {
29484         case ma_aaudio_usage_announcement:                   return MA_AAUDIO_USAGE_MEDIA;
29485         case ma_aaudio_usage_emergency:                      return MA_AAUDIO_USAGE_VOICE_COMMUNICATION;
29486         case ma_aaudio_usage_safety:                         return MA_AAUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
29487         case ma_aaudio_usage_vehicle_status:                 return MA_AAUDIO_USAGE_ALARM;
29488         case ma_aaudio_usage_alarm:                          return MA_AAUDIO_USAGE_NOTIFICATION;
29489         case ma_aaudio_usage_assistance_accessibility:       return MA_AAUDIO_USAGE_NOTIFICATION_RINGTONE;
29490         case ma_aaudio_usage_assistance_navigation_guidance: return MA_AAUDIO_USAGE_NOTIFICATION_EVENT;
29491         case ma_aaudio_usage_assistance_sonification:        return MA_AAUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
29492         case ma_aaudio_usage_assitant:                       return MA_AAUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
29493         case ma_aaudio_usage_game:                           return MA_AAUDIO_USAGE_ASSISTANCE_SONIFICATION;
29494         case ma_aaudio_usage_media:                          return MA_AAUDIO_USAGE_GAME;
29495         case ma_aaudio_usage_notification:                   return MA_AAUDIO_USAGE_ASSISTANT;
29496         case ma_aaudio_usage_notification_event:             return MA_AAUDIO_SYSTEM_USAGE_EMERGENCY;
29497         case ma_aaudio_usage_notification_ringtone:          return MA_AAUDIO_SYSTEM_USAGE_SAFETY;
29498         case ma_aaudio_usage_voice_communication:            return MA_AAUDIO_SYSTEM_USAGE_VEHICLE_STATUS;
29499         case ma_aaudio_usage_voice_communication_signalling: return MA_AAUDIO_SYSTEM_USAGE_ANNOUNCEMENT;
29500         default: break;
29501     }
29502
29503     return MA_AAUDIO_USAGE_MEDIA;
29504 }
29505
29506 static ma_aaudio_content_type_t ma_to_content_type__aaudio(ma_aaudio_content_type contentType)
29507 {
29508     switch (contentType) {
29509         case ma_aaudio_content_type_movie:        return MA_AAUDIO_CONTENT_TYPE_MOVIE;
29510         case ma_aaudio_content_type_music:        return MA_AAUDIO_CONTENT_TYPE_MUSIC;
29511         case ma_aaudio_content_type_sonification: return MA_AAUDIO_CONTENT_TYPE_SONIFICATION;
29512         case ma_aaudio_content_type_speech:       return MA_AAUDIO_CONTENT_TYPE_SPEECH;
29513         default: break;
29514     }
29515
29516     return MA_AAUDIO_CONTENT_TYPE_SPEECH;
29517 }
29518
29519 static ma_aaudio_input_preset_t ma_to_input_preset__aaudio(ma_aaudio_input_preset inputPreset)
29520 {
29521     switch (inputPreset) {
29522         case ma_aaudio_input_preset_generic:             return MA_AAUDIO_INPUT_PRESET_GENERIC;
29523         case ma_aaudio_input_preset_camcorder:           return MA_AAUDIO_INPUT_PRESET_CAMCORDER;
29524         case ma_aaudio_input_preset_unprocessed:         return MA_AAUDIO_INPUT_PRESET_UNPROCESSED;
29525         case ma_aaudio_input_preset_voice_recognition:   return MA_AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
29526         case ma_aaudio_input_preset_voice_communication: return MA_AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION;
29527         case ma_aaudio_input_preset_voice_performance:   return MA_AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE;
29528         default: break;
29529     }
29530
29531     return MA_AAUDIO_INPUT_PRESET_GENERIC;
29532 }
29533
29534 static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUserData, ma_aaudio_result_t error)
29535 {
29536     ma_device* pDevice = (ma_device*)pUserData;
29537     MA_ASSERT(pDevice != NULL);
29538
29539     (void)error;
29540
29541 #if defined(MA_DEBUG_OUTPUT)
29542     printf("[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream));
29543 #endif
29544
29545     /*
29546     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
29547     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.
29548     */
29549     if (((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream) == MA_AAUDIO_STREAM_STATE_DISCONNECTED) {
29550 #if defined(MA_DEBUG_OUTPUT)
29551         printf("[AAudio] Device Disconnected.\n");
29552 #endif
29553     }
29554 }
29555
29556 static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
29557 {
29558     ma_device* pDevice = (ma_device*)pUserData;
29559     MA_ASSERT(pDevice != NULL);
29560
29561     ma_device_handle_backend_data_callback(pDevice, NULL, pAudioData, frameCount);
29562
29563     (void)pStream;
29564     return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
29565 }
29566
29567 static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio(ma_AAudioStream* pStream, void* pUserData, void* pAudioData, int32_t frameCount)
29568 {
29569     ma_device* pDevice = (ma_device*)pUserData;
29570     MA_ASSERT(pDevice != NULL);
29571
29572     ma_device_handle_backend_data_callback(pDevice, pAudioData, NULL, frameCount);
29573
29574     (void)pStream;
29575     return MA_AAUDIO_CALLBACK_RESULT_CONTINUE;
29576 }
29577
29578 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)
29579 {
29580     ma_AAudioStreamBuilder* pBuilder;
29581     ma_aaudio_result_t resultAA;
29582     ma_uint32 bufferCapacityInFrames;
29583
29584     /* Safety. */
29585     *ppBuilder = NULL;
29586
29587     resultAA = ((MA_PFN_AAudio_createStreamBuilder)pContext->aaudio.AAudio_createStreamBuilder)(&pBuilder);
29588     if (resultAA != MA_AAUDIO_OK) {
29589         return ma_result_from_aaudio(resultAA);
29590     }
29591
29592     if (pDeviceID != NULL) {
29593         ((MA_PFN_AAudioStreamBuilder_setDeviceId)pContext->aaudio.AAudioStreamBuilder_setDeviceId)(pBuilder, pDeviceID->aaudio);
29594     }
29595
29596     ((MA_PFN_AAudioStreamBuilder_setDirection)pContext->aaudio.AAudioStreamBuilder_setDirection)(pBuilder, (deviceType == ma_device_type_playback) ? MA_AAUDIO_DIRECTION_OUTPUT : MA_AAUDIO_DIRECTION_INPUT);
29597     ((MA_PFN_AAudioStreamBuilder_setSharingMode)pContext->aaudio.AAudioStreamBuilder_setSharingMode)(pBuilder, (shareMode == ma_share_mode_shared) ? MA_AAUDIO_SHARING_MODE_SHARED : MA_AAUDIO_SHARING_MODE_EXCLUSIVE);
29598
29599
29600     /* If we have a device descriptor make sure we configure the stream builder to take our requested parameters. */
29601     if (pDescriptor != NULL) {
29602         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. */
29603
29604         if (pDescriptor->sampleRate != 0) {
29605             ((MA_PFN_AAudioStreamBuilder_setSampleRate)pContext->aaudio.AAudioStreamBuilder_setSampleRate)(pBuilder, pDescriptor->sampleRate);
29606         }
29607
29608         if (deviceType == ma_device_type_capture) {
29609             if (pDescriptor->channels != 0) {
29610                 ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels);
29611             }
29612             if (pDescriptor->format != ma_format_unknown) {
29613                 ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT);
29614             }
29615         } else {
29616             if (pDescriptor->channels != 0) {
29617                 ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels);
29618             }
29619             if (pDescriptor->format != ma_format_unknown) {
29620                 ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT);
29621             }
29622         }
29623
29624         /*
29625         AAudio is annoying when it comes to it's buffer calculation stuff because it doesn't let you
29626         retrieve the actual sample rate until after you've opened the stream. But you need to configure
29627         the buffer capacity before you open the stream... :/
29628
29629         To solve, we're just going to assume MA_DEFAULT_SAMPLE_RATE (48000) and move on.
29630         */
29631         bufferCapacityInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, pDescriptor->sampleRate, pConfig->performanceProfile) * pDescriptor->periodCount;
29632
29633         ((MA_PFN_AAudioStreamBuilder_setBufferCapacityInFrames)pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames)(pBuilder, bufferCapacityInFrames);
29634         ((MA_PFN_AAudioStreamBuilder_setFramesPerDataCallback)pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback)(pBuilder, bufferCapacityInFrames / pDescriptor->periodCount);
29635
29636         if (deviceType == ma_device_type_capture) {
29637             if (pConfig->aaudio.inputPreset != ma_aaudio_input_preset_default && pContext->aaudio.AAudioStreamBuilder_setInputPreset != NULL) {
29638                 ((MA_PFN_AAudioStreamBuilder_setInputPreset)pContext->aaudio.AAudioStreamBuilder_setInputPreset)(pBuilder, ma_to_input_preset__aaudio(pConfig->aaudio.inputPreset));
29639             }
29640
29641             ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_capture__aaudio, (void*)pDevice);
29642         } else {
29643             if (pConfig->aaudio.usage != ma_aaudio_usage_default && pContext->aaudio.AAudioStreamBuilder_setUsage != NULL) {
29644                 ((MA_PFN_AAudioStreamBuilder_setUsage)pContext->aaudio.AAudioStreamBuilder_setUsage)(pBuilder, ma_to_usage__aaudio(pConfig->aaudio.usage));
29645             }
29646
29647             if (pConfig->aaudio.contentType != ma_aaudio_content_type_default && pContext->aaudio.AAudioStreamBuilder_setContentType != NULL) {
29648                 ((MA_PFN_AAudioStreamBuilder_setContentType)pContext->aaudio.AAudioStreamBuilder_setContentType)(pBuilder, ma_to_content_type__aaudio(pConfig->aaudio.contentType));
29649             }
29650
29651             ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_playback__aaudio, (void*)pDevice);
29652         }
29653
29654         /* 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. */
29655         ((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);
29656     
29657         /* We need to set an error callback to detect device changes. */
29658         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. */
29659             ((MA_PFN_AAudioStreamBuilder_setErrorCallback)pContext->aaudio.AAudioStreamBuilder_setErrorCallback)(pBuilder, ma_stream_error_callback__aaudio, (void*)pDevice);
29660         }
29661     }
29662
29663     *ppBuilder = pBuilder;
29664
29665     return MA_SUCCESS;
29666 }
29667
29668 static ma_result ma_open_stream_and_close_builder__aaudio(ma_context* pContext, ma_AAudioStreamBuilder* pBuilder, ma_AAudioStream** ppStream)
29669 {
29670     ma_result result;
29671
29672     result = ma_result_from_aaudio(((MA_PFN_AAudioStreamBuilder_openStream)pContext->aaudio.AAudioStreamBuilder_openStream)(pBuilder, ppStream));
29673     ((MA_PFN_AAudioStreamBuilder_delete)pContext->aaudio.AAudioStreamBuilder_delete)(pBuilder);
29674
29675     return result;
29676 }
29677
29678 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)
29679 {
29680     ma_result result;
29681     ma_AAudioStreamBuilder* pBuilder;
29682
29683     *ppStream = NULL;
29684
29685     result = ma_create_and_configure_AAudioStreamBuilder__aaudio(pContext, pDeviceID, deviceType, shareMode, NULL, NULL, NULL, &pBuilder);
29686     if (result != MA_SUCCESS) {
29687         return result;
29688     }
29689
29690     return ma_open_stream_and_close_builder__aaudio(pContext, pBuilder, ppStream);
29691 }
29692
29693 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)
29694 {
29695     ma_result result;
29696     ma_AAudioStreamBuilder* pBuilder;
29697
29698     MA_ASSERT(pConfig != NULL);
29699     MA_ASSERT(pConfig->deviceType != ma_device_type_duplex);   /* This function should not be called for a full-duplex device type. */
29700
29701     *ppStream = NULL;
29702
29703     result = ma_create_and_configure_AAudioStreamBuilder__aaudio(pDevice->pContext, pDescriptor->pDeviceID, deviceType, pDescriptor->shareMode, pDescriptor, pConfig, pDevice, &pBuilder);
29704     if (result != MA_SUCCESS) {
29705         return result;
29706     }
29707
29708     return ma_open_stream_and_close_builder__aaudio(pDevice->pContext, pBuilder, ppStream);
29709 }
29710
29711 static ma_result ma_close_stream__aaudio(ma_context* pContext, ma_AAudioStream* pStream)
29712 {
29713     return ma_result_from_aaudio(((MA_PFN_AAudioStream_close)pContext->aaudio.AAudioStream_close)(pStream));
29714 }
29715
29716 static ma_bool32 ma_has_default_device__aaudio(ma_context* pContext, ma_device_type deviceType)
29717 {
29718     /* The only way to know this is to try creating a stream. */
29719     ma_AAudioStream* pStream;
29720     ma_result result = ma_open_stream_basic__aaudio(pContext, NULL, deviceType, ma_share_mode_shared, &pStream);
29721     if (result != MA_SUCCESS) {
29722         return MA_FALSE;
29723     }
29724
29725     ma_close_stream__aaudio(pContext, pStream);
29726     return MA_TRUE;
29727 }
29728
29729 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)
29730 {
29731     ma_aaudio_stream_state_t actualNewState;
29732     ma_aaudio_result_t resultAA = ((MA_PFN_AAudioStream_waitForStateChange)pContext->aaudio.AAudioStream_waitForStateChange)(pStream, oldState, &actualNewState, 5000000000); /* 5 second timeout. */
29733     if (resultAA != MA_AAUDIO_OK) {
29734         return ma_result_from_aaudio(resultAA);
29735     }
29736
29737     if (newState != actualNewState) {
29738         return MA_ERROR;   /* Failed to transition into the expected state. */
29739     }
29740
29741     return MA_SUCCESS;
29742 }
29743
29744
29745 static ma_result ma_context_enumerate_devices__aaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
29746 {
29747     ma_bool32 cbResult = MA_TRUE;
29748
29749     MA_ASSERT(pContext != NULL);
29750     MA_ASSERT(callback != NULL);
29751
29752     /* 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. */
29753
29754     /* Playback. */
29755     if (cbResult) {
29756         ma_device_info deviceInfo;
29757         MA_ZERO_OBJECT(&deviceInfo);
29758         deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED;
29759         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
29760
29761         if (ma_has_default_device__aaudio(pContext, ma_device_type_playback)) {
29762             cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
29763         }
29764     }
29765
29766     /* Capture. */
29767     if (cbResult) {
29768         ma_device_info deviceInfo;
29769         MA_ZERO_OBJECT(&deviceInfo);
29770         deviceInfo.id.aaudio = MA_AAUDIO_UNSPECIFIED;
29771         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
29772
29773         if (ma_has_default_device__aaudio(pContext, ma_device_type_capture)) {
29774             cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
29775         }
29776     }
29777
29778     return MA_SUCCESS;
29779 }
29780
29781 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)
29782 {
29783     MA_ASSERT(pContext    != NULL);
29784     MA_ASSERT(pStream     != NULL);
29785     MA_ASSERT(pDeviceInfo != NULL);
29786
29787     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
29788     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = ((MA_PFN_AAudioStream_getChannelCount)pContext->aaudio.AAudioStream_getChannelCount)(pStream);
29789     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = ((MA_PFN_AAudioStream_getSampleRate)pContext->aaudio.AAudioStream_getSampleRate)(pStream);
29790     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = flags;
29791     pDeviceInfo->nativeDataFormatCount += 1;
29792 }
29793
29794 static void ma_context_add_native_data_format_from_AAudioStream__aaudio(ma_context* pContext, ma_AAudioStream* pStream, ma_uint32 flags, ma_device_info* pDeviceInfo)
29795 {
29796     /* AAudio supports s16 and f32. */
29797     ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(pContext, pStream, ma_format_f32, flags, pDeviceInfo);
29798     ma_context_add_native_data_format_from_AAudioStream_ex__aaudio(pContext, pStream, ma_format_s16, flags, pDeviceInfo);
29799 }
29800
29801 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)
29802 {
29803     ma_AAudioStream* pStream;
29804     ma_result result;
29805
29806     MA_ASSERT(pContext != NULL);
29807
29808     /* ID */
29809     if (pDeviceID != NULL) {
29810         pDeviceInfo->id.aaudio = pDeviceID->aaudio;
29811     } else {
29812         pDeviceInfo->id.aaudio = MA_AAUDIO_UNSPECIFIED;
29813     }
29814
29815     /* Name */
29816     if (deviceType == ma_device_type_playback) {
29817         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
29818     } else {
29819         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
29820     }
29821
29822
29823     pDeviceInfo->nativeDataFormatCount = 0;
29824
29825     /* We'll need to open the device to get accurate sample rate and channel count information. */
29826     result = ma_open_stream_basic__aaudio(pContext, pDeviceID, deviceType, ma_share_mode_shared, &pStream);
29827     if (result != MA_SUCCESS) {
29828         return result;
29829     }
29830
29831     ma_context_add_native_data_format_from_AAudioStream__aaudio(pContext, pStream, 0, pDeviceInfo);
29832
29833     ma_close_stream__aaudio(pContext, pStream);
29834     pStream = NULL;
29835
29836     return MA_SUCCESS;
29837 }
29838
29839
29840 static ma_result ma_device_uninit__aaudio(ma_device* pDevice)
29841 {
29842     MA_ASSERT(pDevice != NULL);
29843
29844     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
29845         ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
29846         pDevice->aaudio.pStreamCapture = NULL;
29847     }
29848
29849     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
29850         ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
29851         pDevice->aaudio.pStreamPlayback = NULL;
29852     }
29853
29854     return MA_SUCCESS;
29855 }
29856
29857 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)
29858 {
29859     ma_result result;
29860     int32_t bufferCapacityInFrames;
29861     int32_t framesPerDataCallback;
29862     ma_AAudioStream* pStream;
29863
29864     MA_ASSERT(pDevice     != NULL);
29865     MA_ASSERT(pConfig     != NULL);
29866     MA_ASSERT(pDescriptor != NULL);
29867
29868     *ppStream = NULL;   /* Safety. */
29869
29870     /* First step is to open the stream. From there we'll be able to extract the internal configuration. */
29871     result = ma_open_stream__aaudio(pDevice, pConfig, deviceType, pDescriptor, &pStream);
29872     if (result != MA_SUCCESS) {
29873         return result;  /* Failed to open the AAudio stream. */
29874     }
29875
29876     /* Now extract the internal configuration. */
29877     pDescriptor->format     = (((MA_PFN_AAudioStream_getFormat)pDevice->pContext->aaudio.AAudioStream_getFormat)(pStream) == MA_AAUDIO_FORMAT_PCM_I16) ? ma_format_s16 : ma_format_f32;
29878     pDescriptor->channels   = ((MA_PFN_AAudioStream_getChannelCount)pDevice->pContext->aaudio.AAudioStream_getChannelCount)(pStream);
29879     pDescriptor->sampleRate = ((MA_PFN_AAudioStream_getSampleRate)pDevice->pContext->aaudio.AAudioStream_getSampleRate)(pStream);
29880
29881     /* For the channel map we need to be sure we don't overflow any buffers. */
29882     if (pDescriptor->channels <= MA_MAX_CHANNELS) {
29883         ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptor->channels, pDescriptor->channelMap); /* <-- Cannot find info on channel order, so assuming a default. */
29884     } else {
29885         ma_channel_map_init_blank(MA_MAX_CHANNELS, pDescriptor->channelMap); /* Too many channels. Use a blank channel map. */
29886     }
29887
29888     bufferCapacityInFrames = ((MA_PFN_AAudioStream_getBufferCapacityInFrames)pDevice->pContext->aaudio.AAudioStream_getBufferCapacityInFrames)(pStream);
29889     framesPerDataCallback = ((MA_PFN_AAudioStream_getFramesPerDataCallback)pDevice->pContext->aaudio.AAudioStream_getFramesPerDataCallback)(pStream);
29890
29891     if (framesPerDataCallback > 0) {
29892         pDescriptor->periodSizeInFrames = framesPerDataCallback;
29893         pDescriptor->periodCount        = bufferCapacityInFrames / framesPerDataCallback;
29894     } else {
29895         pDescriptor->periodSizeInFrames = bufferCapacityInFrames;
29896         pDescriptor->periodCount        = 1;
29897     }
29898
29899     *ppStream = pStream;
29900
29901     return MA_SUCCESS;
29902 }
29903
29904 static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
29905 {
29906     ma_result result;
29907
29908     MA_ASSERT(pDevice != NULL);
29909
29910     if (pConfig->deviceType == ma_device_type_loopback) {
29911         return MA_DEVICE_TYPE_NOT_SUPPORTED;
29912     }
29913
29914     /* No exclusive mode with AAudio. */
29915     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
29916         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
29917         return MA_SHARE_MODE_NOT_SUPPORTED;
29918     }
29919
29920     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
29921         result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_capture, pDescriptorCapture, (ma_AAudioStream**)&pDevice->aaudio.pStreamCapture);
29922         if (result != MA_SUCCESS) {
29923             return result;
29924         }
29925     }
29926
29927     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
29928         result = ma_device_init_by_type__aaudio(pDevice, pConfig, ma_device_type_playback, pDescriptorPlayback, (ma_AAudioStream**)&pDevice->aaudio.pStreamPlayback);
29929         if (result != MA_SUCCESS) {
29930             return result;
29931         }
29932     }
29933
29934     return MA_SUCCESS;
29935 }
29936
29937 static ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream)
29938 {
29939     ma_aaudio_result_t resultAA;
29940     ma_aaudio_stream_state_t currentState;
29941
29942     MA_ASSERT(pDevice != NULL);
29943
29944     resultAA = ((MA_PFN_AAudioStream_requestStart)pDevice->pContext->aaudio.AAudioStream_requestStart)(pStream);
29945     if (resultAA != MA_AAUDIO_OK) {
29946         return ma_result_from_aaudio(resultAA);
29947     }
29948
29949     /* Do we actually need to wait for the device to transition into it's started state? */
29950
29951     /* 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. */
29952     currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream);
29953     if (currentState != MA_AAUDIO_STREAM_STATE_STARTED) {
29954         ma_result result;
29955
29956         if (currentState != MA_AAUDIO_STREAM_STATE_STARTING) {
29957             return MA_ERROR;   /* Expecting the stream to be a starting or started state. */
29958         }
29959
29960         result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STARTED);
29961         if (result != MA_SUCCESS) {
29962             return result;
29963         }
29964     }
29965
29966     return MA_SUCCESS;
29967 }
29968
29969 static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream)
29970 {
29971     ma_aaudio_result_t resultAA;
29972     ma_aaudio_stream_state_t currentState;
29973
29974     MA_ASSERT(pDevice != NULL);
29975
29976     /*
29977     From the AAudio documentation:
29978
29979         The stream will stop after all of the data currently buffered has been played.
29980
29981     This maps with miniaudio's requirement that device's be drained which means we don't need to implement any draining logic.
29982     */
29983
29984     resultAA = ((MA_PFN_AAudioStream_requestStop)pDevice->pContext->aaudio.AAudioStream_requestStop)(pStream);
29985     if (resultAA != MA_AAUDIO_OK) {
29986         return ma_result_from_aaudio(resultAA);
29987     }
29988
29989     /* 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. */
29990     currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream);
29991     if (currentState != MA_AAUDIO_STREAM_STATE_STOPPED) {
29992         ma_result result;
29993
29994         if (currentState != MA_AAUDIO_STREAM_STATE_STOPPING) {
29995             return MA_ERROR;   /* Expecting the stream to be a stopping or stopped state. */
29996         }
29997
29998         result = ma_wait_for_simple_state_transition__aaudio(pDevice->pContext, pStream, currentState, MA_AAUDIO_STREAM_STATE_STOPPED);
29999         if (result != MA_SUCCESS) {
30000             return result;
30001         }
30002     }
30003
30004     return MA_SUCCESS;
30005 }
30006
30007 static ma_result ma_device_start__aaudio(ma_device* pDevice)
30008 {
30009     MA_ASSERT(pDevice != NULL);
30010
30011     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
30012         ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
30013         if (result != MA_SUCCESS) {
30014             return result;
30015         }
30016     }
30017
30018     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
30019         ma_result result = ma_device_start_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
30020         if (result != MA_SUCCESS) {
30021             if (pDevice->type == ma_device_type_duplex) {
30022                 ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
30023             }
30024             return result;
30025         }
30026     }
30027
30028     return MA_SUCCESS;
30029 }
30030
30031 static ma_result ma_device_stop__aaudio(ma_device* pDevice)
30032 {
30033     ma_stop_proc onStop;
30034
30035     MA_ASSERT(pDevice != NULL);
30036
30037     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
30038         ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
30039         if (result != MA_SUCCESS) {
30040             return result;
30041         }
30042     }
30043
30044     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
30045         ma_result result = ma_device_stop_stream__aaudio(pDevice, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
30046         if (result != MA_SUCCESS) {
30047             return result;
30048         }
30049     }
30050
30051     onStop = pDevice->onStop;
30052     if (onStop) {
30053         onStop(pDevice);
30054     }
30055
30056     return MA_SUCCESS;
30057 }
30058
30059
30060 static ma_result ma_context_uninit__aaudio(ma_context* pContext)
30061 {
30062     MA_ASSERT(pContext != NULL);
30063     MA_ASSERT(pContext->backend == ma_backend_aaudio);
30064
30065     ma_dlclose(pContext, pContext->aaudio.hAAudio);
30066     pContext->aaudio.hAAudio = NULL;
30067
30068     return MA_SUCCESS;
30069 }
30070
30071 static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
30072 {
30073     size_t i;
30074     const char* libNames[] = {
30075         "libaaudio.so"
30076     };
30077
30078     for (i = 0; i < ma_countof(libNames); ++i) {
30079         pContext->aaudio.hAAudio = ma_dlopen(pContext, libNames[i]);
30080         if (pContext->aaudio.hAAudio != NULL) {
30081             break;
30082         }
30083     }
30084
30085     if (pContext->aaudio.hAAudio == NULL) {
30086         return MA_FAILED_TO_INIT_BACKEND;
30087     }
30088
30089     pContext->aaudio.AAudio_createStreamBuilder                    = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudio_createStreamBuilder");
30090     pContext->aaudio.AAudioStreamBuilder_delete                    = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete");
30091     pContext->aaudio.AAudioStreamBuilder_setDeviceId               = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId");
30092     pContext->aaudio.AAudioStreamBuilder_setDirection              = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection");
30093     pContext->aaudio.AAudioStreamBuilder_setSharingMode            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode");
30094     pContext->aaudio.AAudioStreamBuilder_setFormat                 = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat");
30095     pContext->aaudio.AAudioStreamBuilder_setChannelCount           = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount");
30096     pContext->aaudio.AAudioStreamBuilder_setSampleRate             = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate");
30097     pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames");
30098     pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback  = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback");
30099     pContext->aaudio.AAudioStreamBuilder_setDataCallback           = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback");
30100     pContext->aaudio.AAudioStreamBuilder_setErrorCallback          = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setErrorCallback");
30101     pContext->aaudio.AAudioStreamBuilder_setPerformanceMode        = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode");
30102     pContext->aaudio.AAudioStreamBuilder_setUsage                  = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setUsage");
30103     pContext->aaudio.AAudioStreamBuilder_setContentType            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setContentType");
30104     pContext->aaudio.AAudioStreamBuilder_setInputPreset            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setInputPreset");
30105     pContext->aaudio.AAudioStreamBuilder_openStream                = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream");
30106     pContext->aaudio.AAudioStream_close                            = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close");
30107     pContext->aaudio.AAudioStream_getState                         = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState");
30108     pContext->aaudio.AAudioStream_waitForStateChange               = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange");
30109     pContext->aaudio.AAudioStream_getFormat                        = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFormat");
30110     pContext->aaudio.AAudioStream_getChannelCount                  = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getChannelCount");
30111     pContext->aaudio.AAudioStream_getSampleRate                    = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getSampleRate");
30112     pContext->aaudio.AAudioStream_getBufferCapacityInFrames        = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames");
30113     pContext->aaudio.AAudioStream_getFramesPerDataCallback         = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback");
30114     pContext->aaudio.AAudioStream_getFramesPerBurst                = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst");
30115     pContext->aaudio.AAudioStream_requestStart                     = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStart");
30116     pContext->aaudio.AAudioStream_requestStop                      = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStop");
30117
30118
30119     pCallbacks->onContextInit             = ma_context_init__aaudio;
30120     pCallbacks->onContextUninit           = ma_context_uninit__aaudio;
30121     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__aaudio;
30122     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__aaudio;
30123     pCallbacks->onDeviceInit              = ma_device_init__aaudio;
30124     pCallbacks->onDeviceUninit            = ma_device_uninit__aaudio;
30125     pCallbacks->onDeviceStart             = ma_device_start__aaudio;
30126     pCallbacks->onDeviceStop              = ma_device_stop__aaudio;
30127     pCallbacks->onDeviceRead              = NULL;   /* Not used because AAudio is asynchronous. */
30128     pCallbacks->onDeviceWrite             = NULL;   /* Not used because AAudio is asynchronous. */
30129     pCallbacks->onDeviceDataLoop          = NULL;   /* Not used because AAudio is asynchronous. */
30130
30131     (void)pConfig;
30132     return MA_SUCCESS;
30133 }
30134 #endif  /* AAudio */
30135
30136
30137 /******************************************************************************
30138
30139 OpenSL|ES Backend
30140
30141 ******************************************************************************/
30142 #ifdef MA_HAS_OPENSL
30143 #include <SLES/OpenSLES.h>
30144 #ifdef MA_ANDROID
30145 #include <SLES/OpenSLES_Android.h>
30146 #endif
30147
30148 typedef SLresult (SLAPIENTRY * ma_slCreateEngine_proc)(SLObjectItf* pEngine, SLuint32 numOptions, SLEngineOption* pEngineOptions, SLuint32 numInterfaces, SLInterfaceID* pInterfaceIds, SLboolean* pInterfaceRequired);
30149
30150 /* OpenSL|ES has one-per-application objects :( */
30151 static SLObjectItf g_maEngineObjectSL    = NULL;
30152 static SLEngineItf g_maEngineSL          = NULL;
30153 static ma_uint32   g_maOpenSLInitCounter = 0;
30154 static ma_spinlock g_maOpenSLSpinlock    = 0;   /* For init/uninit. */
30155
30156 #define MA_OPENSL_OBJ(p)         (*((SLObjectItf)(p)))
30157 #define MA_OPENSL_OUTPUTMIX(p)   (*((SLOutputMixItf)(p)))
30158 #define MA_OPENSL_PLAY(p)        (*((SLPlayItf)(p)))
30159 #define MA_OPENSL_RECORD(p)      (*((SLRecordItf)(p)))
30160
30161 #ifdef MA_ANDROID
30162 #define MA_OPENSL_BUFFERQUEUE(p) (*((SLAndroidSimpleBufferQueueItf)(p)))
30163 #else
30164 #define MA_OPENSL_BUFFERQUEUE(p) (*((SLBufferQueueItf)(p)))
30165 #endif
30166
30167 static ma_result ma_result_from_OpenSL(SLuint32 result)
30168 {
30169     switch (result)
30170     {
30171         case SL_RESULT_SUCCESS:                 return MA_SUCCESS;
30172         case SL_RESULT_PRECONDITIONS_VIOLATED:  return MA_ERROR;
30173         case SL_RESULT_PARAMETER_INVALID:       return MA_INVALID_ARGS;
30174         case SL_RESULT_MEMORY_FAILURE:          return MA_OUT_OF_MEMORY;
30175         case SL_RESULT_RESOURCE_ERROR:          return MA_INVALID_DATA;
30176         case SL_RESULT_RESOURCE_LOST:           return MA_ERROR;
30177         case SL_RESULT_IO_ERROR:                return MA_IO_ERROR;
30178         case SL_RESULT_BUFFER_INSUFFICIENT:     return MA_NO_SPACE;
30179         case SL_RESULT_CONTENT_CORRUPTED:       return MA_INVALID_DATA;
30180         case SL_RESULT_CONTENT_UNSUPPORTED:     return MA_FORMAT_NOT_SUPPORTED;
30181         case SL_RESULT_CONTENT_NOT_FOUND:       return MA_ERROR;
30182         case SL_RESULT_PERMISSION_DENIED:       return MA_ACCESS_DENIED;
30183         case SL_RESULT_FEATURE_UNSUPPORTED:     return MA_NOT_IMPLEMENTED;
30184         case SL_RESULT_INTERNAL_ERROR:          return MA_ERROR;
30185         case SL_RESULT_UNKNOWN_ERROR:           return MA_ERROR;
30186         case SL_RESULT_OPERATION_ABORTED:       return MA_ERROR;
30187         case SL_RESULT_CONTROL_LOST:            return MA_ERROR;
30188         default:                                return MA_ERROR;
30189     }
30190 }
30191
30192 /* Converts an individual OpenSL-style channel identifier (SL_SPEAKER_FRONT_LEFT, etc.) to miniaudio. */
30193 static ma_uint8 ma_channel_id_to_ma__opensl(SLuint32 id)
30194 {
30195     switch (id)
30196     {
30197         case SL_SPEAKER_FRONT_LEFT:            return MA_CHANNEL_FRONT_LEFT;
30198         case SL_SPEAKER_FRONT_RIGHT:           return MA_CHANNEL_FRONT_RIGHT;
30199         case SL_SPEAKER_FRONT_CENTER:          return MA_CHANNEL_FRONT_CENTER;
30200         case SL_SPEAKER_LOW_FREQUENCY:         return MA_CHANNEL_LFE;
30201         case SL_SPEAKER_BACK_LEFT:             return MA_CHANNEL_BACK_LEFT;
30202         case SL_SPEAKER_BACK_RIGHT:            return MA_CHANNEL_BACK_RIGHT;
30203         case SL_SPEAKER_FRONT_LEFT_OF_CENTER:  return MA_CHANNEL_FRONT_LEFT_CENTER;
30204         case SL_SPEAKER_FRONT_RIGHT_OF_CENTER: return MA_CHANNEL_FRONT_RIGHT_CENTER;
30205         case SL_SPEAKER_BACK_CENTER:           return MA_CHANNEL_BACK_CENTER;
30206         case SL_SPEAKER_SIDE_LEFT:             return MA_CHANNEL_SIDE_LEFT;
30207         case SL_SPEAKER_SIDE_RIGHT:            return MA_CHANNEL_SIDE_RIGHT;
30208         case SL_SPEAKER_TOP_CENTER:            return MA_CHANNEL_TOP_CENTER;
30209         case SL_SPEAKER_TOP_FRONT_LEFT:        return MA_CHANNEL_TOP_FRONT_LEFT;
30210         case SL_SPEAKER_TOP_FRONT_CENTER:      return MA_CHANNEL_TOP_FRONT_CENTER;
30211         case SL_SPEAKER_TOP_FRONT_RIGHT:       return MA_CHANNEL_TOP_FRONT_RIGHT;
30212         case SL_SPEAKER_TOP_BACK_LEFT:         return MA_CHANNEL_TOP_BACK_LEFT;
30213         case SL_SPEAKER_TOP_BACK_CENTER:       return MA_CHANNEL_TOP_BACK_CENTER;
30214         case SL_SPEAKER_TOP_BACK_RIGHT:        return MA_CHANNEL_TOP_BACK_RIGHT;
30215         default: return 0;
30216     }
30217 }
30218
30219 /* Converts an individual miniaudio channel identifier (MA_CHANNEL_FRONT_LEFT, etc.) to OpenSL-style. */
30220 static SLuint32 ma_channel_id_to_opensl(ma_uint8 id)
30221 {
30222     switch (id)
30223     {
30224         case MA_CHANNEL_MONO:               return SL_SPEAKER_FRONT_CENTER;
30225         case MA_CHANNEL_FRONT_LEFT:         return SL_SPEAKER_FRONT_LEFT;
30226         case MA_CHANNEL_FRONT_RIGHT:        return SL_SPEAKER_FRONT_RIGHT;
30227         case MA_CHANNEL_FRONT_CENTER:       return SL_SPEAKER_FRONT_CENTER;
30228         case MA_CHANNEL_LFE:                return SL_SPEAKER_LOW_FREQUENCY;
30229         case MA_CHANNEL_BACK_LEFT:          return SL_SPEAKER_BACK_LEFT;
30230         case MA_CHANNEL_BACK_RIGHT:         return SL_SPEAKER_BACK_RIGHT;
30231         case MA_CHANNEL_FRONT_LEFT_CENTER:  return SL_SPEAKER_FRONT_LEFT_OF_CENTER;
30232         case MA_CHANNEL_FRONT_RIGHT_CENTER: return SL_SPEAKER_FRONT_RIGHT_OF_CENTER;
30233         case MA_CHANNEL_BACK_CENTER:        return SL_SPEAKER_BACK_CENTER;
30234         case MA_CHANNEL_SIDE_LEFT:          return SL_SPEAKER_SIDE_LEFT;
30235         case MA_CHANNEL_SIDE_RIGHT:         return SL_SPEAKER_SIDE_RIGHT;
30236         case MA_CHANNEL_TOP_CENTER:         return SL_SPEAKER_TOP_CENTER;
30237         case MA_CHANNEL_TOP_FRONT_LEFT:     return SL_SPEAKER_TOP_FRONT_LEFT;
30238         case MA_CHANNEL_TOP_FRONT_CENTER:   return SL_SPEAKER_TOP_FRONT_CENTER;
30239         case MA_CHANNEL_TOP_FRONT_RIGHT:    return SL_SPEAKER_TOP_FRONT_RIGHT;
30240         case MA_CHANNEL_TOP_BACK_LEFT:      return SL_SPEAKER_TOP_BACK_LEFT;
30241         case MA_CHANNEL_TOP_BACK_CENTER:    return SL_SPEAKER_TOP_BACK_CENTER;
30242         case MA_CHANNEL_TOP_BACK_RIGHT:     return SL_SPEAKER_TOP_BACK_RIGHT;
30243         default: return 0;
30244     }
30245 }
30246
30247 /* Converts a channel mapping to an OpenSL-style channel mask. */
30248 static SLuint32 ma_channel_map_to_channel_mask__opensl(const ma_channel* pChannelMap, ma_uint32 channels)
30249 {
30250     SLuint32 channelMask = 0;
30251     ma_uint32 iChannel;
30252     for (iChannel = 0; iChannel < channels; ++iChannel) {
30253         channelMask |= ma_channel_id_to_opensl(pChannelMap[iChannel]);
30254     }
30255
30256     return channelMask;
30257 }
30258
30259 /* Converts an OpenSL-style channel mask to a miniaudio channel map. */
30260 static void ma_channel_mask_to_channel_map__opensl(SLuint32 channelMask, ma_uint32 channels, ma_channel* pChannelMap)
30261 {
30262     if (channels == 1 && channelMask == 0) {
30263         pChannelMap[0] = MA_CHANNEL_MONO;
30264     } else if (channels == 2 && channelMask == 0) {
30265         pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
30266         pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
30267     } else {
30268         if (channels == 1 && (channelMask & SL_SPEAKER_FRONT_CENTER) != 0) {
30269             pChannelMap[0] = MA_CHANNEL_MONO;
30270         } else {
30271             /* Just iterate over each bit. */
30272             ma_uint32 iChannel = 0;
30273             ma_uint32 iBit;
30274             for (iBit = 0; iBit < 32 && iChannel < channels; ++iBit) {
30275                 SLuint32 bitValue = (channelMask & (1UL << iBit));
30276                 if (bitValue != 0) {
30277                     /* The bit is set. */
30278                     pChannelMap[iChannel] = ma_channel_id_to_ma__opensl(bitValue);
30279                     iChannel += 1;
30280                 }
30281             }
30282         }
30283     }
30284 }
30285
30286 static SLuint32 ma_round_to_standard_sample_rate__opensl(SLuint32 samplesPerSec)
30287 {
30288     if (samplesPerSec <= SL_SAMPLINGRATE_8) {
30289         return SL_SAMPLINGRATE_8;
30290     }
30291     if (samplesPerSec <= SL_SAMPLINGRATE_11_025) {
30292         return SL_SAMPLINGRATE_11_025;
30293     }
30294     if (samplesPerSec <= SL_SAMPLINGRATE_12) {
30295         return SL_SAMPLINGRATE_12;
30296     }
30297     if (samplesPerSec <= SL_SAMPLINGRATE_16) {
30298         return SL_SAMPLINGRATE_16;
30299     }
30300     if (samplesPerSec <= SL_SAMPLINGRATE_22_05) {
30301         return SL_SAMPLINGRATE_22_05;
30302     }
30303     if (samplesPerSec <= SL_SAMPLINGRATE_24) {
30304         return SL_SAMPLINGRATE_24;
30305     }
30306     if (samplesPerSec <= SL_SAMPLINGRATE_32) {
30307         return SL_SAMPLINGRATE_32;
30308     }
30309     if (samplesPerSec <= SL_SAMPLINGRATE_44_1) {
30310         return SL_SAMPLINGRATE_44_1;
30311     }
30312     if (samplesPerSec <= SL_SAMPLINGRATE_48) {
30313         return SL_SAMPLINGRATE_48;
30314     }
30315
30316     /* Android doesn't support more than 48000. */
30317 #ifndef MA_ANDROID
30318     if (samplesPerSec <= SL_SAMPLINGRATE_64) {
30319         return SL_SAMPLINGRATE_64;
30320     }
30321     if (samplesPerSec <= SL_SAMPLINGRATE_88_2) {
30322         return SL_SAMPLINGRATE_88_2;
30323     }
30324     if (samplesPerSec <= SL_SAMPLINGRATE_96) {
30325         return SL_SAMPLINGRATE_96;
30326     }
30327     if (samplesPerSec <= SL_SAMPLINGRATE_192) {
30328         return SL_SAMPLINGRATE_192;
30329     }
30330 #endif
30331
30332     return SL_SAMPLINGRATE_16;
30333 }
30334
30335
30336 static SLint32 ma_to_stream_type__opensl(ma_opensl_stream_type streamType)
30337 {
30338     switch (streamType) {
30339         case ma_opensl_stream_type_voice:        return SL_ANDROID_STREAM_VOICE;
30340         case ma_opensl_stream_type_system:       return SL_ANDROID_STREAM_SYSTEM;
30341         case ma_opensl_stream_type_ring:         return SL_ANDROID_STREAM_RING;
30342         case ma_opensl_stream_type_media:        return SL_ANDROID_STREAM_MEDIA;
30343         case ma_opensl_stream_type_alarm:        return SL_ANDROID_STREAM_ALARM;
30344         case ma_opensl_stream_type_notification: return SL_ANDROID_STREAM_NOTIFICATION;
30345         default: break;
30346     }
30347
30348     return SL_ANDROID_STREAM_VOICE;
30349 }
30350
30351 static SLint32 ma_to_recording_preset__opensl(ma_opensl_recording_preset recordingPreset)
30352 {
30353     switch (recordingPreset) {
30354         case ma_opensl_recording_preset_generic:             return SL_ANDROID_RECORDING_PRESET_GENERIC;
30355         case ma_opensl_recording_preset_camcorder:           return SL_ANDROID_RECORDING_PRESET_CAMCORDER;
30356         case ma_opensl_recording_preset_voice_recognition:   return SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
30357         case ma_opensl_recording_preset_voice_communication: return SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
30358         case ma_opensl_recording_preset_voice_unprocessed:   return SL_ANDROID_RECORDING_PRESET_UNPROCESSED;
30359         default: break;
30360     }
30361
30362     return SL_ANDROID_RECORDING_PRESET_NONE;
30363 }
30364
30365
30366 static ma_result ma_context_enumerate_devices__opensl(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
30367 {
30368     ma_bool32 cbResult;
30369
30370     MA_ASSERT(pContext != NULL);
30371     MA_ASSERT(callback != NULL);
30372
30373     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. */
30374     if (g_maOpenSLInitCounter == 0) {
30375         return MA_INVALID_OPERATION;
30376     }
30377
30378     /*
30379     TODO: Test Me.
30380
30381     This is currently untested, so for now we are just returning default devices.
30382     */
30383 #if 0 && !defined(MA_ANDROID)
30384     ma_bool32 isTerminated = MA_FALSE;
30385
30386     SLuint32 pDeviceIDs[128];
30387     SLint32 deviceCount = sizeof(pDeviceIDs) / sizeof(pDeviceIDs[0]);
30388
30389     SLAudioIODeviceCapabilitiesItf deviceCaps;
30390     SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
30391     if (resultSL != SL_RESULT_SUCCESS) {
30392         /* The interface may not be supported so just report a default device. */
30393         goto return_default_device;
30394     }
30395
30396     /* Playback */
30397     if (!isTerminated) {
30398         resultSL = (*deviceCaps)->GetAvailableAudioOutputs(deviceCaps, &deviceCount, pDeviceIDs);
30399         if (resultSL != SL_RESULT_SUCCESS) {
30400             return ma_result_from_OpenSL(resultSL);
30401         }
30402
30403         for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) {
30404             ma_device_info deviceInfo;
30405             MA_ZERO_OBJECT(&deviceInfo);
30406             deviceInfo.id.opensl = pDeviceIDs[iDevice];
30407
30408             SLAudioOutputDescriptor desc;
30409             resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc);
30410             if (resultSL == SL_RESULT_SUCCESS) {
30411                 ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.pDeviceName, (size_t)-1);
30412
30413                 ma_bool32 cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
30414                 if (cbResult == MA_FALSE) {
30415                     isTerminated = MA_TRUE;
30416                     break;
30417                 }
30418             }
30419         }
30420     }
30421
30422     /* Capture */
30423     if (!isTerminated) {
30424         resultSL = (*deviceCaps)->GetAvailableAudioInputs(deviceCaps, &deviceCount, pDeviceIDs);
30425         if (resultSL != SL_RESULT_SUCCESS) {
30426             return ma_result_from_OpenSL(resultSL);
30427         }
30428
30429         for (SLint32 iDevice = 0; iDevice < deviceCount; ++iDevice) {
30430             ma_device_info deviceInfo;
30431             MA_ZERO_OBJECT(&deviceInfo);
30432             deviceInfo.id.opensl = pDeviceIDs[iDevice];
30433
30434             SLAudioInputDescriptor desc;
30435             resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, deviceInfo.id.opensl, &desc);
30436             if (resultSL == SL_RESULT_SUCCESS) {
30437                 ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), (const char*)desc.deviceName, (size_t)-1);
30438
30439                 ma_bool32 cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
30440                 if (cbResult == MA_FALSE) {
30441                     isTerminated = MA_TRUE;
30442                     break;
30443                 }
30444             }
30445         }
30446     }
30447
30448     return MA_SUCCESS;
30449 #else
30450     goto return_default_device;
30451 #endif
30452
30453 return_default_device:;
30454     cbResult = MA_TRUE;
30455
30456     /* Playback. */
30457     if (cbResult) {
30458         ma_device_info deviceInfo;
30459         MA_ZERO_OBJECT(&deviceInfo);
30460         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
30461         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
30462     }
30463
30464     /* Capture. */
30465     if (cbResult) {
30466         ma_device_info deviceInfo;
30467         MA_ZERO_OBJECT(&deviceInfo);
30468         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
30469         cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
30470     }
30471
30472     return MA_SUCCESS;
30473 }
30474
30475 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)
30476 {
30477     MA_ASSERT(pContext    != NULL);
30478     MA_ASSERT(pDeviceInfo != NULL);
30479
30480     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
30481     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
30482     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
30483     pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = 0;
30484     pDeviceInfo->nativeDataFormatCount += 1;
30485 }
30486
30487 static void ma_context_add_data_format__opensl(ma_context* pContext, ma_format format, ma_device_info* pDeviceInfo)
30488 {
30489     ma_uint32 minChannels   = 1;
30490     ma_uint32 maxChannels   = 2;
30491     ma_uint32 minSampleRate = (ma_uint32)ma_standard_sample_rate_8000;
30492     ma_uint32 maxSampleRate = (ma_uint32)ma_standard_sample_rate_48000;
30493     ma_uint32 iChannel;
30494     ma_uint32 iSampleRate;
30495
30496     MA_ASSERT(pContext    != NULL);
30497     MA_ASSERT(pDeviceInfo != NULL);
30498
30499     /*
30500     Each sample format can support mono and stereo, and we'll support a small subset of standard
30501     rates (up to 48000). A better solution would be to somehow find a native sample rate.
30502     */
30503     for (iChannel = minChannels; iChannel < maxChannels; iChannel += 1) {
30504         for (iSampleRate = 0; iSampleRate < ma_countof(g_maStandardSampleRatePriorities); iSampleRate += 1) {
30505             ma_uint32 standardSampleRate = g_maStandardSampleRatePriorities[iSampleRate];
30506             if (standardSampleRate >= minSampleRate && standardSampleRate <= maxSampleRate) {
30507                 ma_context_add_data_format_ex__opensl(pContext, format, iChannel, standardSampleRate, pDeviceInfo);
30508             }
30509         }
30510     }
30511 }
30512
30513 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)
30514 {
30515     MA_ASSERT(pContext != NULL);
30516
30517     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. */
30518     if (g_maOpenSLInitCounter == 0) {
30519         return MA_INVALID_OPERATION;
30520     }
30521
30522     /*
30523     TODO: Test Me.
30524
30525     This is currently untested, so for now we are just returning default devices.
30526     */
30527 #if 0 && !defined(MA_ANDROID)
30528     SLAudioIODeviceCapabilitiesItf deviceCaps;
30529     SLresult resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES, &deviceCaps);
30530     if (resultSL != SL_RESULT_SUCCESS) {
30531         /* The interface may not be supported so just report a default device. */
30532         goto return_default_device;
30533     }
30534
30535     if (deviceType == ma_device_type_playback) {
30536         SLAudioOutputDescriptor desc;
30537         resultSL = (*deviceCaps)->QueryAudioOutputCapabilities(deviceCaps, pDeviceID->opensl, &desc);
30538         if (resultSL != SL_RESULT_SUCCESS) {
30539             return ma_result_from_OpenSL(resultSL);
30540         }
30541
30542         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.pDeviceName, (size_t)-1);
30543     } else {
30544         SLAudioInputDescriptor desc;
30545         resultSL = (*deviceCaps)->QueryAudioInputCapabilities(deviceCaps, pDeviceID->opensl, &desc);
30546         if (resultSL != SL_RESULT_SUCCESS) {
30547             return ma_result_from_OpenSL(resultSL);
30548         }
30549
30550         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), (const char*)desc.deviceName, (size_t)-1);
30551     }
30552
30553     goto return_detailed_info;
30554 #else
30555     goto return_default_device;
30556 #endif
30557
30558 return_default_device:
30559     if (pDeviceID != NULL) {
30560         if ((deviceType == ma_device_type_playback && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOOUTPUT) ||
30561             (deviceType == ma_device_type_capture  && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOINPUT)) {
30562             return MA_NO_DEVICE;   /* Don't know the device. */
30563         }
30564     }
30565
30566     /* Name / Description */
30567     if (deviceType == ma_device_type_playback) {
30568         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
30569     } else {
30570         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
30571     }
30572
30573     pDeviceInfo->isDefault = MA_TRUE;
30574
30575     goto return_detailed_info;
30576
30577
30578 return_detailed_info:
30579
30580     /*
30581     For now we're just outputting a set of values that are supported by the API but not necessarily supported
30582     by the device natively. Later on we should work on this so that it more closely reflects the device's
30583     actual native format.
30584     */
30585     pDeviceInfo->nativeDataFormatCount = 0;
30586 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
30587     ma_context_add_data_format__opensl(pContext, ma_format_f32, pDeviceInfo);
30588 #endif
30589     ma_context_add_data_format__opensl(pContext, ma_format_s16, pDeviceInfo);
30590     ma_context_add_data_format__opensl(pContext, ma_format_u8,  pDeviceInfo);
30591
30592     return MA_SUCCESS;
30593 }
30594
30595
30596 #ifdef MA_ANDROID
30597 /*void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext)*/
30598 static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
30599 {
30600     ma_device* pDevice = (ma_device*)pUserData;
30601     size_t periodSizeInBytes;
30602     ma_uint8* pBuffer;
30603     SLresult resultSL;
30604
30605     MA_ASSERT(pDevice != NULL);
30606
30607     (void)pBufferQueue;
30608
30609     /*
30610     For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like
30611     OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this,
30612     but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :(
30613     */
30614
30615     /* Don't do anything if the device is not started. */
30616     if (ma_device_get_state(pDevice) != MA_STATE_STARTED) {
30617         return;
30618     }
30619
30620     /* Don't do anything if the device is being drained. */
30621     if (pDevice->opensl.isDrainingCapture) {
30622         return;
30623     }
30624
30625     periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
30626     pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes);
30627
30628     ma_device_handle_backend_data_callback(pDevice, NULL, pBuffer, pDevice->capture.internalPeriodSizeInFrames);
30629
30630     resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pBuffer, periodSizeInBytes);
30631     if (resultSL != SL_RESULT_SUCCESS) {
30632         return;
30633     }
30634
30635     pDevice->opensl.currentBufferIndexCapture = (pDevice->opensl.currentBufferIndexCapture + 1) % pDevice->capture.internalPeriods;
30636 }
30637
30638 static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
30639 {
30640     ma_device* pDevice = (ma_device*)pUserData;
30641     size_t periodSizeInBytes;
30642     ma_uint8* pBuffer;
30643     SLresult resultSL;
30644
30645     MA_ASSERT(pDevice != NULL);
30646
30647     (void)pBufferQueue;
30648
30649     /* Don't do anything if the device is not started. */
30650     if (ma_device_get_state(pDevice) != MA_STATE_STARTED) {
30651         return;
30652     }
30653
30654     /* Don't do anything if the device is being drained. */
30655     if (pDevice->opensl.isDrainingPlayback) {
30656         return;
30657     }
30658
30659     periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
30660     pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes);
30661
30662     ma_device_handle_backend_data_callback(pDevice, pBuffer, NULL, pDevice->playback.internalPeriodSizeInFrames);
30663
30664     resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pBuffer, periodSizeInBytes);
30665     if (resultSL != SL_RESULT_SUCCESS) {
30666         return;
30667     }
30668
30669     pDevice->opensl.currentBufferIndexPlayback = (pDevice->opensl.currentBufferIndexPlayback + 1) % pDevice->playback.internalPeriods;
30670 }
30671 #endif
30672
30673 static ma_result ma_device_uninit__opensl(ma_device* pDevice)
30674 {
30675     MA_ASSERT(pDevice != NULL);
30676
30677     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. */
30678     if (g_maOpenSLInitCounter == 0) {
30679         return MA_INVALID_OPERATION;
30680     }
30681
30682     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
30683         if (pDevice->opensl.pAudioRecorderObj) {
30684             MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioRecorderObj);
30685         }
30686
30687         ma__free_from_callbacks(pDevice->opensl.pBufferCapture, &pDevice->pContext->allocationCallbacks);
30688     }
30689
30690     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
30691         if (pDevice->opensl.pAudioPlayerObj) {
30692             MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Destroy((SLObjectItf)pDevice->opensl.pAudioPlayerObj);
30693         }
30694         if (pDevice->opensl.pOutputMixObj) {
30695             MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Destroy((SLObjectItf)pDevice->opensl.pOutputMixObj);
30696         }
30697
30698         ma__free_from_callbacks(pDevice->opensl.pBufferPlayback, &pDevice->pContext->allocationCallbacks);
30699     }
30700
30701     return MA_SUCCESS;
30702 }
30703
30704 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
30705 typedef SLAndroidDataFormat_PCM_EX  ma_SLDataFormat_PCM;
30706 #else
30707 typedef SLDataFormat_PCM            ma_SLDataFormat_PCM;
30708 #endif
30709
30710 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)
30711 {
30712     /* We need to convert our format/channels/rate so that they aren't set to default. */
30713     if (format == ma_format_unknown) {
30714         format = MA_DEFAULT_FORMAT;
30715     }
30716     if (channels == 0) {
30717         channels = MA_DEFAULT_CHANNELS;
30718     }
30719     if (sampleRate == 0) {
30720         sampleRate = MA_DEFAULT_SAMPLE_RATE;
30721     }
30722
30723 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
30724     if (format == ma_format_f32) {
30725         pDataFormat->formatType     = SL_ANDROID_DATAFORMAT_PCM_EX;
30726         pDataFormat->representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
30727     } else {
30728         pDataFormat->formatType = SL_DATAFORMAT_PCM;
30729     }
30730 #else
30731     pDataFormat->formatType = SL_DATAFORMAT_PCM;
30732 #endif
30733
30734     pDataFormat->numChannels   = channels;
30735     ((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 */
30736     pDataFormat->bitsPerSample = ma_get_bytes_per_sample(format)*8;
30737     pDataFormat->channelMask   = ma_channel_map_to_channel_mask__opensl(channelMap, channels);
30738     pDataFormat->endianness    = (ma_is_little_endian()) ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
30739
30740     /*
30741     Android has a few restrictions on the format as documented here: https://developer.android.com/ndk/guides/audio/opensl-for-android.html
30742      - Only mono and stereo is supported.
30743      - Only u8 and s16 formats are supported.
30744      - Maximum sample rate of 48000.
30745     */
30746 #ifdef MA_ANDROID
30747     if (pDataFormat->numChannels > 2) {
30748         pDataFormat->numChannels = 2;
30749     }
30750 #if __ANDROID_API__ >= 21
30751     if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) {
30752         /* It's floating point. */
30753         MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT);
30754         if (pDataFormat->bitsPerSample > 32) {
30755             pDataFormat->bitsPerSample = 32;
30756         }
30757     } else {
30758         if (pDataFormat->bitsPerSample > 16) {
30759             pDataFormat->bitsPerSample = 16;
30760         }
30761     }
30762 #else
30763     if (pDataFormat->bitsPerSample > 16) {
30764         pDataFormat->bitsPerSample = 16;
30765     }
30766 #endif
30767     if (((SLDataFormat_PCM*)pDataFormat)->samplesPerSec > SL_SAMPLINGRATE_48) {
30768         ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec = SL_SAMPLINGRATE_48;
30769     }
30770 #endif
30771
30772     pDataFormat->containerSize = pDataFormat->bitsPerSample;  /* Always tightly packed for now. */
30773
30774     return MA_SUCCESS;
30775 }
30776
30777 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)
30778 {
30779     ma_bool32 isFloatingPoint = MA_FALSE;
30780 #if defined(MA_ANDROID) && __ANDROID_API__ >= 21
30781     if (pDataFormat->formatType == SL_ANDROID_DATAFORMAT_PCM_EX) {
30782         MA_ASSERT(pDataFormat->representation == SL_ANDROID_PCM_REPRESENTATION_FLOAT);
30783         isFloatingPoint = MA_TRUE;
30784     }
30785 #endif
30786     if (isFloatingPoint) {
30787         if (pDataFormat->bitsPerSample == 32) {
30788             *pFormat = ma_format_f32;
30789         }
30790     } else {
30791         if (pDataFormat->bitsPerSample == 8) {
30792             *pFormat = ma_format_u8;
30793         } else if (pDataFormat->bitsPerSample == 16) {
30794             *pFormat = ma_format_s16;
30795         } else if (pDataFormat->bitsPerSample == 24) {
30796             *pFormat = ma_format_s24;
30797         } else if (pDataFormat->bitsPerSample == 32) {
30798             *pFormat = ma_format_s32;
30799         }
30800     }
30801
30802     *pChannels   = pDataFormat->numChannels;
30803     *pSampleRate = ((SLDataFormat_PCM*)pDataFormat)->samplesPerSec / 1000;
30804     ma_channel_mask_to_channel_map__opensl(pDataFormat->channelMask, ma_min(pDataFormat->numChannels, channelMapCap), pChannelMap);
30805
30806     return MA_SUCCESS;
30807 }
30808
30809 static ma_result ma_device_init__opensl(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
30810 {
30811 #ifdef MA_ANDROID
30812     SLDataLocator_AndroidSimpleBufferQueue queue;
30813     SLresult resultSL;
30814     size_t bufferSizeInBytes;
30815     SLInterfaceID itfIDs1[1];
30816     const SLboolean itfIDsRequired1[] = {SL_BOOLEAN_TRUE};
30817 #endif
30818
30819     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. */
30820     if (g_maOpenSLInitCounter == 0) {
30821         return MA_INVALID_OPERATION;
30822     }
30823
30824     if (pConfig->deviceType == ma_device_type_loopback) {
30825         return MA_DEVICE_TYPE_NOT_SUPPORTED;
30826     }
30827
30828     /*
30829     For now, only supporting Android implementations of OpenSL|ES since that's the only one I've
30830     been able to test with and I currently depend on Android-specific extensions (simple buffer
30831     queues).
30832     */
30833 #ifdef MA_ANDROID
30834     itfIDs1[0] = (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
30835
30836     /* No exclusive mode with OpenSL|ES. */
30837     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
30838         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
30839         return MA_SHARE_MODE_NOT_SUPPORTED;
30840     }
30841
30842     /* Now we can start initializing the device properly. */
30843     MA_ASSERT(pDevice != NULL);
30844     MA_ZERO_OBJECT(&pDevice->opensl);
30845
30846     queue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
30847
30848     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
30849         ma_SLDataFormat_PCM pcm;
30850         SLDataLocator_IODevice locatorDevice;
30851         SLDataSource source;
30852         SLDataSink sink;
30853         SLAndroidConfigurationItf pRecorderConfig;
30854
30855         ma_SLDataFormat_PCM_init__opensl(pDescriptorCapture->format, pDescriptorCapture->channels, pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, &pcm);
30856
30857         locatorDevice.locatorType = SL_DATALOCATOR_IODEVICE;
30858         locatorDevice.deviceType  = SL_IODEVICE_AUDIOINPUT;
30859         locatorDevice.deviceID    = (pDescriptorCapture->pDeviceID == NULL) ? SL_DEFAULTDEVICEID_AUDIOINPUT : pDescriptorCapture->pDeviceID->opensl;
30860         locatorDevice.device      = NULL;
30861
30862         source.pLocator = &locatorDevice;
30863         source.pFormat  = NULL;
30864
30865         queue.numBuffers = pDescriptorCapture->periodCount;
30866
30867         sink.pLocator = &queue;
30868         sink.pFormat  = (SLDataFormat_PCM*)&pcm;
30869
30870         resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
30871         if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) {
30872             /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
30873             pcm.formatType    = SL_DATAFORMAT_PCM;
30874             pcm.numChannels   = 1;
30875             ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16;  /* The name of the sample rate variable is different between SLAndroidDataFormat_PCM_EX and SLDataFormat_PCM. */
30876             pcm.bitsPerSample = 16;
30877             pcm.containerSize = pcm.bitsPerSample;  /* Always tightly packed for now. */
30878             pcm.channelMask   = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
30879             resultSL = (*g_maEngineSL)->CreateAudioRecorder(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioRecorderObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
30880         }
30881
30882         if (resultSL != SL_RESULT_SUCCESS) {
30883             ma_device_uninit__opensl(pDevice);
30884             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio recorder.", ma_result_from_OpenSL(resultSL));
30885         }
30886
30887
30888         /* Set the recording preset before realizing the player. */
30889         if (pConfig->opensl.recordingPreset != ma_opensl_recording_preset_default) {
30890             resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION, &pRecorderConfig);
30891             if (resultSL == SL_RESULT_SUCCESS) {
30892                 SLint32 recordingPreset = ma_to_recording_preset__opensl(pConfig->opensl.recordingPreset);
30893                 resultSL = (*pRecorderConfig)->SetConfiguration(pRecorderConfig, SL_ANDROID_KEY_RECORDING_PRESET, &recordingPreset, sizeof(SLint32));
30894                 if (resultSL != SL_RESULT_SUCCESS) {
30895                     /* Failed to set the configuration. Just keep going. */
30896                 }
30897             }
30898         }
30899
30900         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->Realize((SLObjectItf)pDevice->opensl.pAudioRecorderObj, SL_BOOLEAN_FALSE);
30901         if (resultSL != SL_RESULT_SUCCESS) {
30902             ma_device_uninit__opensl(pDevice);
30903             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio recorder.", ma_result_from_OpenSL(resultSL));
30904         }
30905
30906         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_RECORD, &pDevice->opensl.pAudioRecorder);
30907         if (resultSL != SL_RESULT_SUCCESS) {
30908             ma_device_uninit__opensl(pDevice);
30909             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_RECORD interface.", ma_result_from_OpenSL(resultSL));
30910         }
30911
30912         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioRecorderObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioRecorderObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueueCapture);
30913         if (resultSL != SL_RESULT_SUCCESS) {
30914             ma_device_uninit__opensl(pDevice);
30915             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
30916         }
30917
30918         resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, ma_buffer_queue_callback_capture__opensl_android, pDevice);
30919         if (resultSL != SL_RESULT_SUCCESS) {
30920             ma_device_uninit__opensl(pDevice);
30921             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL));
30922         }
30923
30924         /* The internal format is determined by the "pcm" object. */
30925         ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDescriptorCapture->format, &pDescriptorCapture->channels, &pDescriptorCapture->sampleRate, pDescriptorCapture->channelMap, ma_countof(pDescriptorCapture->channelMap));
30926
30927         /* Buffer. */
30928         pDescriptorCapture->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorCapture, pDescriptorCapture->sampleRate, pConfig->performanceProfile);
30929         pDevice->opensl.currentBufferIndexCapture = 0;
30930
30931         bufferSizeInBytes = pDescriptorCapture->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorCapture->format, pDescriptorCapture->channels) * pDescriptorCapture->periodCount;
30932         pDevice->opensl.pBufferCapture = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks);
30933         if (pDevice->opensl.pBufferCapture == NULL) {
30934             ma_device_uninit__opensl(pDevice);
30935             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY);
30936         }
30937         MA_ZERO_MEMORY(pDevice->opensl.pBufferCapture, bufferSizeInBytes);
30938     }
30939
30940     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
30941         ma_SLDataFormat_PCM pcm;
30942         SLDataSource source;
30943         SLDataLocator_OutputMix outmixLocator;
30944         SLDataSink sink;
30945         SLAndroidConfigurationItf pPlayerConfig;
30946
30947         ma_SLDataFormat_PCM_init__opensl(pDescriptorPlayback->format, pDescriptorPlayback->channels, pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, &pcm);
30948
30949         resultSL = (*g_maEngineSL)->CreateOutputMix(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pOutputMixObj, 0, NULL, NULL);
30950         if (resultSL != SL_RESULT_SUCCESS) {
30951             ma_device_uninit__opensl(pDevice);
30952             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create output mix.", ma_result_from_OpenSL(resultSL));
30953         }
30954
30955         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->Realize((SLObjectItf)pDevice->opensl.pOutputMixObj, SL_BOOLEAN_FALSE);
30956         if (resultSL != SL_RESULT_SUCCESS) {
30957             ma_device_uninit__opensl(pDevice);
30958             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize output mix object.", ma_result_from_OpenSL(resultSL));
30959         }
30960
30961         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pOutputMixObj)->GetInterface((SLObjectItf)pDevice->opensl.pOutputMixObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_OUTPUTMIX, &pDevice->opensl.pOutputMix);
30962         if (resultSL != SL_RESULT_SUCCESS) {
30963             ma_device_uninit__opensl(pDevice);
30964             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_OUTPUTMIX interface.", ma_result_from_OpenSL(resultSL));
30965         }
30966
30967         /* Set the output device. */
30968         if (pDescriptorPlayback->pDeviceID != NULL) {
30969             SLuint32 deviceID_OpenSL = pDescriptorPlayback->pDeviceID->opensl;
30970             MA_OPENSL_OUTPUTMIX(pDevice->opensl.pOutputMix)->ReRoute((SLOutputMixItf)pDevice->opensl.pOutputMix, 1, &deviceID_OpenSL);
30971         }
30972
30973         queue.numBuffers = pDescriptorPlayback->periodCount;
30974
30975         source.pLocator = &queue;
30976         source.pFormat  = (SLDataFormat_PCM*)&pcm;
30977
30978         outmixLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
30979         outmixLocator.outputMix   = (SLObjectItf)pDevice->opensl.pOutputMixObj;
30980
30981         sink.pLocator = &outmixLocator;
30982         sink.pFormat  = NULL;
30983
30984         resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
30985         if (resultSL == SL_RESULT_CONTENT_UNSUPPORTED) {
30986             /* Unsupported format. Fall back to something safer and try again. If this fails, just abort. */
30987             pcm.formatType = SL_DATAFORMAT_PCM;
30988             pcm.numChannels = 2;
30989             ((SLDataFormat_PCM*)&pcm)->samplesPerSec = SL_SAMPLINGRATE_16;
30990             pcm.bitsPerSample = 16;
30991             pcm.containerSize = pcm.bitsPerSample;  /* Always tightly packed for now. */
30992             pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
30993             resultSL = (*g_maEngineSL)->CreateAudioPlayer(g_maEngineSL, (SLObjectItf*)&pDevice->opensl.pAudioPlayerObj, &source, &sink, 1, itfIDs1, itfIDsRequired1);
30994         }
30995
30996         if (resultSL != SL_RESULT_SUCCESS) {
30997             ma_device_uninit__opensl(pDevice);
30998             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to create audio player.", ma_result_from_OpenSL(resultSL));
30999         }
31000
31001
31002         /* Set the stream type before realizing the player. */
31003         if (pConfig->opensl.streamType != ma_opensl_stream_type_default) {
31004             resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDCONFIGURATION, &pPlayerConfig);
31005             if (resultSL == SL_RESULT_SUCCESS) {
31006                 SLint32 streamType = ma_to_stream_type__opensl(pConfig->opensl.streamType);
31007                 resultSL = (*pPlayerConfig)->SetConfiguration(pPlayerConfig, SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
31008                 if (resultSL != SL_RESULT_SUCCESS) {
31009                     /* Failed to set the configuration. Just keep going. */
31010                 }
31011             }
31012         }
31013
31014         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->Realize((SLObjectItf)pDevice->opensl.pAudioPlayerObj, SL_BOOLEAN_FALSE);
31015         if (resultSL != SL_RESULT_SUCCESS) {
31016             ma_device_uninit__opensl(pDevice);
31017             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to realize audio player.", ma_result_from_OpenSL(resultSL));
31018         }
31019
31020         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_PLAY, &pDevice->opensl.pAudioPlayer);
31021         if (resultSL != SL_RESULT_SUCCESS) {
31022             ma_device_uninit__opensl(pDevice);
31023             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_PLAY interface.", ma_result_from_OpenSL(resultSL));
31024         }
31025
31026         resultSL = MA_OPENSL_OBJ(pDevice->opensl.pAudioPlayerObj)->GetInterface((SLObjectItf)pDevice->opensl.pAudioPlayerObj, (SLInterfaceID)pDevice->pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &pDevice->opensl.pBufferQueuePlayback);
31027         if (resultSL != SL_RESULT_SUCCESS) {
31028             ma_device_uninit__opensl(pDevice);
31029             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to retrieve SL_IID_ANDROIDSIMPLEBUFFERQUEUE interface.", ma_result_from_OpenSL(resultSL));
31030         }
31031
31032         resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->RegisterCallback((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, ma_buffer_queue_callback_playback__opensl_android, pDevice);
31033         if (resultSL != SL_RESULT_SUCCESS) {
31034             ma_device_uninit__opensl(pDevice);
31035             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to register buffer queue callback.", ma_result_from_OpenSL(resultSL));
31036         }
31037
31038         /* The internal format is determined by the "pcm" object. */
31039         ma_deconstruct_SLDataFormat_PCM__opensl(&pcm, &pDescriptorPlayback->format, &pDescriptorPlayback->channels, &pDescriptorPlayback->sampleRate, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap));
31040
31041         /* Buffer. */
31042         pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
31043         pDevice->opensl.currentBufferIndexPlayback   = 0;
31044
31045         bufferSizeInBytes = pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels) * pDescriptorPlayback->periodCount;
31046         pDevice->opensl.pBufferPlayback = (ma_uint8*)ma__calloc_from_callbacks(bufferSizeInBytes, &pDevice->pContext->allocationCallbacks);
31047         if (pDevice->opensl.pBufferPlayback == NULL) {
31048             ma_device_uninit__opensl(pDevice);
31049             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to allocate memory for data buffer.", MA_OUT_OF_MEMORY);
31050         }
31051         MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, bufferSizeInBytes);
31052     }
31053
31054     return MA_SUCCESS;
31055 #else
31056     return MA_NO_BACKEND;   /* Non-Android implementations are not supported. */
31057 #endif
31058 }
31059
31060 static ma_result ma_device_start__opensl(ma_device* pDevice)
31061 {
31062     SLresult resultSL;
31063     size_t periodSizeInBytes;
31064     ma_uint32 iPeriod;
31065
31066     MA_ASSERT(pDevice != NULL);
31067
31068     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. */
31069     if (g_maOpenSLInitCounter == 0) {
31070         return MA_INVALID_OPERATION;
31071     }
31072
31073     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
31074         resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_RECORDING);
31075         if (resultSL != SL_RESULT_SUCCESS) {
31076             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal capture device.", ma_result_from_OpenSL(resultSL));
31077         }
31078
31079         periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
31080         for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) {
31081             resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes);
31082             if (resultSL != SL_RESULT_SUCCESS) {
31083                 MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
31084                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.", ma_result_from_OpenSL(resultSL));
31085             }
31086         }
31087     }
31088
31089     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
31090         resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_PLAYING);
31091         if (resultSL != SL_RESULT_SUCCESS) {
31092             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to start internal playback device.", ma_result_from_OpenSL(resultSL));
31093         }
31094
31095         /* In playback mode (no duplex) we need to load some initial buffers. In duplex mode we need to enqueu silent buffers. */
31096         if (pDevice->type == ma_device_type_duplex) {
31097             MA_ZERO_MEMORY(pDevice->opensl.pBufferPlayback, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels));
31098         } else {
31099             ma_device__read_frames_from_client(pDevice, pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods, pDevice->opensl.pBufferPlayback);
31100         }
31101
31102         periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
31103         for (iPeriod = 0; iPeriod < pDevice->playback.internalPeriods; ++iPeriod) {
31104             resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pDevice->opensl.pBufferPlayback + (periodSizeInBytes * iPeriod), periodSizeInBytes);
31105             if (resultSL != SL_RESULT_SUCCESS) {
31106                 MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED);
31107                 return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for playback device.", ma_result_from_OpenSL(resultSL));
31108             }
31109         }
31110     }
31111
31112     return MA_SUCCESS;
31113 }
31114
31115 static ma_result ma_device_drain__opensl(ma_device* pDevice, ma_device_type deviceType)
31116 {
31117     SLAndroidSimpleBufferQueueItf pBufferQueue;
31118
31119     MA_ASSERT(deviceType == ma_device_type_capture || deviceType == ma_device_type_playback);
31120
31121     if (pDevice->type == ma_device_type_capture) {
31122         pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture;
31123         pDevice->opensl.isDrainingCapture  = MA_TRUE;
31124     } else {
31125         pBufferQueue = (SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback;
31126         pDevice->opensl.isDrainingPlayback = MA_TRUE;
31127     }
31128
31129     for (;;) {
31130         SLAndroidSimpleBufferQueueState state;
31131
31132         MA_OPENSL_BUFFERQUEUE(pBufferQueue)->GetState(pBufferQueue, &state);
31133         if (state.count == 0) {
31134             break;
31135         }
31136
31137         ma_sleep(10);
31138     }
31139
31140     if (pDevice->type == ma_device_type_capture) {
31141         pDevice->opensl.isDrainingCapture  = MA_FALSE;
31142     } else {
31143         pDevice->opensl.isDrainingPlayback = MA_FALSE;
31144     }
31145
31146     return MA_SUCCESS;
31147 }
31148
31149 static ma_result ma_device_stop__opensl(ma_device* pDevice)
31150 {
31151     SLresult resultSL;
31152     ma_stop_proc onStop;
31153
31154     MA_ASSERT(pDevice != NULL);
31155
31156     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. */
31157     if (g_maOpenSLInitCounter == 0) {
31158         return MA_INVALID_OPERATION;
31159     }
31160
31161     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
31162         ma_device_drain__opensl(pDevice, ma_device_type_capture);
31163
31164         resultSL = MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED);
31165         if (resultSL != SL_RESULT_SUCCESS) {
31166             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal capture device.", ma_result_from_OpenSL(resultSL));
31167         }
31168
31169         MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture);
31170     }
31171
31172     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
31173         ma_device_drain__opensl(pDevice, ma_device_type_playback);
31174
31175         resultSL = MA_OPENSL_PLAY(pDevice->opensl.pAudioPlayer)->SetPlayState((SLPlayItf)pDevice->opensl.pAudioPlayer, SL_PLAYSTATE_STOPPED);
31176         if (resultSL != SL_RESULT_SUCCESS) {
31177             return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to stop internal playback device.", ma_result_from_OpenSL(resultSL));
31178         }
31179
31180         MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Clear((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback);
31181     }
31182
31183     /* 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. */
31184     onStop = pDevice->onStop;
31185     if (onStop) {
31186         onStop(pDevice);
31187     }
31188
31189     return MA_SUCCESS;
31190 }
31191
31192
31193 static ma_result ma_context_uninit__opensl(ma_context* pContext)
31194 {
31195     MA_ASSERT(pContext != NULL);
31196     MA_ASSERT(pContext->backend == ma_backend_opensl);
31197     (void)pContext;
31198
31199     /* Uninit global data. */
31200     ma_spinlock_lock(&g_maOpenSLSpinlock);
31201     {
31202         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(). */
31203
31204         g_maOpenSLInitCounter -= 1;
31205         if (g_maOpenSLInitCounter == 0) {
31206             (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
31207         }
31208     }
31209     ma_spinlock_unlock(&g_maOpenSLSpinlock);
31210
31211     return MA_SUCCESS;
31212 }
31213
31214 static ma_result ma_dlsym_SLInterfaceID__opensl(ma_context* pContext, const char* pName, ma_handle* pHandle)
31215 {
31216     /* 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. */
31217     ma_handle* p = (ma_handle*)ma_dlsym(pContext, pContext->opensl.libOpenSLES, pName);
31218     if (p == NULL) {
31219         ma_post_log_messagef(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol %s", pName);
31220         return MA_NO_BACKEND;
31221     }
31222
31223     *pHandle = *p;
31224     return MA_SUCCESS;
31225 }
31226
31227 static ma_result ma_context_init_engine_nolock__opensl(ma_context* pContext)
31228 {
31229     g_maOpenSLInitCounter += 1;
31230     if (g_maOpenSLInitCounter == 1) {
31231         SLresult resultSL;
31232
31233         resultSL = ((ma_slCreateEngine_proc)pContext->opensl.slCreateEngine)(&g_maEngineObjectSL, 0, NULL, 0, NULL, NULL);
31234         if (resultSL != SL_RESULT_SUCCESS) {
31235             g_maOpenSLInitCounter -= 1;
31236             return ma_result_from_OpenSL(resultSL);
31237         }
31238
31239         (*g_maEngineObjectSL)->Realize(g_maEngineObjectSL, SL_BOOLEAN_FALSE);
31240
31241         resultSL = (*g_maEngineObjectSL)->GetInterface(g_maEngineObjectSL, (SLInterfaceID)pContext->opensl.SL_IID_ENGINE, &g_maEngineSL);
31242         if (resultSL != SL_RESULT_SUCCESS) {
31243             (*g_maEngineObjectSL)->Destroy(g_maEngineObjectSL);
31244             g_maOpenSLInitCounter -= 1;
31245             return ma_result_from_OpenSL(resultSL);
31246         }
31247     }
31248
31249     return MA_SUCCESS;
31250 }
31251
31252 static ma_result ma_context_init__opensl(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
31253 {
31254     ma_result result;
31255
31256 #if !defined(MA_NO_RUNTIME_LINKING)
31257     size_t i;
31258     const char* libOpenSLESNames[] = {
31259         "libOpenSLES.so"
31260     };
31261 #endif
31262
31263     MA_ASSERT(pContext != NULL);
31264
31265     (void)pConfig;
31266
31267 #if !defined(MA_NO_RUNTIME_LINKING)
31268     /*
31269     Dynamically link against libOpenSLES.so. I have now had multiple reports that SL_IID_ANDROIDSIMPLEBUFFERQUEUE cannot be found. One
31270     report was happening at compile time and another at runtime. To try working around this, I'm going to link to libOpenSLES at runtime
31271     and extract the symbols rather than reference them directly. This should, hopefully, fix these issues as the compiler won't see any
31272     references to the symbols and will hopefully skip the checks.
31273     */
31274     for (i = 0; i < ma_countof(libOpenSLESNames); i += 1) {
31275         pContext->opensl.libOpenSLES = ma_dlopen(pContext, libOpenSLESNames[i]);
31276         if (pContext->opensl.libOpenSLES != NULL) {
31277             break;
31278         }
31279     }
31280
31281     if (pContext->opensl.libOpenSLES == NULL) {
31282         ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Could not find libOpenSLES.so");
31283         return MA_NO_BACKEND;
31284     }
31285
31286     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ENGINE", &pContext->opensl.SL_IID_ENGINE);
31287     if (result != MA_SUCCESS) {
31288         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31289         return result;
31290     }
31291
31292     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_AUDIOIODEVICECAPABILITIES", &pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES);
31293     if (result != MA_SUCCESS) {
31294         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31295         return result;
31296     }
31297
31298     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDSIMPLEBUFFERQUEUE", &pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE);
31299     if (result != MA_SUCCESS) {
31300         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31301         return result;
31302     }
31303
31304     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_RECORD", &pContext->opensl.SL_IID_RECORD);
31305     if (result != MA_SUCCESS) {
31306         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31307         return result;
31308     }
31309
31310     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_PLAY", &pContext->opensl.SL_IID_PLAY);
31311     if (result != MA_SUCCESS) {
31312         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31313         return result;
31314     }
31315
31316     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_OUTPUTMIX", &pContext->opensl.SL_IID_OUTPUTMIX);
31317     if (result != MA_SUCCESS) {
31318         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31319         return result;
31320     }
31321
31322     result = ma_dlsym_SLInterfaceID__opensl(pContext, "SL_IID_ANDROIDCONFIGURATION", &pContext->opensl.SL_IID_ANDROIDCONFIGURATION);
31323     if (result != MA_SUCCESS) {
31324         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31325         return result;
31326     }
31327
31328     pContext->opensl.slCreateEngine = (ma_proc)ma_dlsym(pContext, pContext->opensl.libOpenSLES, "slCreateEngine");
31329     if (pContext->opensl.slCreateEngine == NULL) {
31330         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31331         ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Cannot find symbol slCreateEngine.");
31332         return MA_NO_BACKEND;
31333     }
31334 #else
31335     pContext->opensl.SL_IID_ENGINE                    = (ma_handle)SL_IID_ENGINE;
31336     pContext->opensl.SL_IID_AUDIOIODEVICECAPABILITIES = (ma_handle)SL_IID_AUDIOIODEVICECAPABILITIES;
31337     pContext->opensl.SL_IID_ANDROIDSIMPLEBUFFERQUEUE  = (ma_handle)SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
31338     pContext->opensl.SL_IID_RECORD                    = (ma_handle)SL_IID_RECORD;
31339     pContext->opensl.SL_IID_PLAY                      = (ma_handle)SL_IID_PLAY;
31340     pContext->opensl.SL_IID_OUTPUTMIX                 = (ma_handle)SL_IID_OUTPUTMIX;
31341     pContext->opensl.SL_IID_ANDROIDCONFIGURATION      = (ma_handle)SL_IID_ANDROIDCONFIGURATION;
31342     pContext->opensl.slCreateEngine                   = (ma_proc)slCreateEngine;
31343 #endif
31344
31345
31346     /* Initialize global data first if applicable. */
31347     ma_spinlock_lock(&g_maOpenSLSpinlock);
31348     {
31349         result = ma_context_init_engine_nolock__opensl(pContext);
31350     }
31351     ma_spinlock_unlock(&g_maOpenSLSpinlock);
31352
31353     if (result != MA_SUCCESS) {
31354         ma_dlclose(pContext, pContext->opensl.libOpenSLES);
31355         ma_post_log_message(pContext, NULL, MA_LOG_LEVEL_INFO, "[OpenSL|ES] Failed to initialize OpenSL engine.");
31356         return result;
31357     }
31358
31359     pCallbacks->onContextInit             = ma_context_init__opensl;
31360     pCallbacks->onContextUninit           = ma_context_uninit__opensl;
31361     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__opensl;
31362     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__opensl;
31363     pCallbacks->onDeviceInit              = ma_device_init__opensl;
31364     pCallbacks->onDeviceUninit            = ma_device_uninit__opensl;
31365     pCallbacks->onDeviceStart             = ma_device_start__opensl;
31366     pCallbacks->onDeviceStop              = ma_device_stop__opensl;
31367     pCallbacks->onDeviceRead              = NULL;   /* Not needed because OpenSL|ES is asynchronous. */
31368     pCallbacks->onDeviceWrite             = NULL;   /* Not needed because OpenSL|ES is asynchronous. */
31369     pCallbacks->onDeviceDataLoop          = NULL;   /* Not needed because OpenSL|ES is asynchronous. */
31370
31371     return MA_SUCCESS;
31372 }
31373 #endif  /* OpenSL|ES */
31374
31375
31376 /******************************************************************************
31377
31378 Web Audio Backend
31379
31380 ******************************************************************************/
31381 #ifdef MA_HAS_WEBAUDIO
31382 #include <emscripten/emscripten.h>
31383
31384 static ma_bool32 ma_is_capture_supported__webaudio()
31385 {
31386     return EM_ASM_INT({
31387         return (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined);
31388     }, 0) != 0; /* Must pass in a dummy argument for C99 compatibility. */
31389 }
31390
31391 #ifdef __cplusplus
31392 extern "C" {
31393 #endif
31394 void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_capture__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
31395 {
31396     ma_device_handle_backend_data_callback(pDevice, NULL, pFrames, (ma_uint32)frameCount);
31397 }
31398
31399 void EMSCRIPTEN_KEEPALIVE ma_device_process_pcm_frames_playback__webaudio(ma_device* pDevice, int frameCount, float* pFrames)
31400 {
31401     ma_device_handle_backend_data_callback(pDevice, pFrames, NULL, (ma_uint32)frameCount);
31402 }
31403 #ifdef __cplusplus
31404 }
31405 #endif
31406
31407 static ma_result ma_context_enumerate_devices__webaudio(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
31408 {
31409     ma_bool32 cbResult = MA_TRUE;
31410
31411     MA_ASSERT(pContext != NULL);
31412     MA_ASSERT(callback != NULL);
31413
31414     /* Only supporting default devices for now. */
31415
31416     /* Playback. */
31417     if (cbResult) {
31418         ma_device_info deviceInfo;
31419         MA_ZERO_OBJECT(&deviceInfo);
31420         ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
31421         deviceInfo.isDefault = MA_TRUE;    /* Only supporting default devices. */
31422         cbResult = callback(pContext, ma_device_type_playback, &deviceInfo, pUserData);
31423     }
31424
31425     /* Capture. */
31426     if (cbResult) {
31427         if (ma_is_capture_supported__webaudio()) {
31428             ma_device_info deviceInfo;
31429             MA_ZERO_OBJECT(&deviceInfo);
31430             ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
31431             deviceInfo.isDefault = MA_TRUE;    /* Only supporting default devices. */
31432             cbResult = callback(pContext, ma_device_type_capture, &deviceInfo, pUserData);
31433         }
31434     }
31435
31436     return MA_SUCCESS;
31437 }
31438
31439 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)
31440 {
31441     MA_ASSERT(pContext != NULL);
31442
31443     if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) {
31444         return MA_NO_DEVICE;
31445     }
31446
31447     MA_ZERO_MEMORY(pDeviceInfo->id.webaudio, sizeof(pDeviceInfo->id.webaudio));
31448
31449     /* Only supporting default devices for now. */
31450     (void)pDeviceID;
31451     if (deviceType == ma_device_type_playback) {
31452         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
31453     } else {
31454         ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
31455     }
31456
31457     /* Only supporting default devices. */
31458     pDeviceInfo->isDefault = MA_TRUE;
31459
31460     /* Web Audio can support any number of channels and sample rates. It only supports f32 formats, however. */
31461     pDeviceInfo->nativeDataFormats[0].flags      = 0;
31462     pDeviceInfo->nativeDataFormats[0].format     = ma_format_unknown;
31463     pDeviceInfo->nativeDataFormats[0].channels   = 0; /* All channels are supported. */
31464     pDeviceInfo->nativeDataFormats[0].sampleRate = EM_ASM_INT({
31465         try {
31466             var temp = new (window.AudioContext || window.webkitAudioContext)();
31467             var sampleRate = temp.sampleRate;
31468             temp.close();
31469             return sampleRate;
31470         } catch(e) {
31471             return 0;
31472         }
31473     }, 0);  /* Must pass in a dummy argument for C99 compatibility. */
31474
31475     if (pDeviceInfo->nativeDataFormats[0].sampleRate == 0) {
31476         return MA_NO_DEVICE;
31477     }
31478
31479     pDeviceInfo->nativeDataFormatCount = 1;
31480
31481     return MA_SUCCESS;
31482 }
31483
31484
31485 static void ma_device_uninit_by_index__webaudio(ma_device* pDevice, ma_device_type deviceType, int deviceIndex)
31486 {
31487     MA_ASSERT(pDevice != NULL);
31488
31489     EM_ASM({
31490         var device = miniaudio.get_device_by_index($0);
31491
31492         /* Make sure all nodes are disconnected and marked for collection. */
31493         if (device.scriptNode !== undefined) {
31494             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... */
31495             device.scriptNode.disconnect();
31496             device.scriptNode = undefined;
31497         }
31498         if (device.streamNode !== undefined) {
31499             device.streamNode.disconnect();
31500             device.streamNode = undefined;
31501         }
31502
31503         /*
31504         Stop the device. I think there is a chance the callback could get fired after calling this, hence why we want
31505         to clear the callback before closing.
31506         */
31507         device.webaudio.close();
31508         device.webaudio = undefined;
31509
31510         /* Can't forget to free the intermediary buffer. This is the buffer that's shared between JavaScript and C. */
31511         if (device.intermediaryBuffer !== undefined) {
31512             Module._free(device.intermediaryBuffer);
31513             device.intermediaryBuffer = undefined;
31514             device.intermediaryBufferView = undefined;
31515             device.intermediaryBufferSizeInBytes = undefined;
31516         }
31517
31518         /* Make sure the device is untracked so the slot can be reused later. */
31519         miniaudio.untrack_device_by_index($0);
31520     }, deviceIndex, deviceType);
31521 }
31522
31523 static ma_result ma_device_uninit__webaudio(ma_device* pDevice)
31524 {
31525     MA_ASSERT(pDevice != NULL);
31526
31527     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
31528         ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture);
31529     }
31530
31531     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
31532         ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_playback, pDevice->webaudio.indexPlayback);
31533     }
31534
31535     return MA_SUCCESS;
31536 }
31537
31538 static ma_uint32 ma_calculate_period_size_in_frames_from_descriptor__webaudio(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
31539 {
31540     /*
31541     There have been reports of the default buffer size being too small on some browsers. There have been reports of the default buffer
31542     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
31543     standard defaults.
31544     */
31545     ma_uint32 periodSizeInFrames;
31546
31547     if (pDescriptor->periodSizeInFrames == 0) {
31548         if (pDescriptor->periodSizeInMilliseconds == 0) {
31549             if (performanceProfile == ma_performance_profile_low_latency) {
31550                 periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(33, nativeSampleRate);  /* 1 frame @ 30 FPS */
31551             } else {
31552                 periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(333, nativeSampleRate);
31553             }
31554         } else {
31555             periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate);
31556         }
31557     } else {
31558         periodSizeInFrames = pDescriptor->periodSizeInFrames;
31559     }
31560
31561     /* The size of the buffer must be a power of 2 and between 256 and 16384. */
31562     if (periodSizeInFrames < 256) {
31563         periodSizeInFrames = 256;
31564     } else if (periodSizeInFrames > 16384) {
31565         periodSizeInFrames = 16384;
31566     } else {
31567         periodSizeInFrames = ma_next_power_of_2(periodSizeInFrames);
31568     }
31569
31570     return periodSizeInFrames;
31571 }
31572
31573 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)
31574 {
31575     int deviceIndex;
31576     ma_uint32 channels;
31577     ma_uint32 sampleRate;
31578     ma_uint32 periodSizeInFrames;
31579
31580     MA_ASSERT(pDevice    != NULL);
31581     MA_ASSERT(pConfig    != NULL);
31582     MA_ASSERT(deviceType != ma_device_type_duplex);
31583
31584     if (deviceType == ma_device_type_capture && !ma_is_capture_supported__webaudio()) {
31585         return MA_NO_DEVICE;
31586     }
31587
31588     /* We're going to calculate some stuff in C just to simplify the JS code. */
31589     channels           = (pDescriptor->channels   > 0) ? pDescriptor->channels   : MA_DEFAULT_CHANNELS;
31590     sampleRate         = (pDescriptor->sampleRate > 0) ? pDescriptor->sampleRate : MA_DEFAULT_SAMPLE_RATE;
31591     periodSizeInFrames = ma_calculate_period_size_in_frames_from_descriptor__webaudio(pDescriptor, sampleRate, pConfig->performanceProfile);
31592
31593
31594     /* 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. */
31595     deviceIndex = EM_ASM_INT({
31596         var channels   = $0;
31597         var sampleRate = $1;
31598         var bufferSize = $2;    /* In PCM frames. */
31599         var isCapture  = $3;
31600         var pDevice    = $4;
31601
31602         if (typeof(miniaudio) === 'undefined') {
31603             return -1;  /* Context not initialized. */
31604         }
31605
31606         var device = {};
31607
31608         /* The AudioContext must be created in a suspended state. */
31609         device.webaudio = new (window.AudioContext || window.webkitAudioContext)({sampleRate:sampleRate});
31610         device.webaudio.suspend();
31611         device.state = 1; /* MA_STATE_STOPPED */
31612
31613         /*
31614         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
31615         JavaScript and C it needs to be allocated and freed using Module._malloc() and Module._free().
31616         */
31617         device.intermediaryBufferSizeInBytes = channels * bufferSize * 4;
31618         device.intermediaryBuffer = Module._malloc(device.intermediaryBufferSizeInBytes);
31619         device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes);
31620
31621         /*
31622         Both playback and capture devices use a ScriptProcessorNode for performing per-sample operations.
31623
31624         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
31625         that's periodically fired, just like a normal audio callback function. But apparently this design is "flawed" and is now deprecated in favour of
31626         something called AudioWorklets which _forces_ you to load a _separate_ .js file at run time... nice... Hopefully ScriptProcessorNode will continue to
31627         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
31628         implementation. I'll be avoiding that insane AudioWorklet API like the plague...
31629
31630         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
31631         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
31632         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
31633         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
31634         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
31635         this for now. If anyone knows how I could get raw PCM data using the MediaRecorder API please let me know!
31636         */
31637         device.scriptNode = device.webaudio.createScriptProcessor(bufferSize, channels, channels);
31638
31639         if (isCapture) {
31640             device.scriptNode.onaudioprocess = function(e) {
31641                 if (device.intermediaryBuffer === undefined) {
31642                     return; /* This means the device has been uninitialized. */
31643                 }
31644
31645                 if(device.intermediaryBufferView.length == 0) {
31646                     /* Recreate intermediaryBufferView when losing reference to the underlying buffer, probably due to emscripten resizing heap. */
31647                     device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes);
31648                 }
31649
31650                 /* Make sure silence it output to the AudioContext destination. Not doing this will cause sound to come out of the speakers! */
31651                 for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
31652                     e.outputBuffer.getChannelData(iChannel).fill(0.0);
31653                 }
31654
31655                 /* There are some situations where we may want to send silence to the client. */
31656                 var sendSilence = false;
31657                 if (device.streamNode === undefined) {
31658                     sendSilence = true;
31659                 }
31660
31661                 /* Sanity check. This will never happen, right? */
31662                 if (e.inputBuffer.numberOfChannels != channels) {
31663                     console.log("Capture: Channel count mismatch. " + e.inputBufer.numberOfChannels + " != " + channels + ". Sending silence.");
31664                     sendSilence = true;
31665                 }
31666
31667                 /* This looped design guards against the situation where e.inputBuffer is a different size to the original buffer size. Should never happen in practice. */
31668                 var totalFramesProcessed = 0;
31669                 while (totalFramesProcessed < e.inputBuffer.length) {
31670                     var framesRemaining = e.inputBuffer.length - totalFramesProcessed;
31671                     var framesToProcess = framesRemaining;
31672                     if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) {
31673                         framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4);
31674                     }
31675
31676                     /* 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. */
31677                     if (sendSilence) {
31678                         device.intermediaryBufferView.fill(0.0);
31679                     } else {
31680                         for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) {
31681                             for (var iChannel = 0; iChannel < e.inputBuffer.numberOfChannels; ++iChannel) {
31682                                 device.intermediaryBufferView[iFrame*channels + iChannel] = e.inputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame];
31683                             }
31684                         }
31685                     }
31686
31687                     /* Send data to the client from our intermediary buffer. */
31688                     ccall("ma_device_process_pcm_frames_capture__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]);
31689
31690                     totalFramesProcessed += framesToProcess;
31691                 }
31692             };
31693
31694             navigator.mediaDevices.getUserMedia({audio:true, video:false})
31695                 .then(function(stream) {
31696                     device.streamNode = device.webaudio.createMediaStreamSource(stream);
31697                     device.streamNode.connect(device.scriptNode);
31698                     device.scriptNode.connect(device.webaudio.destination);
31699                 })
31700                 .catch(function(error) {
31701                     /* I think this should output silence... */
31702                     device.scriptNode.connect(device.webaudio.destination);
31703                 });
31704         } else {
31705             device.scriptNode.onaudioprocess = function(e) {
31706                 if (device.intermediaryBuffer === undefined) {
31707                     return; /* This means the device has been uninitialized. */
31708                 }
31709
31710                 if(device.intermediaryBufferView.length == 0) {
31711                     /* Recreate intermediaryBufferView when losing reference to the underlying buffer, probably due to emscripten resizing heap. */
31712                     device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, device.intermediaryBuffer, device.intermediaryBufferSizeInBytes);
31713                 }
31714
31715                 var outputSilence = false;
31716
31717                 /* Sanity check. This will never happen, right? */
31718                 if (e.outputBuffer.numberOfChannels != channels) {
31719                     console.log("Playback: Channel count mismatch. " + e.outputBufer.numberOfChannels + " != " + channels + ". Outputting silence.");
31720                     outputSilence = true;
31721                     return;
31722                 }
31723
31724                 /* This looped design guards against the situation where e.outputBuffer is a different size to the original buffer size. Should never happen in practice. */
31725                 var totalFramesProcessed = 0;
31726                 while (totalFramesProcessed < e.outputBuffer.length) {
31727                     var framesRemaining = e.outputBuffer.length - totalFramesProcessed;
31728                     var framesToProcess = framesRemaining;
31729                     if (framesToProcess > (device.intermediaryBufferSizeInBytes/channels/4)) {
31730                         framesToProcess = (device.intermediaryBufferSizeInBytes/channels/4);
31731                     }
31732
31733                     /* Read data from the client into our intermediary buffer. */
31734                     ccall("ma_device_process_pcm_frames_playback__webaudio", "undefined", ["number", "number", "number"], [pDevice, framesToProcess, device.intermediaryBuffer]);
31735
31736                     /* At this point we'll have data in our intermediary buffer which we now need to deinterleave and copy over to the output buffers. */
31737                     if (outputSilence) {
31738                         for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
31739                             e.outputBuffer.getChannelData(iChannel).fill(0.0);
31740                         }
31741                     } else {
31742                         for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) {
31743                             for (var iFrame = 0; iFrame < framesToProcess; ++iFrame) {
31744                                 e.outputBuffer.getChannelData(iChannel)[totalFramesProcessed + iFrame] = device.intermediaryBufferView[iFrame*channels + iChannel];
31745                             }
31746                         }
31747                     }
31748
31749                     totalFramesProcessed += framesToProcess;
31750                 }
31751             };
31752
31753             device.scriptNode.connect(device.webaudio.destination);
31754         }
31755
31756         return miniaudio.track_device(device);
31757     }, channels, sampleRate, periodSizeInFrames, deviceType == ma_device_type_capture, pDevice);
31758
31759     if (deviceIndex < 0) {
31760         return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
31761     }
31762
31763     if (deviceType == ma_device_type_capture) {
31764         pDevice->webaudio.indexCapture  = deviceIndex;
31765     } else {
31766         pDevice->webaudio.indexPlayback = deviceIndex;
31767     }
31768
31769     pDescriptor->format              = ma_format_f32;
31770     pDescriptor->channels            = channels;
31771     ma_get_standard_channel_map(ma_standard_channel_map_webaudio, pDescriptor->channels, pDescriptor->channelMap);
31772     pDescriptor->sampleRate          = EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex);
31773     pDescriptor->periodSizeInFrames  = periodSizeInFrames;
31774     pDescriptor->periodCount         = 1;
31775
31776     return MA_SUCCESS;
31777 }
31778
31779 static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
31780 {
31781     ma_result result;
31782
31783     if (pConfig->deviceType == ma_device_type_loopback) {
31784         return MA_DEVICE_TYPE_NOT_SUPPORTED;
31785     }
31786
31787     /* No exclusive mode with Web Audio. */
31788     if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) ||
31789         ((pConfig->deviceType == ma_device_type_capture  || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode  == ma_share_mode_exclusive)) {
31790         return MA_SHARE_MODE_NOT_SUPPORTED;
31791     }
31792
31793     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
31794         result = ma_device_init_by_type__webaudio(pDevice, pConfig, pDescriptorCapture, ma_device_type_capture);
31795         if (result != MA_SUCCESS) {
31796             return result;
31797         }
31798     }
31799
31800     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
31801         result = ma_device_init_by_type__webaudio(pDevice, pConfig, pDescriptorPlayback, ma_device_type_playback);
31802         if (result != MA_SUCCESS) {
31803             if (pConfig->deviceType == ma_device_type_duplex) {
31804                 ma_device_uninit_by_index__webaudio(pDevice, ma_device_type_capture, pDevice->webaudio.indexCapture);
31805             }
31806             return result;
31807         }
31808     }
31809
31810     return MA_SUCCESS;
31811 }
31812
31813 static ma_result ma_device_start__webaudio(ma_device* pDevice)
31814 {
31815     MA_ASSERT(pDevice != NULL);
31816
31817     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
31818         EM_ASM({
31819             var device = miniaudio.get_device_by_index($0);
31820             device.webaudio.resume();
31821             device.state = 2; /* MA_STATE_STARTED */
31822         }, pDevice->webaudio.indexCapture);
31823     }
31824
31825     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
31826         EM_ASM({
31827             var device = miniaudio.get_device_by_index($0);
31828             device.webaudio.resume();
31829             device.state = 2; /* MA_STATE_STARTED */
31830         }, pDevice->webaudio.indexPlayback);
31831     }
31832
31833     return MA_SUCCESS;
31834 }
31835
31836 static ma_result ma_device_stop__webaudio(ma_device* pDevice)
31837 {
31838     MA_ASSERT(pDevice != NULL);
31839
31840     /*
31841     From the WebAudio API documentation for AudioContext.suspend():
31842
31843         Suspends the progression of AudioContext's currentTime, allows any current context processing blocks that are already processed to be played to the
31844         destination, and then allows the system to release its claim on audio hardware.
31845
31846     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
31847     do any kind of explicit draining.
31848     */
31849
31850     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
31851         EM_ASM({
31852             var device = miniaudio.get_device_by_index($0);
31853             device.webaudio.suspend();
31854             device.state = 1; /* MA_STATE_STOPPED */
31855         }, pDevice->webaudio.indexCapture);
31856     }
31857
31858     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
31859         EM_ASM({
31860             var device = miniaudio.get_device_by_index($0);
31861             device.webaudio.suspend();
31862             device.state = 1; /* MA_STATE_STOPPED */
31863         }, pDevice->webaudio.indexPlayback);
31864     }
31865
31866     ma_stop_proc onStop = pDevice->onStop;
31867     if (onStop) {
31868         onStop(pDevice);
31869     }
31870
31871     return MA_SUCCESS;
31872 }
31873
31874 static ma_result ma_context_uninit__webaudio(ma_context* pContext)
31875 {
31876     MA_ASSERT(pContext != NULL);
31877     MA_ASSERT(pContext->backend == ma_backend_webaudio);
31878
31879     /* Nothing needs to be done here. */
31880     (void)pContext;
31881
31882     return MA_SUCCESS;
31883 }
31884
31885 static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
31886 {
31887     int resultFromJS;
31888
31889     MA_ASSERT(pContext != NULL);
31890
31891     (void)pConfig; /* Unused. */
31892
31893     /* Here is where our global JavaScript object is initialized. */
31894     resultFromJS = EM_ASM_INT({
31895         if ((window.AudioContext || window.webkitAudioContext) === undefined) {
31896             return 0;   /* Web Audio not supported. */
31897         }
31898
31899         if (typeof(miniaudio) === 'undefined') {
31900             miniaudio = {};
31901             miniaudio.devices = [];   /* Device cache for mapping devices to indexes for JavaScript/C interop. */
31902
31903             miniaudio.track_device = function(device) {
31904                 /* Try inserting into a free slot first. */
31905                 for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) {
31906                     if (miniaudio.devices[iDevice] == null) {
31907                         miniaudio.devices[iDevice] = device;
31908                         return iDevice;
31909                     }
31910                 }
31911
31912                 /* Getting here means there is no empty slots in the array so we just push to the end. */
31913                 miniaudio.devices.push(device);
31914                 return miniaudio.devices.length - 1;
31915             };
31916
31917             miniaudio.untrack_device_by_index = function(deviceIndex) {
31918                 /* We just set the device's slot to null. The slot will get reused in the next call to ma_track_device. */
31919                 miniaudio.devices[deviceIndex] = null;
31920
31921                 /* Trim the array if possible. */
31922                 while (miniaudio.devices.length > 0) {
31923                     if (miniaudio.devices[miniaudio.devices.length-1] == null) {
31924                         miniaudio.devices.pop();
31925                     } else {
31926                         break;
31927                     }
31928                 }
31929             };
31930
31931             miniaudio.untrack_device = function(device) {
31932                 for (var iDevice = 0; iDevice < miniaudio.devices.length; ++iDevice) {
31933                     if (miniaudio.devices[iDevice] == device) {
31934                         return miniaudio.untrack_device_by_index(iDevice);
31935                     }
31936                 }
31937             };
31938
31939             miniaudio.get_device_by_index = function(deviceIndex) {
31940                 return miniaudio.devices[deviceIndex];
31941             };
31942
31943             miniaudio.unlock_event_types = (function(){
31944                 return ['touchstart', 'touchend', 'click'];
31945             })();
31946
31947             miniaudio.unlock = function() {
31948                 for(var i = 0; i < miniaudio.devices.length; ++i) {
31949                     var device = miniaudio.devices[i];
31950                     if (device != null && device.webaudio != null && device.state === 2 /* MA_STATE_STARTED */) {
31951                         device.webaudio.resume();
31952                     }
31953                 }
31954                 miniaudio.unlock_event_types.map(function(event_type) {
31955                     document.removeEventListener(event_type, miniaudio.unlock, true);
31956                 });
31957             };
31958
31959             miniaudio.unlock_event_types.map(function(event_type) {
31960                 document.addEventListener(event_type, miniaudio.unlock, true);
31961             });
31962         }
31963
31964         return 1;
31965     }, 0);  /* Must pass in a dummy argument for C99 compatibility. */
31966
31967     if (resultFromJS != 1) {
31968         return MA_FAILED_TO_INIT_BACKEND;
31969     }
31970
31971     pCallbacks->onContextInit             = ma_context_init__webaudio;
31972     pCallbacks->onContextUninit           = ma_context_uninit__webaudio;
31973     pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__webaudio;
31974     pCallbacks->onContextGetDeviceInfo    = ma_context_get_device_info__webaudio;
31975     pCallbacks->onDeviceInit              = ma_device_init__webaudio;
31976     pCallbacks->onDeviceUninit            = ma_device_uninit__webaudio;
31977     pCallbacks->onDeviceStart             = ma_device_start__webaudio;
31978     pCallbacks->onDeviceStop              = ma_device_stop__webaudio;
31979     pCallbacks->onDeviceRead              = NULL;   /* Not needed because WebAudio is asynchronous. */
31980     pCallbacks->onDeviceWrite             = NULL;   /* Not needed because WebAudio is asynchronous. */
31981     pCallbacks->onDeviceDataLoop          = NULL;   /* Not needed because WebAudio is asynchronous. */
31982
31983     return MA_SUCCESS;
31984 }
31985 #endif  /* Web Audio */
31986
31987
31988
31989 static ma_bool32 ma__is_channel_map_valid(const ma_channel* channelMap, ma_uint32 channels)
31990 {
31991     /* A blank channel map should be allowed, in which case it should use an appropriate default which will depend on context. */
31992     if (channelMap[0] != MA_CHANNEL_NONE) {
31993         ma_uint32 iChannel;
31994
31995         if (channels == 0 || channels > MA_MAX_CHANNELS) {
31996             return MA_FALSE;   /* Channel count out of range. */
31997         }
31998
31999         /* A channel cannot be present in the channel map more than once. */
32000         for (iChannel = 0; iChannel < channels; ++iChannel) {
32001             ma_uint32 jChannel;
32002             for (jChannel = iChannel + 1; jChannel < channels; ++jChannel) {
32003                 if (channelMap[iChannel] == channelMap[jChannel]) {
32004                     return MA_FALSE;
32005                 }
32006             }
32007         }
32008     }
32009
32010     return MA_TRUE;
32011 }
32012
32013
32014 static ma_result ma_device__post_init_setup(ma_device* pDevice, ma_device_type deviceType)
32015 {
32016     ma_result result;
32017
32018     MA_ASSERT(pDevice != NULL);
32019
32020     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
32021         if (pDevice->capture.format == ma_format_unknown) {
32022             pDevice->capture.format = pDevice->capture.internalFormat;
32023         }
32024         if (pDevice->capture.channels == 0) {
32025             pDevice->capture.channels = pDevice->capture.internalChannels;
32026         }
32027         if (pDevice->capture.channelMap[0] == MA_CHANNEL_NONE) {
32028             MA_ASSERT(pDevice->capture.channels <= MA_MAX_CHANNELS);
32029             if (pDevice->capture.internalChannels == pDevice->capture.channels) {
32030                 ma_channel_map_copy(pDevice->capture.channelMap, pDevice->capture.internalChannelMap, pDevice->capture.channels);
32031             } else {
32032                 if (pDevice->capture.channelMixMode == ma_channel_mix_mode_simple) {
32033                     ma_channel_map_init_blank(pDevice->capture.channels, pDevice->capture.channelMap);
32034                 } else {
32035                     ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->capture.channels, pDevice->capture.channelMap);
32036                 }
32037             }
32038         }
32039     }
32040
32041     if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
32042         if (pDevice->playback.format == ma_format_unknown) {
32043             pDevice->playback.format = pDevice->playback.internalFormat;
32044         }
32045         if (pDevice->playback.channels == 0) {
32046             pDevice->playback.channels = pDevice->playback.internalChannels;
32047         }
32048         if (pDevice->playback.channelMap[0] == MA_CHANNEL_NONE) {
32049             MA_ASSERT(pDevice->playback.channels <= MA_MAX_CHANNELS);
32050             if (pDevice->playback.internalChannels == pDevice->playback.channels) {
32051                 ma_channel_map_copy(pDevice->playback.channelMap, pDevice->playback.internalChannelMap, pDevice->playback.channels);
32052             } else {
32053                 if (pDevice->playback.channelMixMode == ma_channel_mix_mode_simple) {
32054                     ma_channel_map_init_blank(pDevice->playback.channels, pDevice->playback.channelMap);
32055                 } else {
32056                     ma_get_standard_channel_map(ma_standard_channel_map_default, pDevice->playback.channels, pDevice->playback.channelMap);
32057                 }
32058             }
32059         }
32060     }
32061
32062     if (pDevice->sampleRate == 0) {
32063         if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
32064             pDevice->sampleRate = pDevice->capture.internalSampleRate;
32065         } else {
32066             pDevice->sampleRate = pDevice->playback.internalSampleRate;
32067         }
32068     }
32069
32070     /* Data converters. */
32071     if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) {
32072         /* Converting from internal device format to client format. */
32073         ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
32074         converterConfig.formatIn                   = pDevice->capture.internalFormat;
32075         converterConfig.channelsIn                 = pDevice->capture.internalChannels;
32076         converterConfig.sampleRateIn               = pDevice->capture.internalSampleRate;
32077         ma_channel_map_copy(converterConfig.channelMapIn, pDevice->capture.internalChannelMap, ma_min(pDevice->capture.internalChannels, MA_MAX_CHANNELS));
32078         converterConfig.formatOut                  = pDevice->capture.format;
32079         converterConfig.channelsOut                = pDevice->capture.channels;
32080         converterConfig.sampleRateOut              = pDevice->sampleRate;
32081         ma_channel_map_copy(converterConfig.channelMapOut, pDevice->capture.channelMap, ma_min(pDevice->capture.channels, MA_MAX_CHANNELS));
32082         converterConfig.channelMixMode             = pDevice->capture.channelMixMode;
32083         converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
32084         converterConfig.resampling.algorithm       = pDevice->resampling.algorithm;
32085         converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
32086         converterConfig.resampling.speex.quality   = pDevice->resampling.speex.quality;
32087
32088         result = ma_data_converter_init(&converterConfig, &pDevice->capture.converter);
32089         if (result != MA_SUCCESS) {
32090             return result;
32091         }
32092     }
32093
32094     if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
32095         /* Converting from client format to device format. */
32096         ma_data_converter_config converterConfig = ma_data_converter_config_init_default();
32097         converterConfig.formatIn                   = pDevice->playback.format;
32098         converterConfig.channelsIn                 = pDevice->playback.channels;
32099         converterConfig.sampleRateIn               = pDevice->sampleRate;
32100         ma_channel_map_copy(converterConfig.channelMapIn, pDevice->playback.channelMap, ma_min(pDevice->playback.channels, MA_MAX_CHANNELS));
32101         converterConfig.formatOut                  = pDevice->playback.internalFormat;
32102         converterConfig.channelsOut                = pDevice->playback.internalChannels;
32103         converterConfig.sampleRateOut              = pDevice->playback.internalSampleRate;
32104         ma_channel_map_copy(converterConfig.channelMapOut, pDevice->playback.internalChannelMap, ma_min(pDevice->playback.internalChannels, MA_MAX_CHANNELS));
32105         converterConfig.channelMixMode             = pDevice->playback.channelMixMode;
32106         converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;
32107         converterConfig.resampling.algorithm       = pDevice->resampling.algorithm;
32108         converterConfig.resampling.linear.lpfOrder = pDevice->resampling.linear.lpfOrder;
32109         converterConfig.resampling.speex.quality   = pDevice->resampling.speex.quality;
32110
32111         result = ma_data_converter_init(&converterConfig, &pDevice->playback.converter);
32112         if (result != MA_SUCCESS) {
32113             return result;
32114         }
32115     }
32116
32117     return MA_SUCCESS;
32118 }
32119
32120
32121 static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData)
32122 {
32123     ma_device* pDevice = (ma_device*)pData;
32124     MA_ASSERT(pDevice != NULL);
32125
32126 #ifdef MA_WIN32
32127     ma_CoInitializeEx(pDevice->pContext, NULL, MA_COINIT_VALUE);
32128 #endif
32129
32130     /*
32131     When the device is being initialized it's initial state is set to MA_STATE_UNINITIALIZED. Before returning from
32132     ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately
32133     after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker
32134     thread to signal an event to know when the worker thread is ready for action.
32135     */
32136     ma_device__set_state(pDevice, MA_STATE_STOPPED);
32137     ma_event_signal(&pDevice->stopEvent);
32138
32139     for (;;) {  /* <-- This loop just keeps the thread alive. The main audio loop is inside. */
32140         ma_stop_proc onStop;
32141
32142         /* We wait on an event to know when something has requested that the device be started and the main loop entered. */
32143         ma_event_wait(&pDevice->wakeupEvent);
32144
32145         /* Default result code. */
32146         pDevice->workResult = MA_SUCCESS;
32147
32148         /* If the reason for the wake up is that we are terminating, just break from the loop. */
32149         if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) {
32150             break;
32151         }
32152
32153         /*
32154         Getting to this point means the device is wanting to get started. The function that has requested that the device
32155         be started will be waiting on an event (pDevice->startEvent) which means we need to make sure we signal the event
32156         in both the success and error case. It's important that the state of the device is set _before_ signaling the event.
32157         */
32158         MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STARTING);
32159
32160         /* If the device has a start callback, start it now. */
32161         if (pDevice->pContext->callbacks.onDeviceStart != NULL) {
32162             ma_result result = pDevice->pContext->callbacks.onDeviceStart(pDevice);
32163             if (result != MA_SUCCESS) {
32164                 pDevice->workResult = result;   /* Failed to start the device. */
32165             }
32166         }
32167
32168         /* Make sure the state is set appropriately. */
32169         ma_device__set_state(pDevice, MA_STATE_STARTED);
32170         ma_event_signal(&pDevice->startEvent);
32171
32172         if (pDevice->pContext->callbacks.onDeviceDataLoop != NULL) {
32173             pDevice->pContext->callbacks.onDeviceDataLoop(pDevice);
32174         } else {
32175             /* The backend is not using a custom main loop implementation, so now fall back to the blocking read-write implementation. */
32176             ma_device_audio_thread__default_read_write(pDevice);
32177         }
32178
32179         /*
32180         Getting here means we have broken from the main loop which happens the application has requested that device be stopped. Note that this
32181         may have actually already happened above if the device was lost and miniaudio has attempted to re-initialize the device. In this case we
32182         don't want to be doing this a second time.
32183         */
32184         if (ma_device_get_state(pDevice) != MA_STATE_UNINITIALIZED) {
32185             if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
32186                 pDevice->pContext->callbacks.onDeviceStop(pDevice);
32187             }
32188         }
32189
32190         /* After the device has stopped, make sure an event is posted. */
32191         onStop = pDevice->onStop;
32192         if (onStop) {
32193             onStop(pDevice);
32194         }
32195
32196         /*
32197         A function somewhere is waiting for the device to have stopped for real so we need to signal an event to allow it to continue. Note that
32198         it's possible that the device has been uninitialized which means we need to _not_ change the status to stopped. We cannot go from an
32199         uninitialized state to stopped state.
32200         */
32201         if (ma_device_get_state(pDevice) != MA_STATE_UNINITIALIZED) {
32202             ma_device__set_state(pDevice, MA_STATE_STOPPED);
32203             ma_event_signal(&pDevice->stopEvent);
32204         }
32205     }
32206
32207     /* Make sure we aren't continuously waiting on a stop event. */
32208     ma_event_signal(&pDevice->stopEvent);  /* <-- Is this still needed? */
32209
32210 #ifdef MA_WIN32
32211     ma_CoUninitialize(pDevice->pContext);
32212 #endif
32213
32214     return (ma_thread_result)0;
32215 }
32216
32217
32218 /* Helper for determining whether or not the given device is initialized. */
32219 static ma_bool32 ma_device__is_initialized(ma_device* pDevice)
32220 {
32221     if (pDevice == NULL) {
32222         return MA_FALSE;
32223     }
32224
32225     return ma_device_get_state(pDevice) != MA_STATE_UNINITIALIZED;
32226 }
32227
32228
32229 #ifdef MA_WIN32
32230 static ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext)
32231 {
32232     ma_CoUninitialize(pContext);
32233     ma_dlclose(pContext, pContext->win32.hUser32DLL);
32234     ma_dlclose(pContext, pContext->win32.hOle32DLL);
32235     ma_dlclose(pContext, pContext->win32.hAdvapi32DLL);
32236
32237     return MA_SUCCESS;
32238 }
32239
32240 static ma_result ma_context_init_backend_apis__win32(ma_context* pContext)
32241 {
32242 #ifdef MA_WIN32_DESKTOP
32243     /* Ole32.dll */
32244     pContext->win32.hOle32DLL = ma_dlopen(pContext, "ole32.dll");
32245     if (pContext->win32.hOle32DLL == NULL) {
32246         return MA_FAILED_TO_INIT_BACKEND;
32247     }
32248
32249     pContext->win32.CoInitializeEx   = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx");
32250     pContext->win32.CoUninitialize   = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize");
32251     pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance");
32252     pContext->win32.CoTaskMemFree    = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoTaskMemFree");
32253     pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "PropVariantClear");
32254     pContext->win32.StringFromGUID2  = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "StringFromGUID2");
32255
32256
32257     /* User32.dll */
32258     pContext->win32.hUser32DLL = ma_dlopen(pContext, "user32.dll");
32259     if (pContext->win32.hUser32DLL == NULL) {
32260         return MA_FAILED_TO_INIT_BACKEND;
32261     }
32262
32263     pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetForegroundWindow");
32264     pContext->win32.GetDesktopWindow    = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetDesktopWindow");
32265
32266
32267     /* Advapi32.dll */
32268     pContext->win32.hAdvapi32DLL = ma_dlopen(pContext, "advapi32.dll");
32269     if (pContext->win32.hAdvapi32DLL == NULL) {
32270         return MA_FAILED_TO_INIT_BACKEND;
32271     }
32272
32273     pContext->win32.RegOpenKeyExA    = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegOpenKeyExA");
32274     pContext->win32.RegCloseKey      = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegCloseKey");
32275     pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA");
32276 #endif
32277
32278     ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE);
32279     return MA_SUCCESS;
32280 }
32281 #else
32282 static ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext)
32283 {
32284 #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
32285     ma_dlclose(pContext, pContext->posix.pthreadSO);
32286 #else
32287     (void)pContext;
32288 #endif
32289
32290     return MA_SUCCESS;
32291 }
32292
32293 static ma_result ma_context_init_backend_apis__nix(ma_context* pContext)
32294 {
32295     /* pthread */
32296 #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING)
32297     const char* libpthreadFileNames[] = {
32298         "libpthread.so",
32299         "libpthread.so.0",
32300         "libpthread.dylib"
32301     };
32302     size_t i;
32303
32304     for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) {
32305         pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]);
32306         if (pContext->posix.pthreadSO != NULL) {
32307             break;
32308         }
32309     }
32310
32311     if (pContext->posix.pthreadSO == NULL) {
32312         return MA_FAILED_TO_INIT_BACKEND;
32313     }
32314
32315     pContext->posix.pthread_create              = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create");
32316     pContext->posix.pthread_join                = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join");
32317     pContext->posix.pthread_mutex_init          = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init");
32318     pContext->posix.pthread_mutex_destroy       = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy");
32319     pContext->posix.pthread_mutex_lock          = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock");
32320     pContext->posix.pthread_mutex_unlock        = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock");
32321     pContext->posix.pthread_cond_init           = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init");
32322     pContext->posix.pthread_cond_destroy        = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy");
32323     pContext->posix.pthread_cond_wait           = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait");
32324     pContext->posix.pthread_cond_signal         = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal");
32325     pContext->posix.pthread_attr_init           = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init");
32326     pContext->posix.pthread_attr_destroy        = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy");
32327     pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy");
32328     pContext->posix.pthread_attr_getschedparam  = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam");
32329     pContext->posix.pthread_attr_setschedparam  = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam");
32330 #else
32331     pContext->posix.pthread_create              = (ma_proc)pthread_create;
32332     pContext->posix.pthread_join                = (ma_proc)pthread_join;
32333     pContext->posix.pthread_mutex_init          = (ma_proc)pthread_mutex_init;
32334     pContext->posix.pthread_mutex_destroy       = (ma_proc)pthread_mutex_destroy;
32335     pContext->posix.pthread_mutex_lock          = (ma_proc)pthread_mutex_lock;
32336     pContext->posix.pthread_mutex_unlock        = (ma_proc)pthread_mutex_unlock;
32337     pContext->posix.pthread_cond_init           = (ma_proc)pthread_cond_init;
32338     pContext->posix.pthread_cond_destroy        = (ma_proc)pthread_cond_destroy;
32339     pContext->posix.pthread_cond_wait           = (ma_proc)pthread_cond_wait;
32340     pContext->posix.pthread_cond_signal         = (ma_proc)pthread_cond_signal;
32341     pContext->posix.pthread_attr_init           = (ma_proc)pthread_attr_init;
32342     pContext->posix.pthread_attr_destroy        = (ma_proc)pthread_attr_destroy;
32343 #if !defined(__EMSCRIPTEN__)
32344     pContext->posix.pthread_attr_setschedpolicy = (ma_proc)pthread_attr_setschedpolicy;
32345     pContext->posix.pthread_attr_getschedparam  = (ma_proc)pthread_attr_getschedparam;
32346     pContext->posix.pthread_attr_setschedparam  = (ma_proc)pthread_attr_setschedparam;
32347 #endif
32348 #endif
32349
32350     return MA_SUCCESS;
32351 }
32352 #endif
32353
32354 static ma_result ma_context_init_backend_apis(ma_context* pContext)
32355 {
32356     ma_result result;
32357 #ifdef MA_WIN32
32358     result = ma_context_init_backend_apis__win32(pContext);
32359 #else
32360     result = ma_context_init_backend_apis__nix(pContext);
32361 #endif
32362
32363     return result;
32364 }
32365
32366 static ma_result ma_context_uninit_backend_apis(ma_context* pContext)
32367 {
32368     ma_result result;
32369 #ifdef MA_WIN32
32370     result = ma_context_uninit_backend_apis__win32(pContext);
32371 #else
32372     result = ma_context_uninit_backend_apis__nix(pContext);
32373 #endif
32374
32375     return result;
32376 }
32377
32378
32379 static ma_bool32 ma_context_is_backend_asynchronous(ma_context* pContext)
32380 {
32381     MA_ASSERT(pContext != NULL);
32382
32383     if (pContext->callbacks.onDeviceRead == NULL && pContext->callbacks.onDeviceWrite == NULL) {
32384         if (pContext->callbacks.onDeviceDataLoop == NULL) {
32385             return MA_TRUE;
32386         } else {
32387             return MA_FALSE;
32388         }
32389     } else {
32390         return MA_FALSE;
32391     }
32392 }
32393
32394
32395 MA_API ma_context_config ma_context_config_init()
32396 {
32397     ma_context_config config;
32398     MA_ZERO_OBJECT(&config);
32399
32400     return config;
32401 }
32402
32403 MA_API ma_result ma_context_init(const ma_backend backends[], ma_uint32 backendCount, const ma_context_config* pConfig, ma_context* pContext)
32404 {
32405     ma_result result;
32406     ma_context_config defaultConfig;
32407     ma_backend defaultBackends[ma_backend_null+1];
32408     ma_uint32 iBackend;
32409     ma_backend* pBackendsToIterate;
32410     ma_uint32 backendsToIterateCount;
32411
32412     if (pContext == NULL) {
32413         return MA_INVALID_ARGS;
32414     }
32415
32416     MA_ZERO_OBJECT(pContext);
32417
32418     /* Always make sure the config is set first to ensure properties are available as soon as possible. */
32419     if (pConfig == NULL) {
32420         defaultConfig = ma_context_config_init();
32421         pConfig = &defaultConfig;
32422     }
32423
32424     pContext->logCallback     = pConfig->logCallback;
32425     pContext->threadPriority  = pConfig->threadPriority;
32426     pContext->threadStackSize = pConfig->threadStackSize;
32427     pContext->pUserData       = pConfig->pUserData;
32428
32429     result = ma_allocation_callbacks_init_copy(&pContext->allocationCallbacks, &pConfig->allocationCallbacks);
32430     if (result != MA_SUCCESS) {
32431         return result;
32432     }
32433
32434     /* Backend APIs need to be initialized first. This is where external libraries will be loaded and linked. */
32435     result = ma_context_init_backend_apis(pContext);
32436     if (result != MA_SUCCESS) {
32437         return result;
32438     }
32439
32440     for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) {
32441         defaultBackends[iBackend] = (ma_backend)iBackend;
32442     }
32443
32444     pBackendsToIterate = (ma_backend*)backends;
32445     backendsToIterateCount = backendCount;
32446     if (pBackendsToIterate == NULL) {
32447         pBackendsToIterate = (ma_backend*)defaultBackends;
32448         backendsToIterateCount = ma_countof(defaultBackends);
32449     }
32450
32451     MA_ASSERT(pBackendsToIterate != NULL);
32452
32453     for (iBackend = 0; iBackend < backendsToIterateCount; iBackend += 1) {
32454         ma_backend backend = pBackendsToIterate[iBackend];
32455
32456         /* Make sure all callbacks are reset so we don't accidentally drag in any from previously failed initialization attempts. */
32457         MA_ZERO_OBJECT(&pContext->callbacks);
32458
32459         /* These backends are using the new callback system. */
32460         switch (backend) {
32461         #ifdef MA_HAS_WASAPI
32462             case ma_backend_wasapi:
32463             {
32464                 pContext->callbacks.onContextInit = ma_context_init__wasapi;
32465             } break;
32466         #endif
32467         #ifdef MA_HAS_DSOUND
32468             case ma_backend_dsound:
32469             {
32470                 pContext->callbacks.onContextInit = ma_context_init__dsound;
32471             } break;
32472         #endif
32473         #ifdef MA_HAS_WINMM
32474             case ma_backend_winmm:
32475             {
32476                 pContext->callbacks.onContextInit = ma_context_init__winmm;
32477             } break;
32478         #endif
32479         #ifdef MA_HAS_COREAUDIO
32480             case ma_backend_coreaudio:
32481             {
32482                 pContext->callbacks.onContextInit = ma_context_init__coreaudio;
32483             } break;
32484         #endif
32485         #ifdef MA_HAS_SNDIO
32486             case ma_backend_sndio:
32487             {
32488                 pContext->callbacks.onContextInit = ma_context_init__sndio;
32489             } break;
32490         #endif
32491         #ifdef MA_HAS_AUDIO4
32492             case ma_backend_audio4:
32493             {
32494                 pContext->callbacks.onContextInit = ma_context_init__audio4;
32495             } break;
32496         #endif
32497         #ifdef MA_HAS_OSS
32498             case ma_backend_oss:
32499             {
32500                 pContext->callbacks.onContextInit = ma_context_init__oss;
32501             } break;
32502         #endif
32503         #ifdef MA_HAS_PULSEAUDIO
32504             case ma_backend_pulseaudio:
32505             {
32506                 pContext->callbacks.onContextInit = ma_context_init__pulse;
32507             } break;
32508         #endif
32509         #ifdef MA_HAS_ALSA
32510             case ma_backend_alsa:
32511             {
32512                 pContext->callbacks.onContextInit = ma_context_init__alsa;
32513             } break;
32514         #endif
32515         #ifdef MA_HAS_JACK
32516             case ma_backend_jack:
32517             {
32518                 pContext->callbacks.onContextInit = ma_context_init__jack;
32519             } break;
32520         #endif
32521         #ifdef MA_HAS_AAUDIO
32522             case ma_backend_aaudio:
32523             {
32524                 pContext->callbacks.onContextInit = ma_context_init__aaudio;
32525             } break;
32526         #endif
32527         #ifdef MA_HAS_OPENSL
32528             case ma_backend_opensl:
32529             {
32530                 pContext->callbacks.onContextInit = ma_context_init__opensl;
32531             } break;
32532         #endif
32533         #ifdef MA_HAS_WEBAUDIO
32534             case ma_backend_webaudio:
32535             {
32536                 pContext->callbacks.onContextInit = ma_context_init__webaudio;
32537             } break;
32538         #endif
32539         #ifdef MA_HAS_CUSTOM
32540             case ma_backend_custom:
32541             {
32542                 /* Slightly different logic for custom backends. Custom backends can optionally set all of their callbacks in the config. */
32543                 pContext->callbacks = pConfig->custom;
32544             } break;
32545         #endif
32546         #ifdef MA_HAS_NULL
32547             case ma_backend_null:
32548             {
32549                 pContext->callbacks.onContextInit = ma_context_init__null;
32550             } break;
32551         #endif
32552
32553             default: break;
32554         }
32555
32556         if (pContext->callbacks.onContextInit != NULL) {
32557             ma_post_log_messagef(pContext, NULL, MA_LOG_LEVEL_VERBOSE, "Attempting to initialize %s backend...", ma_get_backend_name(backend));
32558             result = pContext->callbacks.onContextInit(pContext, pConfig, &pContext->callbacks);
32559         } else {
32560             result = MA_NO_BACKEND;
32561         }
32562
32563         /* If this iteration was successful, return. */
32564         if (result == MA_SUCCESS) {
32565             result = ma_mutex_init(&pContext->deviceEnumLock);
32566             if (result != MA_SUCCESS) {
32567                 ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device enumeration. ma_context_get_devices() is not thread safe.", result);
32568             }
32569
32570             result = ma_mutex_init(&pContext->deviceInfoLock);
32571             if (result != MA_SUCCESS) {
32572                 ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "Failed to initialize mutex for device info retrieval. ma_context_get_device_info() is not thread safe.", result);
32573             }
32574
32575             #ifdef MA_DEBUG_OUTPUT
32576             {
32577                 printf("[miniaudio] Endian:  %s\n", ma_is_little_endian() ? "LE" : "BE");
32578                 printf("[miniaudio] SSE2:    %s\n", ma_has_sse2()    ? "YES" : "NO");
32579                 printf("[miniaudio] AVX2:    %s\n", ma_has_avx2()    ? "YES" : "NO");
32580                 printf("[miniaudio] AVX512F: %s\n", ma_has_avx512f() ? "YES" : "NO");
32581                 printf("[miniaudio] NEON:    %s\n", ma_has_neon()    ? "YES" : "NO");
32582             }
32583             #endif
32584
32585             pContext->backend = backend;
32586             return result;
32587         } else {
32588             ma_post_log_messagef(pContext, NULL, MA_LOG_LEVEL_VERBOSE, "Failed to initialize %s backend.", ma_get_backend_name(backend));
32589         }
32590     }
32591
32592     /* If we get here it means an error occurred. */
32593     MA_ZERO_OBJECT(pContext);  /* Safety. */
32594     return MA_NO_BACKEND;
32595 }
32596
32597 MA_API ma_result ma_context_uninit(ma_context* pContext)
32598 {
32599     if (pContext == NULL) {
32600         return MA_INVALID_ARGS;
32601     }
32602
32603     if (pContext->callbacks.onContextUninit != NULL) {
32604         pContext->callbacks.onContextUninit(pContext);
32605     }
32606
32607     ma_mutex_uninit(&pContext->deviceEnumLock);
32608     ma_mutex_uninit(&pContext->deviceInfoLock);
32609     ma__free_from_callbacks(pContext->pDeviceInfos, &pContext->allocationCallbacks);
32610     ma_context_uninit_backend_apis(pContext);
32611
32612     return MA_SUCCESS;
32613 }
32614
32615 MA_API size_t ma_context_sizeof()
32616 {
32617     return sizeof(ma_context);
32618 }
32619
32620
32621 MA_API ma_result ma_context_enumerate_devices(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
32622 {
32623     ma_result result;
32624
32625     if (pContext == NULL || callback == NULL) {
32626         return MA_INVALID_ARGS;
32627     }
32628
32629     if (pContext->callbacks.onContextEnumerateDevices == NULL) {
32630         return MA_INVALID_OPERATION;
32631     }
32632
32633     ma_mutex_lock(&pContext->deviceEnumLock);
32634     {
32635         result = pContext->callbacks.onContextEnumerateDevices(pContext, callback, pUserData);
32636     }
32637     ma_mutex_unlock(&pContext->deviceEnumLock);
32638
32639     return result;
32640 }
32641
32642
32643 static ma_bool32 ma_context_get_devices__enum_callback(ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData)
32644 {
32645     /*
32646     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
32647     it's just appended to the end. If it's a playback device it's inserted just before the first capture device.
32648     */
32649
32650     /*
32651     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
32652     simple fixed size increment for buffer expansion.
32653     */
32654     const ma_uint32 bufferExpansionCount = 2;
32655     const ma_uint32 totalDeviceInfoCount = pContext->playbackDeviceInfoCount + pContext->captureDeviceInfoCount;
32656
32657     if (totalDeviceInfoCount >= pContext->deviceInfoCapacity) {
32658         ma_uint32 oldCapacity = pContext->deviceInfoCapacity;
32659         ma_uint32 newCapacity = oldCapacity + bufferExpansionCount;
32660         ma_device_info* pNewInfos = (ma_device_info*)ma__realloc_from_callbacks(pContext->pDeviceInfos, sizeof(*pContext->pDeviceInfos)*newCapacity, sizeof(*pContext->pDeviceInfos)*oldCapacity, &pContext->allocationCallbacks);
32661         if (pNewInfos == NULL) {
32662             return MA_FALSE;   /* Out of memory. */
32663         }
32664
32665         pContext->pDeviceInfos = pNewInfos;
32666         pContext->deviceInfoCapacity = newCapacity;
32667     }
32668
32669     if (deviceType == ma_device_type_playback) {
32670         /* Playback. Insert just before the first capture device. */
32671
32672         /* The first thing to do is move all of the capture devices down a slot. */
32673         ma_uint32 iFirstCaptureDevice = pContext->playbackDeviceInfoCount;
32674         size_t iCaptureDevice;
32675         for (iCaptureDevice = totalDeviceInfoCount; iCaptureDevice > iFirstCaptureDevice; --iCaptureDevice) {
32676             pContext->pDeviceInfos[iCaptureDevice] = pContext->pDeviceInfos[iCaptureDevice-1];
32677         }
32678
32679         /* Now just insert where the first capture device was before moving it down a slot. */
32680         pContext->pDeviceInfos[iFirstCaptureDevice] = *pInfo;
32681         pContext->playbackDeviceInfoCount += 1;
32682     } else {
32683         /* Capture. Insert at the end. */
32684         pContext->pDeviceInfos[totalDeviceInfoCount] = *pInfo;
32685         pContext->captureDeviceInfoCount += 1;
32686     }
32687
32688     (void)pUserData;
32689     return MA_TRUE;
32690 }
32691
32692 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)
32693 {
32694     ma_result result;
32695
32696     /* Safety. */
32697     if (ppPlaybackDeviceInfos != NULL) *ppPlaybackDeviceInfos = NULL;
32698     if (pPlaybackDeviceCount  != NULL) *pPlaybackDeviceCount  = 0;
32699     if (ppCaptureDeviceInfos  != NULL) *ppCaptureDeviceInfos  = NULL;
32700     if (pCaptureDeviceCount   != NULL) *pCaptureDeviceCount   = 0;
32701
32702     if (pContext == NULL) {
32703         return MA_INVALID_ARGS;
32704     }
32705
32706     if (pContext->callbacks.onContextEnumerateDevices == NULL) {
32707         return MA_INVALID_OPERATION;
32708     }
32709
32710     /* Note that we don't use ma_context_enumerate_devices() here because we want to do locking at a higher level. */
32711     ma_mutex_lock(&pContext->deviceEnumLock);
32712     {
32713         /* Reset everything first. */
32714         pContext->playbackDeviceInfoCount = 0;
32715         pContext->captureDeviceInfoCount = 0;
32716
32717         /* Now enumerate over available devices. */
32718         result = pContext->callbacks.onContextEnumerateDevices(pContext, ma_context_get_devices__enum_callback, NULL);
32719         if (result == MA_SUCCESS) {
32720             /* Playback devices. */
32721             if (ppPlaybackDeviceInfos != NULL) {
32722                 *ppPlaybackDeviceInfos = pContext->pDeviceInfos;
32723             }
32724             if (pPlaybackDeviceCount != NULL) {
32725                 *pPlaybackDeviceCount = pContext->playbackDeviceInfoCount;
32726             }
32727
32728             /* Capture devices. */
32729             if (ppCaptureDeviceInfos != NULL) {
32730                 *ppCaptureDeviceInfos = pContext->pDeviceInfos + pContext->playbackDeviceInfoCount; /* Capture devices come after playback devices. */
32731             }
32732             if (pCaptureDeviceCount != NULL) {
32733                 *pCaptureDeviceCount = pContext->captureDeviceInfoCount;
32734             }
32735         }
32736     }
32737     ma_mutex_unlock(&pContext->deviceEnumLock);
32738
32739     return result;
32740 }
32741
32742 MA_API ma_result ma_context_get_device_info(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_share_mode shareMode, ma_device_info* pDeviceInfo)
32743 {
32744     ma_result result;
32745     ma_device_info deviceInfo;
32746
32747     (void)shareMode;    /* Unused. This parameter will be removed in version 0.11. */
32748
32749     /* NOTE: Do not clear pDeviceInfo on entry. The reason is the pDeviceID may actually point to pDeviceInfo->id which will break things. */
32750     if (pContext == NULL || pDeviceInfo == NULL) {
32751         return MA_INVALID_ARGS;
32752     }
32753
32754     MA_ZERO_OBJECT(&deviceInfo);
32755
32756     /* Help the backend out by copying over the device ID if we have one. */
32757     if (pDeviceID != NULL) {
32758         MA_COPY_MEMORY(&deviceInfo.id, pDeviceID, sizeof(*pDeviceID));
32759     }
32760
32761     if (pContext->callbacks.onContextGetDeviceInfo == NULL) {
32762         return MA_INVALID_OPERATION;
32763     }
32764
32765     ma_mutex_lock(&pContext->deviceInfoLock);
32766     {
32767         result = pContext->callbacks.onContextGetDeviceInfo(pContext, deviceType, pDeviceID, &deviceInfo);
32768     }
32769     ma_mutex_unlock(&pContext->deviceInfoLock);
32770
32771     /*
32772     If the backend is using the new device info system, do a pass to fill out the old settings for backwards compatibility. This will be removed in
32773     the future when all backends have implemented the new device info system.
32774     */
32775     if (deviceInfo.nativeDataFormatCount > 0) {
32776         ma_uint32 iNativeFormat;
32777         ma_uint32 iSampleFormat;
32778
32779         deviceInfo.minChannels   = 0xFFFFFFFF;
32780         deviceInfo.maxChannels   = 0;
32781         deviceInfo.minSampleRate = 0xFFFFFFFF;
32782         deviceInfo.maxSampleRate = 0;
32783
32784         for (iNativeFormat = 0; iNativeFormat < deviceInfo.nativeDataFormatCount; iNativeFormat += 1) {
32785             /* Formats. */
32786             if (deviceInfo.nativeDataFormats[iNativeFormat].format == ma_format_unknown) {
32787                 /* All formats are supported. */
32788                 deviceInfo.formats[0] = ma_format_u8;
32789                 deviceInfo.formats[1] = ma_format_s16;
32790                 deviceInfo.formats[2] = ma_format_s24;
32791                 deviceInfo.formats[3] = ma_format_s32;
32792                 deviceInfo.formats[4] = ma_format_f32;
32793                 deviceInfo.formatCount = 5;
32794             } else {
32795                 /* Make sure the format isn't already in the list. If so, skip. */
32796                 ma_bool32 alreadyExists = MA_FALSE;
32797                 for (iSampleFormat = 0; iSampleFormat < deviceInfo.formatCount; iSampleFormat += 1) {
32798                     if (deviceInfo.formats[iSampleFormat] == deviceInfo.nativeDataFormats[iNativeFormat].format) {
32799                         alreadyExists = MA_TRUE;
32800                         break;
32801                     }
32802                 }
32803
32804                 if (!alreadyExists) {
32805                     deviceInfo.formats[deviceInfo.formatCount++] = deviceInfo.nativeDataFormats[iNativeFormat].format;
32806                 }
32807             }
32808
32809             /* Channels. */
32810             if (deviceInfo.nativeDataFormats[iNativeFormat].channels == 0) {
32811                 /* All channels supported. */
32812                 deviceInfo.minChannels = MA_MIN_CHANNELS;
32813                 deviceInfo.maxChannels = MA_MAX_CHANNELS;
32814             } else {
32815                 if (deviceInfo.minChannels > deviceInfo.nativeDataFormats[iNativeFormat].channels) {
32816                     deviceInfo.minChannels = deviceInfo.nativeDataFormats[iNativeFormat].channels;
32817                 }
32818                 if (deviceInfo.maxChannels < deviceInfo.nativeDataFormats[iNativeFormat].channels) {
32819                     deviceInfo.maxChannels = deviceInfo.nativeDataFormats[iNativeFormat].channels;
32820                 }
32821             }
32822
32823             /* Sample rate. */
32824             if (deviceInfo.nativeDataFormats[iNativeFormat].sampleRate == 0) {
32825                 /* All sample rates supported. */
32826                 deviceInfo.minSampleRate = (ma_uint32)ma_standard_sample_rate_min;
32827                 deviceInfo.maxSampleRate = (ma_uint32)ma_standard_sample_rate_max;
32828             } else {
32829                 if (deviceInfo.minSampleRate > deviceInfo.nativeDataFormats[iNativeFormat].sampleRate) {
32830                     deviceInfo.minSampleRate = deviceInfo.nativeDataFormats[iNativeFormat].sampleRate;
32831                 }
32832                 if (deviceInfo.maxSampleRate < deviceInfo.nativeDataFormats[iNativeFormat].sampleRate) {
32833                     deviceInfo.maxSampleRate = deviceInfo.nativeDataFormats[iNativeFormat].sampleRate;
32834                 }
32835             }
32836         }
32837     }
32838
32839
32840     /* Clamp ranges. */
32841     deviceInfo.minChannels   = ma_max(deviceInfo.minChannels,   MA_MIN_CHANNELS);
32842     deviceInfo.maxChannels   = ma_min(deviceInfo.maxChannels,   MA_MAX_CHANNELS);
32843     deviceInfo.minSampleRate = ma_max(deviceInfo.minSampleRate, (ma_uint32)ma_standard_sample_rate_min);
32844     deviceInfo.maxSampleRate = ma_min(deviceInfo.maxSampleRate, (ma_uint32)ma_standard_sample_rate_max);
32845
32846     *pDeviceInfo = deviceInfo;
32847     return result;
32848 }
32849
32850 MA_API ma_bool32 ma_context_is_loopback_supported(ma_context* pContext)
32851 {
32852     if (pContext == NULL) {
32853         return MA_FALSE;
32854     }
32855
32856     return ma_is_loopback_supported(pContext->backend);
32857 }
32858
32859
32860 MA_API ma_device_config ma_device_config_init(ma_device_type deviceType)
32861 {
32862     ma_device_config config;
32863     MA_ZERO_OBJECT(&config);
32864     config.deviceType = deviceType;
32865
32866     /* Resampling defaults. We must never use the Speex backend by default because it uses licensed third party code. */
32867     config.resampling.algorithm       = ma_resample_algorithm_linear;
32868     config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
32869     config.resampling.speex.quality   = 3;
32870
32871     return config;
32872 }
32873
32874 MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pConfig, ma_device* pDevice)
32875 {
32876     ma_result result;
32877     ma_device_descriptor descriptorPlayback;
32878     ma_device_descriptor descriptorCapture;
32879
32880     /* The context can be null, in which case we self-manage it. */
32881     if (pContext == NULL) {
32882         return ma_device_init_ex(NULL, 0, NULL, pConfig, pDevice);
32883     }
32884
32885     if (pDevice == NULL) {
32886         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
32887     }
32888
32889     MA_ZERO_OBJECT(pDevice);
32890
32891     if (pConfig == NULL) {
32892         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid arguments (pConfig == NULL).", MA_INVALID_ARGS);
32893     }
32894
32895
32896     /* Check that we have our callbacks defined. */
32897     if (pContext->callbacks.onDeviceInit == NULL) {
32898         return MA_INVALID_OPERATION;
32899     }
32900
32901
32902     /* Basic config validation. */
32903     if (pConfig->deviceType != ma_device_type_playback && pConfig->deviceType != ma_device_type_capture && pConfig->deviceType != ma_device_type_duplex && pConfig->deviceType != ma_device_type_loopback) {
32904         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Device type is invalid. Make sure the device type has been set in the config.", MA_INVALID_DEVICE_CONFIG);
32905     }
32906
32907     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) {
32908         if (pConfig->capture.channels > MA_MAX_CHANNELS) {
32909             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Capture channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG);
32910         }
32911         if (!ma__is_channel_map_valid(pConfig->capture.channelMap, pConfig->capture.channels)) {
32912             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Capture channel map is invalid.", MA_INVALID_DEVICE_CONFIG);
32913         }
32914     }
32915
32916     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
32917         if (pConfig->playback.channels > MA_MAX_CHANNELS) {
32918             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with an invalid config. Playback channel count cannot exceed 32.", MA_INVALID_DEVICE_CONFIG);
32919         }
32920         if (!ma__is_channel_map_valid(pConfig->playback.channelMap, pConfig->playback.channels)) {
32921             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "ma_device_init() called with invalid config. Playback channel map is invalid.", MA_INVALID_DEVICE_CONFIG);
32922         }
32923     }
32924
32925     pDevice->pContext = pContext;
32926
32927     /* Set the user data and log callback ASAP to ensure it is available for the entire initialization process. */
32928     pDevice->pUserData = pConfig->pUserData;
32929     pDevice->onData    = pConfig->dataCallback;
32930     pDevice->onStop    = pConfig->stopCallback;
32931
32932     if (((ma_uintptr)pDevice % sizeof(pDevice)) != 0) {
32933         if (pContext->logCallback) {
32934             pContext->logCallback(pContext, pDevice, MA_LOG_LEVEL_WARNING, "WARNING: ma_device_init() called for a device that is not properly aligned. Thread safety is not supported.");
32935         }
32936     }
32937
32938     if (pConfig->playback.pDeviceID != NULL) {
32939         MA_COPY_MEMORY(&pDevice->playback.id, pConfig->playback.pDeviceID, sizeof(pDevice->playback.id));
32940     }
32941
32942     if (pConfig->capture.pDeviceID != NULL) {
32943         MA_COPY_MEMORY(&pDevice->capture.id, pConfig->capture.pDeviceID, sizeof(pDevice->capture.id));
32944     }
32945
32946     pDevice->noPreZeroedOutputBuffer = pConfig->noPreZeroedOutputBuffer;
32947     pDevice->noClip = pConfig->noClip;
32948     pDevice->masterVolumeFactor = 1;
32949
32950     pDevice->type                       = pConfig->deviceType;
32951     pDevice->sampleRate                 = pConfig->sampleRate;
32952     pDevice->resampling.algorithm       = pConfig->resampling.algorithm;
32953     pDevice->resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder;
32954     pDevice->resampling.speex.quality   = pConfig->resampling.speex.quality;
32955
32956     pDevice->capture.shareMode          = pConfig->capture.shareMode;
32957     pDevice->capture.format             = pConfig->capture.format;
32958     pDevice->capture.channels           = pConfig->capture.channels;
32959     ma_channel_map_copy(pDevice->capture.channelMap, pConfig->capture.channelMap, pConfig->capture.channels);
32960     pDevice->capture.channelMixMode     = pConfig->capture.channelMixMode;
32961     
32962     pDevice->playback.shareMode         = pConfig->playback.shareMode;
32963     pDevice->playback.format            = pConfig->playback.format;
32964     pDevice->playback.channels          = pConfig->playback.channels;
32965     ma_channel_map_copy(pDevice->playback.channelMap, pConfig->playback.channelMap, pConfig->playback.channels);
32966     pDevice->playback.channelMixMode    = pConfig->playback.channelMixMode;
32967     
32968
32969     result = ma_mutex_init(&pDevice->startStopLock);
32970     if (result != MA_SUCCESS) {
32971         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create mutex.", result);
32972     }
32973
32974     /*
32975     When the device is started, the worker thread is the one that does the actual startup of the backend device. We
32976     use a semaphore to wait for the background thread to finish the work. The same applies for stopping the device.
32977
32978     Each of these semaphores is released internally by the worker thread when the work is completed. The start
32979     semaphore is also used to wake up the worker thread.
32980     */
32981     result = ma_event_init(&pDevice->wakeupEvent);
32982     if (result != MA_SUCCESS) {
32983         ma_mutex_uninit(&pDevice->startStopLock);
32984         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread wakeup event.", result);
32985     }
32986
32987     result = ma_event_init(&pDevice->startEvent);
32988     if (result != MA_SUCCESS) {
32989         ma_event_uninit(&pDevice->wakeupEvent);
32990         ma_mutex_uninit(&pDevice->startStopLock);
32991         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread start event.", result);
32992     }
32993
32994     result = ma_event_init(&pDevice->stopEvent);
32995     if (result != MA_SUCCESS) {
32996         ma_event_uninit(&pDevice->startEvent);
32997         ma_event_uninit(&pDevice->wakeupEvent);
32998         ma_mutex_uninit(&pDevice->startStopLock);
32999         return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread stop event.", result);
33000     }
33001
33002
33003     MA_ZERO_OBJECT(&descriptorPlayback);
33004     descriptorPlayback.pDeviceID                = pConfig->playback.pDeviceID;
33005     descriptorPlayback.shareMode                = pConfig->playback.shareMode;
33006     descriptorPlayback.format                   = pConfig->playback.format;
33007     descriptorPlayback.channels                 = pConfig->playback.channels;
33008     descriptorPlayback.sampleRate               = pConfig->sampleRate;
33009     ma_channel_map_copy(descriptorPlayback.channelMap, pConfig->playback.channelMap, pConfig->playback.channels);
33010     descriptorPlayback.periodSizeInFrames       = pConfig->periodSizeInFrames;
33011     descriptorPlayback.periodSizeInMilliseconds = pConfig->periodSizeInMilliseconds;
33012     descriptorPlayback.periodCount              = pConfig->periods;
33013
33014     if (descriptorPlayback.periodCount == 0) {
33015         descriptorPlayback.periodCount = MA_DEFAULT_PERIODS;
33016     }
33017
33018
33019     MA_ZERO_OBJECT(&descriptorCapture);
33020     descriptorCapture.pDeviceID                 = pConfig->capture.pDeviceID;
33021     descriptorCapture.shareMode                 = pConfig->capture.shareMode;
33022     descriptorCapture.format                    = pConfig->capture.format;
33023     descriptorCapture.channels                  = pConfig->capture.channels;
33024     descriptorCapture.sampleRate                = pConfig->sampleRate;
33025     ma_channel_map_copy(descriptorCapture.channelMap, pConfig->capture.channelMap, pConfig->capture.channels);
33026     descriptorCapture.periodSizeInFrames        = pConfig->periodSizeInFrames;
33027     descriptorCapture.periodSizeInMilliseconds  = pConfig->periodSizeInMilliseconds;
33028     descriptorCapture.periodCount               = pConfig->periods;
33029
33030     if (descriptorCapture.periodCount == 0) {
33031         descriptorCapture.periodCount = MA_DEFAULT_PERIODS;
33032     }
33033
33034
33035     result = pContext->callbacks.onDeviceInit(pDevice, pConfig, &descriptorPlayback, &descriptorCapture);
33036     if (result != MA_SUCCESS) {
33037         ma_event_uninit(&pDevice->startEvent);
33038         ma_event_uninit(&pDevice->wakeupEvent);
33039         ma_mutex_uninit(&pDevice->startStopLock);
33040         return result;
33041     }
33042
33043
33044     /*
33045     On output the descriptors will contain the *actual* data format of the device. We need this to know how to convert the data between
33046     the requested format and the internal format.
33047     */
33048     if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
33049         if (!ma_device_descriptor_is_valid(&descriptorCapture)) {
33050             ma_device_uninit(pDevice);
33051             return MA_INVALID_ARGS;
33052         }
33053
33054         pDevice->capture.internalFormat             = descriptorCapture.format;
33055         pDevice->capture.internalChannels           = descriptorCapture.channels;
33056         pDevice->capture.internalSampleRate         = descriptorCapture.sampleRate;
33057         ma_channel_map_copy(pDevice->capture.internalChannelMap, descriptorCapture.channelMap, descriptorCapture.channels);
33058         pDevice->capture.internalPeriodSizeInFrames = descriptorCapture.periodSizeInFrames;
33059         pDevice->capture.internalPeriods            = descriptorCapture.periodCount;
33060
33061         if (pDevice->capture.internalPeriodSizeInFrames == 0) {
33062             pDevice->capture.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorCapture.periodSizeInMilliseconds, descriptorCapture.sampleRate);
33063         }
33064     }
33065
33066     if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
33067         if (!ma_device_descriptor_is_valid(&descriptorPlayback)) {
33068             ma_device_uninit(pDevice);
33069             return MA_INVALID_ARGS;
33070         }
33071
33072         pDevice->playback.internalFormat             = descriptorPlayback.format;
33073         pDevice->playback.internalChannels           = descriptorPlayback.channels;
33074         pDevice->playback.internalSampleRate         = descriptorPlayback.sampleRate;
33075         ma_channel_map_copy(pDevice->playback.internalChannelMap, descriptorPlayback.channelMap, descriptorPlayback.channels);
33076         pDevice->playback.internalPeriodSizeInFrames = descriptorPlayback.periodSizeInFrames;
33077         pDevice->playback.internalPeriods            = descriptorPlayback.periodCount;
33078
33079         if (pDevice->playback.internalPeriodSizeInFrames == 0) {
33080             pDevice->playback.internalPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(descriptorPlayback.periodSizeInMilliseconds, descriptorPlayback.sampleRate);
33081         }
33082     }
33083
33084
33085     /*
33086     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.
33087     For loopback devices, we need to retrieve the name of the playback device.
33088     */
33089     {
33090         ma_device_info deviceInfo;
33091
33092         if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex || pConfig->deviceType == ma_device_type_loopback) {
33093             result = ma_context_get_device_info(pContext, (pConfig->deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, descriptorCapture.pDeviceID, descriptorCapture.shareMode, &deviceInfo);
33094             if (result == MA_SUCCESS) {
33095                 ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1);
33096             } else {
33097                 /* We failed to retrieve the device info. Fall back to a default name. */
33098                 if (descriptorCapture.pDeviceID == NULL) {
33099                     ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
33100                 } else {
33101                     ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), "Capture Device", (size_t)-1);
33102                 }
33103             }
33104         }
33105
33106         if (pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) {
33107             result = ma_context_get_device_info(pContext, ma_device_type_playback, descriptorPlayback.pDeviceID, descriptorPlayback.shareMode, &deviceInfo);
33108             if (result == MA_SUCCESS) {
33109                 ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), deviceInfo.name, (size_t)-1);
33110             } else {
33111                 /* We failed to retrieve the device info. Fall back to a default name. */
33112                 if (descriptorPlayback.pDeviceID == NULL) {
33113                     ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
33114                 } else {
33115                     ma_strncpy_s(pDevice->playback.name, sizeof(pDevice->playback.name), "Playback Device", (size_t)-1);
33116                 }
33117             }
33118         }
33119     }
33120
33121
33122     ma_device__post_init_setup(pDevice, pConfig->deviceType);
33123
33124
33125     /* Some backends don't require the worker thread. */
33126     if (!ma_context_is_backend_asynchronous(pContext)) {
33127         /* The worker thread. */
33128         result = ma_thread_create(&pDevice->thread, pContext->threadPriority, pContext->threadStackSize, ma_worker_thread, pDevice);
33129         if (result != MA_SUCCESS) {
33130             ma_device_uninit(pDevice);
33131             return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "Failed to create worker thread.", result);
33132         }
33133
33134         /* Wait for the worker thread to put the device into it's stopped state for real. */
33135         ma_event_wait(&pDevice->stopEvent);
33136         MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED);
33137     } else {
33138         /*
33139         If the backend is asynchronous and the device is duplex, we'll need an intermediary ring buffer. Note that this needs to be done
33140         after ma_device__post_init_setup().
33141         */
33142         if (ma_context_is_backend_asynchronous(pContext)) {
33143             if (pConfig->deviceType == ma_device_type_duplex) {
33144                 result = ma_duplex_rb_init(pDevice->capture.format, pDevice->capture.channels, pDevice->sampleRate, pDevice->capture.internalSampleRate, pDevice->capture.internalPeriodSizeInFrames, &pDevice->pContext->allocationCallbacks, &pDevice->duplexRB);
33145                 if (result != MA_SUCCESS) {
33146                     ma_device_uninit(pDevice);
33147                     return result;
33148                 }
33149             }
33150         }
33151
33152         ma_device__set_state(pDevice, MA_STATE_STOPPED);
33153     }
33154
33155
33156     ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "[%s]", ma_get_backend_name(pDevice->pContext->backend));
33157     if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
33158         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "  %s (%s)", pDevice->capture.name, "Capture");
33159         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Format:      %s -> %s", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format));
33160         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Channels:    %d -> %d", pDevice->capture.internalChannels, pDevice->capture.channels);
33161         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Sample Rate: %d -> %d", pDevice->capture.internalSampleRate, pDevice->sampleRate);
33162         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Buffer Size: %d*%d (%d)", pDevice->capture.internalPeriodSizeInFrames, pDevice->capture.internalPeriods, (pDevice->capture.internalPeriodSizeInFrames * pDevice->capture.internalPeriods));
33163         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Conversion:");
33164         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Pre Format Conversion:    %s", pDevice->capture.converter.hasPreFormatConversion  ? "YES" : "NO");
33165         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Post Format Conversion:   %s", pDevice->capture.converter.hasPostFormatConversion ? "YES" : "NO");
33166         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Channel Routing:          %s", pDevice->capture.converter.hasChannelConverter     ? "YES" : "NO");
33167         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Resampling:               %s", pDevice->capture.converter.hasResampler            ? "YES" : "NO");
33168         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Passthrough:              %s", pDevice->capture.converter.isPassthrough           ? "YES" : "NO");
33169     }
33170     if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
33171         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "  %s (%s)", pDevice->playback.name, "Playback");
33172         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Format:      %s -> %s", ma_get_format_name(pDevice->playback.format), ma_get_format_name(pDevice->playback.internalFormat));
33173         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Channels:    %d -> %d", pDevice->playback.channels, pDevice->playback.internalChannels);
33174         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Sample Rate: %d -> %d", pDevice->sampleRate, pDevice->playback.internalSampleRate);
33175         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Buffer Size: %d*%d (%d)", pDevice->playback.internalPeriodSizeInFrames, pDevice->playback.internalPeriods, (pDevice->playback.internalPeriodSizeInFrames * pDevice->playback.internalPeriods));
33176         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "    Conversion:");
33177         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Pre Format Conversion:    %s", pDevice->playback.converter.hasPreFormatConversion  ? "YES" : "NO");
33178         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Post Format Conversion:   %s", pDevice->playback.converter.hasPostFormatConversion ? "YES" : "NO");
33179         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Channel Routing:          %s", pDevice->playback.converter.hasChannelConverter     ? "YES" : "NO");
33180         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Resampling:               %s", pDevice->playback.converter.hasResampler            ? "YES" : "NO");
33181         ma_post_log_messagef(pContext, pDevice, MA_LOG_LEVEL_INFO, "      Passthrough:              %s", pDevice->playback.converter.isPassthrough           ? "YES" : "NO");
33182     }
33183
33184     MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED);
33185     return MA_SUCCESS;
33186 }
33187
33188 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)
33189 {
33190     ma_result result;
33191     ma_context* pContext;
33192     ma_backend defaultBackends[ma_backend_null+1];
33193     ma_uint32 iBackend;
33194     ma_backend* pBackendsToIterate;
33195     ma_uint32 backendsToIterateCount;
33196     ma_allocation_callbacks allocationCallbacks;
33197
33198     if (pConfig == NULL) {
33199         return MA_INVALID_ARGS;
33200     }
33201
33202     if (pContextConfig != NULL) {
33203         result = ma_allocation_callbacks_init_copy(&allocationCallbacks, &pContextConfig->allocationCallbacks);
33204         if (result != MA_SUCCESS) {
33205             return result;
33206         }
33207     } else {
33208         allocationCallbacks = ma_allocation_callbacks_init_default();
33209     }
33210
33211
33212     pContext = (ma_context*)ma__malloc_from_callbacks(sizeof(*pContext), &allocationCallbacks);
33213     if (pContext == NULL) {
33214         return MA_OUT_OF_MEMORY;
33215     }
33216
33217     for (iBackend = 0; iBackend <= ma_backend_null; ++iBackend) {
33218         defaultBackends[iBackend] = (ma_backend)iBackend;
33219     }
33220
33221     pBackendsToIterate = (ma_backend*)backends;
33222     backendsToIterateCount = backendCount;
33223     if (pBackendsToIterate == NULL) {
33224         pBackendsToIterate = (ma_backend*)defaultBackends;
33225         backendsToIterateCount = ma_countof(defaultBackends);
33226     }
33227
33228     result = MA_NO_BACKEND;
33229
33230     for (iBackend = 0; iBackend < backendsToIterateCount; ++iBackend) {
33231         result = ma_context_init(&pBackendsToIterate[iBackend], 1, pContextConfig, pContext);
33232         if (result == MA_SUCCESS) {
33233             result = ma_device_init(pContext, pConfig, pDevice);
33234             if (result == MA_SUCCESS) {
33235                 break;  /* Success. */
33236             } else {
33237                 ma_context_uninit(pContext);   /* Failure. */
33238             }
33239         }
33240     }
33241
33242     if (result != MA_SUCCESS) {
33243         ma__free_from_callbacks(pContext, &allocationCallbacks);
33244         return result;
33245     }
33246
33247     pDevice->isOwnerOfContext = MA_TRUE;
33248     return result;
33249 }
33250
33251 MA_API void ma_device_uninit(ma_device* pDevice)
33252 {
33253     if (!ma_device__is_initialized(pDevice)) {
33254         return;
33255     }
33256
33257     /* 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. */
33258     if (ma_device_is_started(pDevice)) {
33259         ma_device_stop(pDevice);
33260     }
33261
33262     /* Putting the device into an uninitialized state will make the worker thread return. */
33263     ma_device__set_state(pDevice, MA_STATE_UNINITIALIZED);
33264
33265     /* Wake up the worker thread and wait for it to properly terminate. */
33266     if (!ma_context_is_backend_asynchronous(pDevice->pContext)) {
33267         ma_event_signal(&pDevice->wakeupEvent);
33268         ma_thread_wait(&pDevice->thread);
33269     }
33270
33271     if (pDevice->pContext->callbacks.onDeviceUninit != NULL) {
33272         pDevice->pContext->callbacks.onDeviceUninit(pDevice);
33273     }
33274
33275
33276     ma_event_uninit(&pDevice->stopEvent);
33277     ma_event_uninit(&pDevice->startEvent);
33278     ma_event_uninit(&pDevice->wakeupEvent);
33279     ma_mutex_uninit(&pDevice->startStopLock);
33280
33281     if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
33282         if (pDevice->type == ma_device_type_duplex) {
33283             ma_duplex_rb_uninit(&pDevice->duplexRB);
33284         }
33285     }
33286
33287     if (pDevice->isOwnerOfContext) {
33288         ma_allocation_callbacks allocationCallbacks = pDevice->pContext->allocationCallbacks;
33289
33290         ma_context_uninit(pDevice->pContext);
33291         ma__free_from_callbacks(pDevice->pContext, &allocationCallbacks);
33292     }
33293
33294     MA_ZERO_OBJECT(pDevice);
33295 }
33296
33297 MA_API ma_result ma_device_start(ma_device* pDevice)
33298 {
33299     ma_result result;
33300
33301     if (pDevice == NULL) {
33302         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
33303     }
33304
33305     if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) {
33306         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED);
33307     }
33308
33309     if (ma_device_get_state(pDevice) == MA_STATE_STARTED) {
33310         return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_start() called when the device is already started.", MA_INVALID_OPERATION);  /* Already started. Returning an error to let the application know because it probably means they're doing something wrong. */
33311     }
33312
33313     ma_mutex_lock(&pDevice->startStopLock);
33314     {
33315         /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */
33316         MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STOPPED);
33317
33318         ma_device__set_state(pDevice, MA_STATE_STARTING);
33319
33320         /* Asynchronous backends need to be handled differently. */
33321         if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
33322             if (pDevice->pContext->callbacks.onDeviceStart != NULL) {
33323                 result = pDevice->pContext->callbacks.onDeviceStart(pDevice);
33324             } else {
33325                 result = MA_INVALID_OPERATION;
33326             }
33327
33328             if (result == MA_SUCCESS) {
33329                 ma_device__set_state(pDevice, MA_STATE_STARTED);
33330             }
33331         } else {
33332             /*
33333             Synchronous backends are started by signaling an event that's being waited on in the worker thread. We first wake up the
33334             thread and then wait for the start event.
33335             */
33336             ma_event_signal(&pDevice->wakeupEvent);
33337
33338             /*
33339             Wait for the worker thread to finish starting the device. Note that the worker thread will be the one who puts the device
33340             into the started state. Don't call ma_device__set_state() here.
33341             */
33342             ma_event_wait(&pDevice->startEvent);
33343             result = pDevice->workResult;
33344         }
33345
33346         /* We changed the state from stopped to started, so if we failed, make sure we put the state back to stopped. */
33347         if (result != MA_SUCCESS) {
33348             ma_device__set_state(pDevice, MA_STATE_STOPPED);
33349         }
33350     }
33351     ma_mutex_unlock(&pDevice->startStopLock);
33352
33353     return result;
33354 }
33355
33356 MA_API ma_result ma_device_stop(ma_device* pDevice)
33357 {
33358     ma_result result;
33359
33360     if (pDevice == NULL) {
33361         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called with invalid arguments (pDevice == NULL).", MA_INVALID_ARGS);
33362     }
33363
33364     if (ma_device_get_state(pDevice) == MA_STATE_UNINITIALIZED) {
33365         return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED);
33366     }
33367
33368     if (ma_device_get_state(pDevice) == MA_STATE_STOPPED) {
33369         return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_stop() called when the device is already stopped.", MA_INVALID_OPERATION);   /* Already stopped. Returning an error to let the application know because it probably means they're doing something wrong. */
33370     }
33371
33372     ma_mutex_lock(&pDevice->startStopLock);
33373     {
33374         /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */
33375         MA_ASSERT(ma_device_get_state(pDevice) == MA_STATE_STARTED);
33376
33377         ma_device__set_state(pDevice, MA_STATE_STOPPING);
33378
33379         /* Asynchronous backends need to be handled differently. */
33380         if (ma_context_is_backend_asynchronous(pDevice->pContext)) {
33381             /* Asynchronous backends must have a stop operation. */
33382             if (pDevice->pContext->callbacks.onDeviceStop != NULL) {
33383                 result = pDevice->pContext->callbacks.onDeviceStop(pDevice);
33384             } else {
33385                 result = MA_INVALID_OPERATION;
33386             }
33387
33388             ma_device__set_state(pDevice, MA_STATE_STOPPED);
33389         } else {
33390             /*
33391             Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If
33392             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
33393             sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super
33394             important though, so I'm asserting it here as well for extra safety in case we accidentally change something later.
33395             */
33396             MA_ASSERT(ma_device_get_state(pDevice) != MA_STATE_STARTED);
33397
33398             if (pDevice->pContext->callbacks.onDeviceDataLoopWakeup != NULL) {
33399                 pDevice->pContext->callbacks.onDeviceDataLoopWakeup(pDevice);
33400             }
33401
33402             /*
33403             We need to wait for the worker thread to become available for work before returning. Note that the worker thread will be
33404             the one who puts the device into the stopped state. Don't call ma_device__set_state() here.
33405             */
33406             ma_event_wait(&pDevice->stopEvent);
33407             result = MA_SUCCESS;
33408         }
33409     }
33410     ma_mutex_unlock(&pDevice->startStopLock);
33411
33412     return result;
33413 }
33414
33415 MA_API ma_bool32 ma_device_is_started(const ma_device* pDevice)
33416 {
33417     return ma_device_get_state(pDevice) == MA_STATE_STARTED;
33418 }
33419
33420 MA_API ma_uint32 ma_device_get_state(const ma_device* pDevice)
33421 {
33422     if (pDevice == NULL) {
33423         return MA_STATE_UNINITIALIZED;
33424     }
33425
33426     return c89atomic_load_32((ma_uint32*)&pDevice->state);  /* Naughty cast to get rid of a const warning. */
33427 }
33428
33429 MA_API ma_result ma_device_set_master_volume(ma_device* pDevice, float volume)
33430 {
33431     if (pDevice == NULL) {
33432         return MA_INVALID_ARGS;
33433     }
33434
33435     if (volume < 0.0f || volume > 1.0f) {
33436         return MA_INVALID_ARGS;
33437     }
33438
33439     c89atomic_exchange_f32(&pDevice->masterVolumeFactor, volume);
33440
33441     return MA_SUCCESS;
33442 }
33443
33444 MA_API ma_result ma_device_get_master_volume(ma_device* pDevice, float* pVolume)
33445 {
33446     if (pVolume == NULL) {
33447         return MA_INVALID_ARGS;
33448     }
33449
33450     if (pDevice == NULL) {
33451         *pVolume = 0;
33452         return MA_INVALID_ARGS;
33453     }
33454
33455     *pVolume = c89atomic_load_f32(&pDevice->masterVolumeFactor);
33456
33457     return MA_SUCCESS;
33458 }
33459
33460 MA_API ma_result ma_device_set_master_gain_db(ma_device* pDevice, float gainDB)
33461 {
33462     if (gainDB > 0) {
33463         return MA_INVALID_ARGS;
33464     }
33465
33466     return ma_device_set_master_volume(pDevice, ma_gain_db_to_factor(gainDB));
33467 }
33468
33469 MA_API ma_result ma_device_get_master_gain_db(ma_device* pDevice, float* pGainDB)
33470 {
33471     float factor;
33472     ma_result result;
33473
33474     if (pGainDB == NULL) {
33475         return MA_INVALID_ARGS;
33476     }
33477
33478     result = ma_device_get_master_volume(pDevice, &factor);
33479     if (result != MA_SUCCESS) {
33480         *pGainDB = 0;
33481         return result;
33482     }
33483
33484     *pGainDB = ma_factor_to_gain_db(factor);
33485
33486     return MA_SUCCESS;
33487 }
33488
33489
33490 MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
33491 {
33492     if (pDevice == NULL) {
33493         return MA_INVALID_ARGS;
33494     }
33495
33496     if (pOutput == NULL && pInput == NULL) {
33497         return MA_INVALID_ARGS;
33498     }
33499
33500     if (pDevice->type == ma_device_type_duplex) {
33501         if (pInput != NULL) {
33502             ma_device__handle_duplex_callback_capture(pDevice, frameCount, pInput, &pDevice->duplexRB.rb);
33503         }
33504
33505         if (pOutput != NULL) {
33506             ma_device__handle_duplex_callback_playback(pDevice, frameCount, pOutput, &pDevice->duplexRB.rb);
33507         }
33508     } else {
33509         if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_loopback) {
33510             if (pInput == NULL) {
33511                 return MA_INVALID_ARGS;
33512             }
33513
33514             ma_device__send_frames_to_client(pDevice, frameCount, pInput);
33515         }
33516
33517         if (pDevice->type == ma_device_type_playback) {
33518             if (pOutput == NULL) {
33519                 return MA_INVALID_ARGS;
33520             }
33521
33522             ma_device__read_frames_from_client(pDevice, frameCount, pOutput);
33523         }
33524     }
33525
33526     return MA_SUCCESS;
33527 }
33528
33529 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_descriptor(const ma_device_descriptor* pDescriptor, ma_uint32 nativeSampleRate, ma_performance_profile performanceProfile)
33530 {
33531     if (pDescriptor == NULL) {
33532         return 0;
33533     }
33534
33535     /*
33536     We must have a non-0 native sample rate, but some backends don't allow retrieval of this at the
33537     time when the size of the buffer needs to be determined. In this case we need to just take a best
33538     guess and move on. We'll try using the sample rate in pDescriptor first. If that's not set we'll
33539     just fall back to MA_DEFAULT_SAMPLE_RATE.
33540     */
33541     if (nativeSampleRate == 0) {
33542         nativeSampleRate = pDescriptor->sampleRate;
33543     }
33544     if (nativeSampleRate == 0) {
33545         nativeSampleRate = MA_DEFAULT_SAMPLE_RATE;
33546     }
33547
33548     MA_ASSERT(nativeSampleRate != 0);
33549
33550     if (pDescriptor->periodSizeInFrames == 0) {
33551         if (pDescriptor->periodSizeInMilliseconds == 0) {
33552             if (performanceProfile == ma_performance_profile_low_latency) {
33553                 return ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, nativeSampleRate);
33554             } else {
33555                 return ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, nativeSampleRate);
33556             }
33557         } else {
33558             return ma_calculate_buffer_size_in_frames_from_milliseconds(pDescriptor->periodSizeInMilliseconds, nativeSampleRate);
33559         }
33560     } else {
33561         return pDescriptor->periodSizeInFrames;
33562     }
33563 }
33564 #endif  /* MA_NO_DEVICE_IO */
33565
33566
33567 MA_API ma_uint32 ma_scale_buffer_size(ma_uint32 baseBufferSize, float scale)
33568 {
33569     return ma_max(1, (ma_uint32)(baseBufferSize*scale));
33570 }
33571
33572 MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate)
33573 {
33574     /* Prevent a division by zero. */
33575     if (sampleRate == 0) {
33576         return 0;
33577     }
33578
33579     return bufferSizeInFrames*1000 / sampleRate;
33580 }
33581
33582 MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate)
33583 {
33584     /* Prevent a division by zero. */
33585     if (sampleRate == 0) {
33586         return 0;
33587     }
33588
33589     return bufferSizeInMilliseconds*sampleRate / 1000;
33590 }
33591
33592 MA_API void ma_copy_pcm_frames(void* dst, const void* src, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
33593 {
33594     if (dst == src) {
33595         return; /* No-op. */
33596     }
33597
33598     ma_copy_memory_64(dst, src, frameCount * ma_get_bytes_per_frame(format, channels));
33599 }
33600
33601 MA_API void ma_silence_pcm_frames(void* p, ma_uint64 frameCount, ma_format format, ma_uint32 channels)
33602 {
33603     if (format == ma_format_u8) {
33604         ma_uint64 sampleCount = frameCount * channels;
33605         ma_uint64 iSample;
33606         for (iSample = 0; iSample < sampleCount; iSample += 1) {
33607             ((ma_uint8*)p)[iSample] = 128;
33608         }
33609     } else {
33610         ma_zero_memory_64(p, frameCount * ma_get_bytes_per_frame(format, channels));
33611     }
33612 }
33613
33614 MA_API void* ma_offset_pcm_frames_ptr(void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels)
33615 {
33616     return ma_offset_ptr(p, offsetInFrames * ma_get_bytes_per_frame(format, channels));
33617 }
33618
33619 MA_API const void* ma_offset_pcm_frames_const_ptr(const void* p, ma_uint64 offsetInFrames, ma_format format, ma_uint32 channels)
33620 {
33621     return ma_offset_ptr(p, offsetInFrames * ma_get_bytes_per_frame(format, channels));
33622 }
33623
33624
33625 MA_API void ma_clip_samples_f32(float* p, ma_uint64 sampleCount)
33626 {
33627     ma_uint32 iSample;
33628
33629     /* TODO: Research a branchless SSE implementation. */
33630     for (iSample = 0; iSample < sampleCount; iSample += 1) {
33631         p[iSample] = ma_clip_f32(p[iSample]);
33632     }
33633 }
33634
33635
33636 MA_API void ma_copy_and_apply_volume_factor_u8(ma_uint8* pSamplesOut, const ma_uint8* pSamplesIn, ma_uint64 sampleCount, float factor)
33637 {
33638     ma_uint64 iSample;
33639
33640     if (pSamplesOut == NULL || pSamplesIn == NULL) {
33641         return;
33642     }
33643
33644     for (iSample = 0; iSample < sampleCount; iSample += 1) {
33645         pSamplesOut[iSample] = (ma_uint8)(pSamplesIn[iSample] * factor);
33646     }
33647 }
33648
33649 MA_API void ma_copy_and_apply_volume_factor_s16(ma_int16* pSamplesOut, const ma_int16* pSamplesIn, ma_uint64 sampleCount, float factor)
33650 {
33651     ma_uint64 iSample;
33652
33653     if (pSamplesOut == NULL || pSamplesIn == NULL) {
33654         return;
33655     }
33656
33657     for (iSample = 0; iSample < sampleCount; iSample += 1) {
33658         pSamplesOut[iSample] = (ma_int16)(pSamplesIn[iSample] * factor);
33659     }
33660 }
33661
33662 MA_API void ma_copy_and_apply_volume_factor_s24(void* pSamplesOut, const void* pSamplesIn, ma_uint64 sampleCount, float factor)
33663 {
33664     ma_uint64 iSample;
33665     ma_uint8* pSamplesOut8;
33666     ma_uint8* pSamplesIn8;
33667
33668     if (pSamplesOut == NULL || pSamplesIn == NULL) {
33669         return;
33670     }
33671
33672     pSamplesOut8 = (ma_uint8*)pSamplesOut;
33673     pSamplesIn8  = (ma_uint8*)pSamplesIn;
33674
33675     for (iSample = 0; iSample < sampleCount; iSample += 1) {
33676         ma_int32 sampleS32;
33677
33678         sampleS32 = (ma_int32)(((ma_uint32)(pSamplesIn8[iSample*3+0]) << 8) | ((ma_uint32)(pSamplesIn8[iSample*3+1]) << 16) | ((ma_uint32)(pSamplesIn8[iSample*3+2])) << 24);
33679         sampleS32 = (ma_int32)(sampleS32 * factor);
33680
33681         pSamplesOut8[iSample*3+0] = (ma_uint8)(((ma_uint32)sampleS32 & 0x0000FF00) >>  8);
33682         pSamplesOut8[iSample*3+1] = (ma_uint8)(((ma_uint32)sampleS32 & 0x00FF0000) >> 16);
33683         pSamplesOut8[iSample*3+2] = (ma_uint8)(((ma_uint32)sampleS32 & 0xFF000000) >> 24);
33684     }
33685 }
33686
33687 MA_API void ma_copy_and_apply_volume_factor_s32(ma_int32* pSamplesOut, const ma_int32* pSamplesIn, ma_uint64 sampleCount, float factor)
33688 {
33689     ma_uint64 iSample;
33690
33691     if (pSamplesOut == NULL || pSamplesIn == NULL) {
33692         return;
33693     }
33694
33695     for (iSample = 0; iSample < sampleCount; iSample += 1) {
33696         pSamplesOut[iSample] = (ma_int32)(pSamplesIn[iSample] * factor);
33697     }
33698 }
33699
33700 MA_API void ma_copy_and_apply_volume_factor_f32(float* pSamplesOut, const float* pSamplesIn, ma_uint64 sampleCount, float factor)
33701 {
33702     ma_uint64 iSample;
33703
33704     if (pSamplesOut == NULL || pSamplesIn == NULL) {
33705         return;
33706     }
33707
33708     for (iSample = 0; iSample < sampleCount; iSample += 1) {
33709         pSamplesOut[iSample] = pSamplesIn[iSample] * factor;
33710     }
33711 }
33712
33713 MA_API void ma_apply_volume_factor_u8(ma_uint8* pSamples, ma_uint64 sampleCount, float factor)
33714 {
33715     ma_copy_and_apply_volume_factor_u8(pSamples, pSamples, sampleCount, factor);
33716 }
33717
33718 MA_API void ma_apply_volume_factor_s16(ma_int16* pSamples, ma_uint64 sampleCount, float factor)
33719 {
33720     ma_copy_and_apply_volume_factor_s16(pSamples, pSamples, sampleCount, factor);
33721 }
33722
33723 MA_API void ma_apply_volume_factor_s24(void* pSamples, ma_uint64 sampleCount, float factor)
33724 {
33725     ma_copy_and_apply_volume_factor_s24(pSamples, pSamples, sampleCount, factor);
33726 }
33727
33728 MA_API void ma_apply_volume_factor_s32(ma_int32* pSamples, ma_uint64 sampleCount, float factor)
33729 {
33730     ma_copy_and_apply_volume_factor_s32(pSamples, pSamples, sampleCount, factor);
33731 }
33732
33733 MA_API void ma_apply_volume_factor_f32(float* pSamples, ma_uint64 sampleCount, float factor)
33734 {
33735     ma_copy_and_apply_volume_factor_f32(pSamples, pSamples, sampleCount, factor);
33736 }
33737
33738 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFramesOut, const ma_uint8* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
33739 {
33740     ma_copy_and_apply_volume_factor_u8(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
33741 }
33742
33743 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFramesOut, const ma_int16* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
33744 {
33745     ma_copy_and_apply_volume_factor_s16(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
33746 }
33747
33748 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s24(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
33749 {
33750     ma_copy_and_apply_volume_factor_s24(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
33751 }
33752
33753 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFramesOut, const ma_int32* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
33754 {
33755     ma_copy_and_apply_volume_factor_s32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
33756 }
33757
33758 MA_API void ma_copy_and_apply_volume_factor_pcm_frames_f32(float* pPCMFramesOut, const float* pPCMFramesIn, ma_uint64 frameCount, ma_uint32 channels, float factor)
33759 {
33760     ma_copy_and_apply_volume_factor_f32(pPCMFramesOut, pPCMFramesIn, frameCount*channels, factor);
33761 }
33762
33763 MA_API void ma_copy_and_apply_volume_factor_pcm_frames(void* pPCMFramesOut, const void* pPCMFramesIn, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor)
33764 {
33765     switch (format)
33766     {
33767     case ma_format_u8:  ma_copy_and_apply_volume_factor_pcm_frames_u8 ((ma_uint8*)pPCMFramesOut, (const ma_uint8*)pPCMFramesIn, frameCount, channels, factor); return;
33768     case ma_format_s16: ma_copy_and_apply_volume_factor_pcm_frames_s16((ma_int16*)pPCMFramesOut, (const ma_int16*)pPCMFramesIn, frameCount, channels, factor); return;
33769     case ma_format_s24: ma_copy_and_apply_volume_factor_pcm_frames_s24(           pPCMFramesOut,                  pPCMFramesIn, frameCount, channels, factor); return;
33770     case ma_format_s32: ma_copy_and_apply_volume_factor_pcm_frames_s32((ma_int32*)pPCMFramesOut, (const ma_int32*)pPCMFramesIn, frameCount, channels, factor); return;
33771     case ma_format_f32: ma_copy_and_apply_volume_factor_pcm_frames_f32(   (float*)pPCMFramesOut,    (const float*)pPCMFramesIn, frameCount, channels, factor); return;
33772     default: return;    /* Do nothing. */
33773     }
33774 }
33775
33776 MA_API void ma_apply_volume_factor_pcm_frames_u8(ma_uint8* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
33777 {
33778     ma_copy_and_apply_volume_factor_pcm_frames_u8(pPCMFrames, pPCMFrames, frameCount, channels, factor);
33779 }
33780
33781 MA_API void ma_apply_volume_factor_pcm_frames_s16(ma_int16* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
33782 {
33783     ma_copy_and_apply_volume_factor_pcm_frames_s16(pPCMFrames, pPCMFrames, frameCount, channels, factor);
33784 }
33785
33786 MA_API void ma_apply_volume_factor_pcm_frames_s24(void* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
33787 {
33788     ma_copy_and_apply_volume_factor_pcm_frames_s24(pPCMFrames, pPCMFrames, frameCount, channels, factor);
33789 }
33790
33791 MA_API void ma_apply_volume_factor_pcm_frames_s32(ma_int32* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
33792 {
33793     ma_copy_and_apply_volume_factor_pcm_frames_s32(pPCMFrames, pPCMFrames, frameCount, channels, factor);
33794 }
33795
33796 MA_API void ma_apply_volume_factor_pcm_frames_f32(float* pPCMFrames, ma_uint64 frameCount, ma_uint32 channels, float factor)
33797 {
33798     ma_copy_and_apply_volume_factor_pcm_frames_f32(pPCMFrames, pPCMFrames, frameCount, channels, factor);
33799 }
33800
33801 MA_API void ma_apply_volume_factor_pcm_frames(void* pPCMFrames, ma_uint64 frameCount, ma_format format, ma_uint32 channels, float factor)
33802 {
33803     ma_copy_and_apply_volume_factor_pcm_frames(pPCMFrames, pPCMFrames, frameCount, format, channels, factor);
33804 }
33805
33806
33807 MA_API float ma_factor_to_gain_db(float factor)
33808 {
33809     return (float)(20*ma_log10f(factor));
33810 }
33811
33812 MA_API float ma_gain_db_to_factor(float gain)
33813 {
33814     return (float)ma_powf(10, gain/20.0f);
33815 }
33816
33817
33818 /**************************************************************************************************************************************************************
33819
33820 Format Conversion
33821
33822 **************************************************************************************************************************************************************/
33823
33824 static MA_INLINE ma_int16 ma_pcm_sample_f32_to_s16(float x)
33825 {
33826     return (ma_int16)(x * 32767.0f);
33827 }
33828
33829 static MA_INLINE ma_int16 ma_pcm_sample_u8_to_s16_no_scale(ma_uint8 x)
33830 {
33831     return (ma_int16)((ma_int16)x - 128);
33832 }
33833
33834 static MA_INLINE ma_int64 ma_pcm_sample_s24_to_s32_no_scale(const ma_uint8* x)
33835 {
33836     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. */
33837 }
33838
33839 static MA_INLINE void ma_pcm_sample_s32_to_s24_no_scale(ma_int64 x, ma_uint8* s24)
33840 {
33841     s24[0] = (ma_uint8)((x & 0x000000FF) >>  0);
33842     s24[1] = (ma_uint8)((x & 0x0000FF00) >>  8);
33843     s24[2] = (ma_uint8)((x & 0x00FF0000) >> 16);
33844 }
33845
33846
33847 static MA_INLINE ma_uint8 ma_clip_u8(ma_int16 x)
33848 {
33849     return (ma_uint8)(ma_clamp(x, -128, 127) + 128);
33850 }
33851
33852 static MA_INLINE ma_int16 ma_clip_s16(ma_int32 x)
33853 {
33854     return (ma_int16)ma_clamp(x, -32768, 32767);
33855 }
33856
33857 static MA_INLINE ma_int64 ma_clip_s24(ma_int64 x)
33858 {
33859     return (ma_int64)ma_clamp(x, -8388608, 8388607);
33860 }
33861
33862 static MA_INLINE ma_int32 ma_clip_s32(ma_int64 x)
33863 {
33864     /* This dance is to silence warnings with -std=c89. A good compiler should be able to optimize this away. */
33865     ma_int64 clipMin;
33866     ma_int64 clipMax;
33867     clipMin = -((ma_int64)2147483647 + 1);
33868     clipMax =   (ma_int64)2147483647;
33869
33870     return (ma_int32)ma_clamp(x, clipMin, clipMax);
33871 }
33872
33873
33874 /* u8 */
33875 MA_API void ma_pcm_u8_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33876 {
33877     (void)ditherMode;
33878     ma_copy_memory_64(dst, src, count * sizeof(ma_uint8));
33879 }
33880
33881
33882 static MA_INLINE void ma_pcm_u8_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33883 {
33884     ma_int16* dst_s16 = (ma_int16*)dst;
33885     const ma_uint8* src_u8 = (const ma_uint8*)src;
33886
33887     ma_uint64 i;
33888     for (i = 0; i < count; i += 1) {
33889         ma_int16 x = src_u8[i];
33890         x = (ma_int16)(x - 128);
33891         x = (ma_int16)(x << 8);
33892         dst_s16[i] = x;
33893     }
33894
33895     (void)ditherMode;
33896 }
33897
33898 static MA_INLINE void ma_pcm_u8_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33899 {
33900     ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode);
33901 }
33902
33903 #if defined(MA_SUPPORT_SSE2)
33904 static MA_INLINE void ma_pcm_u8_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33905 {
33906     ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
33907 }
33908 #endif
33909 #if defined(MA_SUPPORT_AVX2)
33910 static MA_INLINE void ma_pcm_u8_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33911 {
33912     ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
33913 }
33914 #endif
33915 #if defined(MA_SUPPORT_NEON)
33916 static MA_INLINE void ma_pcm_u8_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33917 {
33918     ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
33919 }
33920 #endif
33921
33922 MA_API void ma_pcm_u8_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33923 {
33924 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
33925     ma_pcm_u8_to_s16__reference(dst, src, count, ditherMode);
33926 #else
33927     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
33928         if (ma_has_avx2()) {
33929             ma_pcm_u8_to_s16__avx2(dst, src, count, ditherMode);
33930         } else
33931     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
33932         if (ma_has_sse2()) {
33933             ma_pcm_u8_to_s16__sse2(dst, src, count, ditherMode);
33934         } else
33935     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
33936         if (ma_has_neon()) {
33937             ma_pcm_u8_to_s16__neon(dst, src, count, ditherMode);
33938         } else
33939     #endif
33940         {
33941             ma_pcm_u8_to_s16__optimized(dst, src, count, ditherMode);
33942         }
33943 #endif
33944 }
33945
33946
33947 static MA_INLINE void ma_pcm_u8_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33948 {
33949     ma_uint8* dst_s24 = (ma_uint8*)dst;
33950     const ma_uint8* src_u8 = (const ma_uint8*)src;
33951
33952     ma_uint64 i;
33953     for (i = 0; i < count; i += 1) {
33954         ma_int16 x = src_u8[i];
33955         x = (ma_int16)(x - 128);
33956
33957         dst_s24[i*3+0] = 0;
33958         dst_s24[i*3+1] = 0;
33959         dst_s24[i*3+2] = (ma_uint8)((ma_int8)x);
33960     }
33961
33962     (void)ditherMode;
33963 }
33964
33965 static MA_INLINE void ma_pcm_u8_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33966 {
33967     ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode);
33968 }
33969
33970 #if defined(MA_SUPPORT_SSE2)
33971 static MA_INLINE void ma_pcm_u8_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33972 {
33973     ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
33974 }
33975 #endif
33976 #if defined(MA_SUPPORT_AVX2)
33977 static MA_INLINE void ma_pcm_u8_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33978 {
33979     ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
33980 }
33981 #endif
33982 #if defined(MA_SUPPORT_NEON)
33983 static MA_INLINE void ma_pcm_u8_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33984 {
33985     ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
33986 }
33987 #endif
33988
33989 MA_API void ma_pcm_u8_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
33990 {
33991 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
33992     ma_pcm_u8_to_s24__reference(dst, src, count, ditherMode);
33993 #else
33994     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
33995         if (ma_has_avx2()) {
33996             ma_pcm_u8_to_s24__avx2(dst, src, count, ditherMode);
33997         } else
33998     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
33999         if (ma_has_sse2()) {
34000             ma_pcm_u8_to_s24__sse2(dst, src, count, ditherMode);
34001         } else
34002     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34003         if (ma_has_neon()) {
34004             ma_pcm_u8_to_s24__neon(dst, src, count, ditherMode);
34005         } else
34006     #endif
34007         {
34008             ma_pcm_u8_to_s24__optimized(dst, src, count, ditherMode);
34009         }
34010 #endif
34011 }
34012
34013
34014 static MA_INLINE void ma_pcm_u8_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34015 {
34016     ma_int32* dst_s32 = (ma_int32*)dst;
34017     const ma_uint8* src_u8 = (const ma_uint8*)src;
34018
34019     ma_uint64 i;
34020     for (i = 0; i < count; i += 1) {
34021         ma_int32 x = src_u8[i];
34022         x = x - 128;
34023         x = x << 24;
34024         dst_s32[i] = x;
34025     }
34026
34027     (void)ditherMode;
34028 }
34029
34030 static MA_INLINE void ma_pcm_u8_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34031 {
34032     ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode);
34033 }
34034
34035 #if defined(MA_SUPPORT_SSE2)
34036 static MA_INLINE void ma_pcm_u8_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34037 {
34038     ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
34039 }
34040 #endif
34041 #if defined(MA_SUPPORT_AVX2)
34042 static MA_INLINE void ma_pcm_u8_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34043 {
34044     ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
34045 }
34046 #endif
34047 #if defined(MA_SUPPORT_NEON)
34048 static MA_INLINE void ma_pcm_u8_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34049 {
34050     ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
34051 }
34052 #endif
34053
34054 MA_API void ma_pcm_u8_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34055 {
34056 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34057     ma_pcm_u8_to_s32__reference(dst, src, count, ditherMode);
34058 #else
34059     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34060         if (ma_has_avx2()) {
34061             ma_pcm_u8_to_s32__avx2(dst, src, count, ditherMode);
34062         } else
34063     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34064         if (ma_has_sse2()) {
34065             ma_pcm_u8_to_s32__sse2(dst, src, count, ditherMode);
34066         } else
34067     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34068         if (ma_has_neon()) {
34069             ma_pcm_u8_to_s32__neon(dst, src, count, ditherMode);
34070         } else
34071     #endif
34072         {
34073             ma_pcm_u8_to_s32__optimized(dst, src, count, ditherMode);
34074         }
34075 #endif
34076 }
34077
34078
34079 static MA_INLINE void ma_pcm_u8_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34080 {
34081     float* dst_f32 = (float*)dst;
34082     const ma_uint8* src_u8 = (const ma_uint8*)src;
34083
34084     ma_uint64 i;
34085     for (i = 0; i < count; i += 1) {
34086         float x = (float)src_u8[i];
34087         x = x * 0.00784313725490196078f;    /* 0..255 to 0..2 */
34088         x = x - 1;                          /* 0..2 to -1..1 */
34089
34090         dst_f32[i] = x;
34091     }
34092
34093     (void)ditherMode;
34094 }
34095
34096 static MA_INLINE void ma_pcm_u8_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34097 {
34098     ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode);
34099 }
34100
34101 #if defined(MA_SUPPORT_SSE2)
34102 static MA_INLINE void ma_pcm_u8_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34103 {
34104     ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
34105 }
34106 #endif
34107 #if defined(MA_SUPPORT_AVX2)
34108 static MA_INLINE void ma_pcm_u8_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34109 {
34110     ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
34111 }
34112 #endif
34113 #if defined(MA_SUPPORT_NEON)
34114 static MA_INLINE void ma_pcm_u8_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34115 {
34116     ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
34117 }
34118 #endif
34119
34120 MA_API void ma_pcm_u8_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34121 {
34122 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34123     ma_pcm_u8_to_f32__reference(dst, src, count, ditherMode);
34124 #else
34125     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34126         if (ma_has_avx2()) {
34127             ma_pcm_u8_to_f32__avx2(dst, src, count, ditherMode);
34128         } else
34129     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34130         if (ma_has_sse2()) {
34131             ma_pcm_u8_to_f32__sse2(dst, src, count, ditherMode);
34132         } else
34133     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34134         if (ma_has_neon()) {
34135             ma_pcm_u8_to_f32__neon(dst, src, count, ditherMode);
34136         } else
34137     #endif
34138         {
34139             ma_pcm_u8_to_f32__optimized(dst, src, count, ditherMode);
34140         }
34141 #endif
34142 }
34143
34144
34145 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34146 static MA_INLINE void ma_pcm_interleave_u8__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34147 {
34148     ma_uint8* dst_u8 = (ma_uint8*)dst;
34149     const ma_uint8** src_u8 = (const ma_uint8**)src;
34150
34151     ma_uint64 iFrame;
34152     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34153         ma_uint32 iChannel;
34154         for (iChannel = 0; iChannel < channels; iChannel += 1) {
34155             dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame];
34156         }
34157     }
34158 }
34159 #else
34160 static MA_INLINE void ma_pcm_interleave_u8__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34161 {
34162     ma_uint8* dst_u8 = (ma_uint8*)dst;
34163     const ma_uint8** src_u8 = (const ma_uint8**)src;
34164
34165     if (channels == 1) {
34166         ma_copy_memory_64(dst, src[0], frameCount * sizeof(ma_uint8));
34167     } else if (channels == 2) {
34168         ma_uint64 iFrame;
34169         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34170             dst_u8[iFrame*2 + 0] = src_u8[0][iFrame];
34171             dst_u8[iFrame*2 + 1] = src_u8[1][iFrame];
34172         }
34173     } else {
34174         ma_uint64 iFrame;
34175         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34176             ma_uint32 iChannel;
34177             for (iChannel = 0; iChannel < channels; iChannel += 1) {
34178                 dst_u8[iFrame*channels + iChannel] = src_u8[iChannel][iFrame];
34179             }
34180         }
34181     }
34182 }
34183 #endif
34184
34185 MA_API void ma_pcm_interleave_u8(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34186 {
34187 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34188     ma_pcm_interleave_u8__reference(dst, src, frameCount, channels);
34189 #else
34190     ma_pcm_interleave_u8__optimized(dst, src, frameCount, channels);
34191 #endif
34192 }
34193
34194
34195 static MA_INLINE void ma_pcm_deinterleave_u8__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34196 {
34197     ma_uint8** dst_u8 = (ma_uint8**)dst;
34198     const ma_uint8* src_u8 = (const ma_uint8*)src;
34199
34200     ma_uint64 iFrame;
34201     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34202         ma_uint32 iChannel;
34203         for (iChannel = 0; iChannel < channels; iChannel += 1) {
34204             dst_u8[iChannel][iFrame] = src_u8[iFrame*channels + iChannel];
34205         }
34206     }
34207 }
34208
34209 static MA_INLINE void ma_pcm_deinterleave_u8__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34210 {
34211     ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels);
34212 }
34213
34214 MA_API void ma_pcm_deinterleave_u8(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34215 {
34216 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34217     ma_pcm_deinterleave_u8__reference(dst, src, frameCount, channels);
34218 #else
34219     ma_pcm_deinterleave_u8__optimized(dst, src, frameCount, channels);
34220 #endif
34221 }
34222
34223
34224 /* s16 */
34225 static MA_INLINE void ma_pcm_s16_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34226 {
34227     ma_uint8* dst_u8 = (ma_uint8*)dst;
34228     const ma_int16* src_s16 = (const ma_int16*)src;
34229
34230     if (ditherMode == ma_dither_mode_none) {
34231         ma_uint64 i;
34232         for (i = 0; i < count; i += 1) {
34233             ma_int16 x = src_s16[i];
34234             x = (ma_int16)(x >> 8);
34235             x = (ma_int16)(x + 128);
34236             dst_u8[i] = (ma_uint8)x;
34237         }
34238     } else {
34239         ma_uint64 i;
34240         for (i = 0; i < count; i += 1) {
34241             ma_int16 x = src_s16[i];
34242
34243             /* Dither. Don't overflow. */
34244             ma_int32 dither = ma_dither_s32(ditherMode, -0x80, 0x7F);
34245             if ((x + dither) <= 0x7FFF) {
34246                 x = (ma_int16)(x + dither);
34247             } else {
34248                 x = 0x7FFF;
34249             }
34250
34251             x = (ma_int16)(x >> 8);
34252             x = (ma_int16)(x + 128);
34253             dst_u8[i] = (ma_uint8)x;
34254         }
34255     }
34256 }
34257
34258 static MA_INLINE void ma_pcm_s16_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34259 {
34260     ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode);
34261 }
34262
34263 #if defined(MA_SUPPORT_SSE2)
34264 static MA_INLINE void ma_pcm_s16_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34265 {
34266     ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
34267 }
34268 #endif
34269 #if defined(MA_SUPPORT_AVX2)
34270 static MA_INLINE void ma_pcm_s16_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34271 {
34272     ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
34273 }
34274 #endif
34275 #if defined(MA_SUPPORT_NEON)
34276 static MA_INLINE void ma_pcm_s16_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34277 {
34278     ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
34279 }
34280 #endif
34281
34282 MA_API void ma_pcm_s16_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34283 {
34284 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34285     ma_pcm_s16_to_u8__reference(dst, src, count, ditherMode);
34286 #else
34287     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34288         if (ma_has_avx2()) {
34289             ma_pcm_s16_to_u8__avx2(dst, src, count, ditherMode);
34290         } else
34291     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34292         if (ma_has_sse2()) {
34293             ma_pcm_s16_to_u8__sse2(dst, src, count, ditherMode);
34294         } else
34295     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34296         if (ma_has_neon()) {
34297             ma_pcm_s16_to_u8__neon(dst, src, count, ditherMode);
34298         } else
34299     #endif
34300         {
34301             ma_pcm_s16_to_u8__optimized(dst, src, count, ditherMode);
34302         }
34303 #endif
34304 }
34305
34306
34307 MA_API void ma_pcm_s16_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34308 {
34309     (void)ditherMode;
34310     ma_copy_memory_64(dst, src, count * sizeof(ma_int16));
34311 }
34312
34313
34314 static MA_INLINE void ma_pcm_s16_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34315 {
34316     ma_uint8* dst_s24 = (ma_uint8*)dst;
34317     const ma_int16* src_s16 = (const ma_int16*)src;
34318
34319     ma_uint64 i;
34320     for (i = 0; i < count; i += 1) {
34321         dst_s24[i*3+0] = 0;
34322         dst_s24[i*3+1] = (ma_uint8)(src_s16[i] & 0xFF);
34323         dst_s24[i*3+2] = (ma_uint8)(src_s16[i] >> 8);
34324     }
34325
34326     (void)ditherMode;
34327 }
34328
34329 static MA_INLINE void ma_pcm_s16_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34330 {
34331     ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode);
34332 }
34333
34334 #if defined(MA_SUPPORT_SSE2)
34335 static MA_INLINE void ma_pcm_s16_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34336 {
34337     ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
34338 }
34339 #endif
34340 #if defined(MA_SUPPORT_AVX2)
34341 static MA_INLINE void ma_pcm_s16_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34342 {
34343     ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
34344 }
34345 #endif
34346 #if defined(MA_SUPPORT_NEON)
34347 static MA_INLINE void ma_pcm_s16_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34348 {
34349     ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
34350 }
34351 #endif
34352
34353 MA_API void ma_pcm_s16_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34354 {
34355 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34356     ma_pcm_s16_to_s24__reference(dst, src, count, ditherMode);
34357 #else
34358     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34359         if (ma_has_avx2()) {
34360             ma_pcm_s16_to_s24__avx2(dst, src, count, ditherMode);
34361         } else
34362     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34363         if (ma_has_sse2()) {
34364             ma_pcm_s16_to_s24__sse2(dst, src, count, ditherMode);
34365         } else
34366     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34367         if (ma_has_neon()) {
34368             ma_pcm_s16_to_s24__neon(dst, src, count, ditherMode);
34369         } else
34370     #endif
34371         {
34372             ma_pcm_s16_to_s24__optimized(dst, src, count, ditherMode);
34373         }
34374 #endif
34375 }
34376
34377
34378 static MA_INLINE void ma_pcm_s16_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34379 {
34380     ma_int32* dst_s32 = (ma_int32*)dst;
34381     const ma_int16* src_s16 = (const ma_int16*)src;
34382
34383     ma_uint64 i;
34384     for (i = 0; i < count; i += 1) {
34385         dst_s32[i] = src_s16[i] << 16;
34386     }
34387
34388     (void)ditherMode;
34389 }
34390
34391 static MA_INLINE void ma_pcm_s16_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34392 {
34393     ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode);
34394 }
34395
34396 #if defined(MA_SUPPORT_SSE2)
34397 static MA_INLINE void ma_pcm_s16_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34398 {
34399     ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
34400 }
34401 #endif
34402 #if defined(MA_SUPPORT_AVX2)
34403 static MA_INLINE void ma_pcm_s16_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34404 {
34405     ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
34406 }
34407 #endif
34408 #if defined(MA_SUPPORT_NEON)
34409 static MA_INLINE void ma_pcm_s16_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34410 {
34411     ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
34412 }
34413 #endif
34414
34415 MA_API void ma_pcm_s16_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34416 {
34417 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34418     ma_pcm_s16_to_s32__reference(dst, src, count, ditherMode);
34419 #else
34420     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34421         if (ma_has_avx2()) {
34422             ma_pcm_s16_to_s32__avx2(dst, src, count, ditherMode);
34423         } else
34424     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34425         if (ma_has_sse2()) {
34426             ma_pcm_s16_to_s32__sse2(dst, src, count, ditherMode);
34427         } else
34428     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34429         if (ma_has_neon()) {
34430             ma_pcm_s16_to_s32__neon(dst, src, count, ditherMode);
34431         } else
34432     #endif
34433         {
34434             ma_pcm_s16_to_s32__optimized(dst, src, count, ditherMode);
34435         }
34436 #endif
34437 }
34438
34439
34440 static MA_INLINE void ma_pcm_s16_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34441 {
34442     float* dst_f32 = (float*)dst;
34443     const ma_int16* src_s16 = (const ma_int16*)src;
34444
34445     ma_uint64 i;
34446     for (i = 0; i < count; i += 1) {
34447         float x = (float)src_s16[i];
34448
34449 #if 0
34450         /* The accurate way. */
34451         x = x + 32768.0f;                   /* -32768..32767 to 0..65535 */
34452         x = x * 0.00003051804379339284f;    /* 0..65535 to 0..2 */
34453         x = x - 1;                          /* 0..2 to -1..1 */
34454 #else
34455         /* The fast way. */
34456         x = x * 0.000030517578125f;         /* -32768..32767 to -1..0.999969482421875 */
34457 #endif
34458
34459         dst_f32[i] = x;
34460     }
34461
34462     (void)ditherMode;
34463 }
34464
34465 static MA_INLINE void ma_pcm_s16_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34466 {
34467     ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode);
34468 }
34469
34470 #if defined(MA_SUPPORT_SSE2)
34471 static MA_INLINE void ma_pcm_s16_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34472 {
34473     ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
34474 }
34475 #endif
34476 #if defined(MA_SUPPORT_AVX2)
34477 static MA_INLINE void ma_pcm_s16_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34478 {
34479     ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
34480 }
34481 #endif
34482 #if defined(MA_SUPPORT_NEON)
34483 static MA_INLINE void ma_pcm_s16_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34484 {
34485     ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
34486 }
34487 #endif
34488
34489 MA_API void ma_pcm_s16_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34490 {
34491 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34492     ma_pcm_s16_to_f32__reference(dst, src, count, ditherMode);
34493 #else
34494     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34495         if (ma_has_avx2()) {
34496             ma_pcm_s16_to_f32__avx2(dst, src, count, ditherMode);
34497         } else
34498     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34499         if (ma_has_sse2()) {
34500             ma_pcm_s16_to_f32__sse2(dst, src, count, ditherMode);
34501         } else
34502     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34503         if (ma_has_neon()) {
34504             ma_pcm_s16_to_f32__neon(dst, src, count, ditherMode);
34505         } else
34506     #endif
34507         {
34508             ma_pcm_s16_to_f32__optimized(dst, src, count, ditherMode);
34509         }
34510 #endif
34511 }
34512
34513
34514 static MA_INLINE void ma_pcm_interleave_s16__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34515 {
34516     ma_int16* dst_s16 = (ma_int16*)dst;
34517     const ma_int16** src_s16 = (const ma_int16**)src;
34518
34519     ma_uint64 iFrame;
34520     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34521         ma_uint32 iChannel;
34522         for (iChannel = 0; iChannel < channels; iChannel += 1) {
34523             dst_s16[iFrame*channels + iChannel] = src_s16[iChannel][iFrame];
34524         }
34525     }
34526 }
34527
34528 static MA_INLINE void ma_pcm_interleave_s16__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34529 {
34530     ma_pcm_interleave_s16__reference(dst, src, frameCount, channels);
34531 }
34532
34533 MA_API void ma_pcm_interleave_s16(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34534 {
34535 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34536     ma_pcm_interleave_s16__reference(dst, src, frameCount, channels);
34537 #else
34538     ma_pcm_interleave_s16__optimized(dst, src, frameCount, channels);
34539 #endif
34540 }
34541
34542
34543 static MA_INLINE void ma_pcm_deinterleave_s16__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34544 {
34545     ma_int16** dst_s16 = (ma_int16**)dst;
34546     const ma_int16* src_s16 = (const ma_int16*)src;
34547
34548     ma_uint64 iFrame;
34549     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34550         ma_uint32 iChannel;
34551         for (iChannel = 0; iChannel < channels; iChannel += 1) {
34552             dst_s16[iChannel][iFrame] = src_s16[iFrame*channels + iChannel];
34553         }
34554     }
34555 }
34556
34557 static MA_INLINE void ma_pcm_deinterleave_s16__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34558 {
34559     ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels);
34560 }
34561
34562 MA_API void ma_pcm_deinterleave_s16(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34563 {
34564 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34565     ma_pcm_deinterleave_s16__reference(dst, src, frameCount, channels);
34566 #else
34567     ma_pcm_deinterleave_s16__optimized(dst, src, frameCount, channels);
34568 #endif
34569 }
34570
34571
34572 /* s24 */
34573 static MA_INLINE void ma_pcm_s24_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34574 {
34575     ma_uint8* dst_u8 = (ma_uint8*)dst;
34576     const ma_uint8* src_s24 = (const ma_uint8*)src;
34577
34578     if (ditherMode == ma_dither_mode_none) {
34579         ma_uint64 i;
34580         for (i = 0; i < count; i += 1) {
34581             dst_u8[i] = (ma_uint8)((ma_int8)src_s24[i*3 + 2] + 128);
34582         }
34583     } else {
34584         ma_uint64 i;
34585         for (i = 0; i < count; i += 1) {
34586             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);
34587
34588             /* Dither. Don't overflow. */
34589             ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF);
34590             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
34591                 x = x + dither;
34592             } else {
34593                 x = 0x7FFFFFFF;
34594             }
34595
34596             x = x >> 24;
34597             x = x + 128;
34598             dst_u8[i] = (ma_uint8)x;
34599         }
34600     }
34601 }
34602
34603 static MA_INLINE void ma_pcm_s24_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34604 {
34605     ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode);
34606 }
34607
34608 #if defined(MA_SUPPORT_SSE2)
34609 static MA_INLINE void ma_pcm_s24_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34610 {
34611     ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
34612 }
34613 #endif
34614 #if defined(MA_SUPPORT_AVX2)
34615 static MA_INLINE void ma_pcm_s24_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34616 {
34617     ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
34618 }
34619 #endif
34620 #if defined(MA_SUPPORT_NEON)
34621 static MA_INLINE void ma_pcm_s24_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34622 {
34623     ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
34624 }
34625 #endif
34626
34627 MA_API void ma_pcm_s24_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34628 {
34629 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34630     ma_pcm_s24_to_u8__reference(dst, src, count, ditherMode);
34631 #else
34632     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34633         if (ma_has_avx2()) {
34634             ma_pcm_s24_to_u8__avx2(dst, src, count, ditherMode);
34635         } else
34636     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34637         if (ma_has_sse2()) {
34638             ma_pcm_s24_to_u8__sse2(dst, src, count, ditherMode);
34639         } else
34640     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34641         if (ma_has_neon()) {
34642             ma_pcm_s24_to_u8__neon(dst, src, count, ditherMode);
34643         } else
34644     #endif
34645         {
34646             ma_pcm_s24_to_u8__optimized(dst, src, count, ditherMode);
34647         }
34648 #endif
34649 }
34650
34651
34652 static MA_INLINE void ma_pcm_s24_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34653 {
34654     ma_int16* dst_s16 = (ma_int16*)dst;
34655     const ma_uint8* src_s24 = (const ma_uint8*)src;
34656
34657     if (ditherMode == ma_dither_mode_none) {
34658         ma_uint64 i;
34659         for (i = 0; i < count; i += 1) {
34660             ma_uint16 dst_lo =            ((ma_uint16)src_s24[i*3 + 1]);
34661             ma_uint16 dst_hi = (ma_uint16)((ma_uint16)src_s24[i*3 + 2] << 8);
34662             dst_s16[i] = (ma_int16)(dst_lo | dst_hi);
34663         }
34664     } else {
34665         ma_uint64 i;
34666         for (i = 0; i < count; i += 1) {
34667             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);
34668
34669             /* Dither. Don't overflow. */
34670             ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF);
34671             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
34672                 x = x + dither;
34673             } else {
34674                 x = 0x7FFFFFFF;
34675             }
34676
34677             x = x >> 16;
34678             dst_s16[i] = (ma_int16)x;
34679         }
34680     }
34681 }
34682
34683 static MA_INLINE void ma_pcm_s24_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34684 {
34685     ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode);
34686 }
34687
34688 #if defined(MA_SUPPORT_SSE2)
34689 static MA_INLINE void ma_pcm_s24_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34690 {
34691     ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
34692 }
34693 #endif
34694 #if defined(MA_SUPPORT_AVX2)
34695 static MA_INLINE void ma_pcm_s24_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34696 {
34697     ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
34698 }
34699 #endif
34700 #if defined(MA_SUPPORT_NEON)
34701 static MA_INLINE void ma_pcm_s24_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34702 {
34703     ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
34704 }
34705 #endif
34706
34707 MA_API void ma_pcm_s24_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34708 {
34709 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34710     ma_pcm_s24_to_s16__reference(dst, src, count, ditherMode);
34711 #else
34712     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34713         if (ma_has_avx2()) {
34714             ma_pcm_s24_to_s16__avx2(dst, src, count, ditherMode);
34715         } else
34716     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34717         if (ma_has_sse2()) {
34718             ma_pcm_s24_to_s16__sse2(dst, src, count, ditherMode);
34719         } else
34720     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34721         if (ma_has_neon()) {
34722             ma_pcm_s24_to_s16__neon(dst, src, count, ditherMode);
34723         } else
34724     #endif
34725         {
34726             ma_pcm_s24_to_s16__optimized(dst, src, count, ditherMode);
34727         }
34728 #endif
34729 }
34730
34731
34732 MA_API void ma_pcm_s24_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34733 {
34734     (void)ditherMode;
34735
34736     ma_copy_memory_64(dst, src, count * 3);
34737 }
34738
34739
34740 static MA_INLINE void ma_pcm_s24_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34741 {
34742     ma_int32* dst_s32 = (ma_int32*)dst;
34743     const ma_uint8* src_s24 = (const ma_uint8*)src;
34744
34745     ma_uint64 i;
34746     for (i = 0; i < count; i += 1) {
34747         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);
34748     }
34749
34750     (void)ditherMode;
34751 }
34752
34753 static MA_INLINE void ma_pcm_s24_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34754 {
34755     ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode);
34756 }
34757
34758 #if defined(MA_SUPPORT_SSE2)
34759 static MA_INLINE void ma_pcm_s24_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34760 {
34761     ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
34762 }
34763 #endif
34764 #if defined(MA_SUPPORT_AVX2)
34765 static MA_INLINE void ma_pcm_s24_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34766 {
34767     ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
34768 }
34769 #endif
34770 #if defined(MA_SUPPORT_NEON)
34771 static MA_INLINE void ma_pcm_s24_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34772 {
34773     ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
34774 }
34775 #endif
34776
34777 MA_API void ma_pcm_s24_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34778 {
34779 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34780     ma_pcm_s24_to_s32__reference(dst, src, count, ditherMode);
34781 #else
34782     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34783         if (ma_has_avx2()) {
34784             ma_pcm_s24_to_s32__avx2(dst, src, count, ditherMode);
34785         } else
34786     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34787         if (ma_has_sse2()) {
34788             ma_pcm_s24_to_s32__sse2(dst, src, count, ditherMode);
34789         } else
34790     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34791         if (ma_has_neon()) {
34792             ma_pcm_s24_to_s32__neon(dst, src, count, ditherMode);
34793         } else
34794     #endif
34795         {
34796             ma_pcm_s24_to_s32__optimized(dst, src, count, ditherMode);
34797         }
34798 #endif
34799 }
34800
34801
34802 static MA_INLINE void ma_pcm_s24_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34803 {
34804     float* dst_f32 = (float*)dst;
34805     const ma_uint8* src_s24 = (const ma_uint8*)src;
34806
34807     ma_uint64 i;
34808     for (i = 0; i < count; i += 1) {
34809         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);
34810
34811 #if 0
34812         /* The accurate way. */
34813         x = x + 8388608.0f;                 /* -8388608..8388607 to 0..16777215 */
34814         x = x * 0.00000011920929665621f;    /* 0..16777215 to 0..2 */
34815         x = x - 1;                          /* 0..2 to -1..1 */
34816 #else
34817         /* The fast way. */
34818         x = x * 0.00000011920928955078125f; /* -8388608..8388607 to -1..0.999969482421875 */
34819 #endif
34820
34821         dst_f32[i] = x;
34822     }
34823
34824     (void)ditherMode;
34825 }
34826
34827 static MA_INLINE void ma_pcm_s24_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34828 {
34829     ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode);
34830 }
34831
34832 #if defined(MA_SUPPORT_SSE2)
34833 static MA_INLINE void ma_pcm_s24_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34834 {
34835     ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
34836 }
34837 #endif
34838 #if defined(MA_SUPPORT_AVX2)
34839 static MA_INLINE void ma_pcm_s24_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34840 {
34841     ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
34842 }
34843 #endif
34844 #if defined(MA_SUPPORT_NEON)
34845 static MA_INLINE void ma_pcm_s24_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34846 {
34847     ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
34848 }
34849 #endif
34850
34851 MA_API void ma_pcm_s24_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34852 {
34853 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34854     ma_pcm_s24_to_f32__reference(dst, src, count, ditherMode);
34855 #else
34856     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
34857         if (ma_has_avx2()) {
34858             ma_pcm_s24_to_f32__avx2(dst, src, count, ditherMode);
34859         } else
34860     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
34861         if (ma_has_sse2()) {
34862             ma_pcm_s24_to_f32__sse2(dst, src, count, ditherMode);
34863         } else
34864     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
34865         if (ma_has_neon()) {
34866             ma_pcm_s24_to_f32__neon(dst, src, count, ditherMode);
34867         } else
34868     #endif
34869         {
34870             ma_pcm_s24_to_f32__optimized(dst, src, count, ditherMode);
34871         }
34872 #endif
34873 }
34874
34875
34876 static MA_INLINE void ma_pcm_interleave_s24__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34877 {
34878     ma_uint8* dst8 = (ma_uint8*)dst;
34879     const ma_uint8** src8 = (const ma_uint8**)src;
34880
34881     ma_uint64 iFrame;
34882     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34883         ma_uint32 iChannel;
34884         for (iChannel = 0; iChannel < channels; iChannel += 1) {
34885             dst8[iFrame*3*channels + iChannel*3 + 0] = src8[iChannel][iFrame*3 + 0];
34886             dst8[iFrame*3*channels + iChannel*3 + 1] = src8[iChannel][iFrame*3 + 1];
34887             dst8[iFrame*3*channels + iChannel*3 + 2] = src8[iChannel][iFrame*3 + 2];
34888         }
34889     }
34890 }
34891
34892 static MA_INLINE void ma_pcm_interleave_s24__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34893 {
34894     ma_pcm_interleave_s24__reference(dst, src, frameCount, channels);
34895 }
34896
34897 MA_API void ma_pcm_interleave_s24(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
34898 {
34899 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34900     ma_pcm_interleave_s24__reference(dst, src, frameCount, channels);
34901 #else
34902     ma_pcm_interleave_s24__optimized(dst, src, frameCount, channels);
34903 #endif
34904 }
34905
34906
34907 static MA_INLINE void ma_pcm_deinterleave_s24__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34908 {
34909     ma_uint8** dst8 = (ma_uint8**)dst;
34910     const ma_uint8* src8 = (const ma_uint8*)src;
34911
34912     ma_uint32 iFrame;
34913     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
34914         ma_uint32 iChannel;
34915         for (iChannel = 0; iChannel < channels; iChannel += 1) {
34916             dst8[iChannel][iFrame*3 + 0] = src8[iFrame*3*channels + iChannel*3 + 0];
34917             dst8[iChannel][iFrame*3 + 1] = src8[iFrame*3*channels + iChannel*3 + 1];
34918             dst8[iChannel][iFrame*3 + 2] = src8[iFrame*3*channels + iChannel*3 + 2];
34919         }
34920     }
34921 }
34922
34923 static MA_INLINE void ma_pcm_deinterleave_s24__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34924 {
34925     ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels);
34926 }
34927
34928 MA_API void ma_pcm_deinterleave_s24(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
34929 {
34930 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
34931     ma_pcm_deinterleave_s24__reference(dst, src, frameCount, channels);
34932 #else
34933     ma_pcm_deinterleave_s24__optimized(dst, src, frameCount, channels);
34934 #endif
34935 }
34936
34937
34938
34939 /* s32 */
34940 static MA_INLINE void ma_pcm_s32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34941 {
34942     ma_uint8* dst_u8 = (ma_uint8*)dst;
34943     const ma_int32* src_s32 = (const ma_int32*)src;
34944
34945     if (ditherMode == ma_dither_mode_none) {
34946         ma_uint64 i;
34947         for (i = 0; i < count; i += 1) {
34948             ma_int32 x = src_s32[i];
34949             x = x >> 24;
34950             x = x + 128;
34951             dst_u8[i] = (ma_uint8)x;
34952         }
34953     } else {
34954         ma_uint64 i;
34955         for (i = 0; i < count; i += 1) {
34956             ma_int32 x = src_s32[i];
34957
34958             /* Dither. Don't overflow. */
34959             ma_int32 dither = ma_dither_s32(ditherMode, -0x800000, 0x7FFFFF);
34960             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
34961                 x = x + dither;
34962             } else {
34963                 x = 0x7FFFFFFF;
34964             }
34965
34966             x = x >> 24;
34967             x = x + 128;
34968             dst_u8[i] = (ma_uint8)x;
34969         }
34970     }
34971 }
34972
34973 static MA_INLINE void ma_pcm_s32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34974 {
34975     ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode);
34976 }
34977
34978 #if defined(MA_SUPPORT_SSE2)
34979 static MA_INLINE void ma_pcm_s32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34980 {
34981     ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
34982 }
34983 #endif
34984 #if defined(MA_SUPPORT_AVX2)
34985 static MA_INLINE void ma_pcm_s32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34986 {
34987     ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
34988 }
34989 #endif
34990 #if defined(MA_SUPPORT_NEON)
34991 static MA_INLINE void ma_pcm_s32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34992 {
34993     ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
34994 }
34995 #endif
34996
34997 MA_API void ma_pcm_s32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
34998 {
34999 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35000     ma_pcm_s32_to_u8__reference(dst, src, count, ditherMode);
35001 #else
35002     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35003         if (ma_has_avx2()) {
35004             ma_pcm_s32_to_u8__avx2(dst, src, count, ditherMode);
35005         } else
35006     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35007         if (ma_has_sse2()) {
35008             ma_pcm_s32_to_u8__sse2(dst, src, count, ditherMode);
35009         } else
35010     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35011         if (ma_has_neon()) {
35012             ma_pcm_s32_to_u8__neon(dst, src, count, ditherMode);
35013         } else
35014     #endif
35015         {
35016             ma_pcm_s32_to_u8__optimized(dst, src, count, ditherMode);
35017         }
35018 #endif
35019 }
35020
35021
35022 static MA_INLINE void ma_pcm_s32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35023 {
35024     ma_int16* dst_s16 = (ma_int16*)dst;
35025     const ma_int32* src_s32 = (const ma_int32*)src;
35026
35027     if (ditherMode == ma_dither_mode_none) {
35028         ma_uint64 i;
35029         for (i = 0; i < count; i += 1) {
35030             ma_int32 x = src_s32[i];
35031             x = x >> 16;
35032             dst_s16[i] = (ma_int16)x;
35033         }
35034     } else {
35035         ma_uint64 i;
35036         for (i = 0; i < count; i += 1) {
35037             ma_int32 x = src_s32[i];
35038
35039             /* Dither. Don't overflow. */
35040             ma_int32 dither = ma_dither_s32(ditherMode, -0x8000, 0x7FFF);
35041             if ((ma_int64)x + dither <= 0x7FFFFFFF) {
35042                 x = x + dither;
35043             } else {
35044                 x = 0x7FFFFFFF;
35045             }
35046
35047             x = x >> 16;
35048             dst_s16[i] = (ma_int16)x;
35049         }
35050     }
35051 }
35052
35053 static MA_INLINE void ma_pcm_s32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35054 {
35055     ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode);
35056 }
35057
35058 #if defined(MA_SUPPORT_SSE2)
35059 static MA_INLINE void ma_pcm_s32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35060 {
35061     ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
35062 }
35063 #endif
35064 #if defined(MA_SUPPORT_AVX2)
35065 static MA_INLINE void ma_pcm_s32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35066 {
35067     ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
35068 }
35069 #endif
35070 #if defined(MA_SUPPORT_NEON)
35071 static MA_INLINE void ma_pcm_s32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35072 {
35073     ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
35074 }
35075 #endif
35076
35077 MA_API void ma_pcm_s32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35078 {
35079 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35080     ma_pcm_s32_to_s16__reference(dst, src, count, ditherMode);
35081 #else
35082     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35083         if (ma_has_avx2()) {
35084             ma_pcm_s32_to_s16__avx2(dst, src, count, ditherMode);
35085         } else
35086     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35087         if (ma_has_sse2()) {
35088             ma_pcm_s32_to_s16__sse2(dst, src, count, ditherMode);
35089         } else
35090     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35091         if (ma_has_neon()) {
35092             ma_pcm_s32_to_s16__neon(dst, src, count, ditherMode);
35093         } else
35094     #endif
35095         {
35096             ma_pcm_s32_to_s16__optimized(dst, src, count, ditherMode);
35097         }
35098 #endif
35099 }
35100
35101
35102 static MA_INLINE void ma_pcm_s32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35103 {
35104     ma_uint8* dst_s24 = (ma_uint8*)dst;
35105     const ma_int32* src_s32 = (const ma_int32*)src;
35106
35107     ma_uint64 i;
35108     for (i = 0; i < count; i += 1) {
35109         ma_uint32 x = (ma_uint32)src_s32[i];
35110         dst_s24[i*3+0] = (ma_uint8)((x & 0x0000FF00) >>  8);
35111         dst_s24[i*3+1] = (ma_uint8)((x & 0x00FF0000) >> 16);
35112         dst_s24[i*3+2] = (ma_uint8)((x & 0xFF000000) >> 24);
35113     }
35114
35115     (void)ditherMode;   /* No dithering for s32 -> s24. */
35116 }
35117
35118 static MA_INLINE void ma_pcm_s32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35119 {
35120     ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode);
35121 }
35122
35123 #if defined(MA_SUPPORT_SSE2)
35124 static MA_INLINE void ma_pcm_s32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35125 {
35126     ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
35127 }
35128 #endif
35129 #if defined(MA_SUPPORT_AVX2)
35130 static MA_INLINE void ma_pcm_s32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35131 {
35132     ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
35133 }
35134 #endif
35135 #if defined(MA_SUPPORT_NEON)
35136 static MA_INLINE void ma_pcm_s32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35137 {
35138     ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
35139 }
35140 #endif
35141
35142 MA_API void ma_pcm_s32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35143 {
35144 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35145     ma_pcm_s32_to_s24__reference(dst, src, count, ditherMode);
35146 #else
35147     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35148         if (ma_has_avx2()) {
35149             ma_pcm_s32_to_s24__avx2(dst, src, count, ditherMode);
35150         } else
35151     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35152         if (ma_has_sse2()) {
35153             ma_pcm_s32_to_s24__sse2(dst, src, count, ditherMode);
35154         } else
35155     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35156         if (ma_has_neon()) {
35157             ma_pcm_s32_to_s24__neon(dst, src, count, ditherMode);
35158         } else
35159     #endif
35160         {
35161             ma_pcm_s32_to_s24__optimized(dst, src, count, ditherMode);
35162         }
35163 #endif
35164 }
35165
35166
35167 MA_API void ma_pcm_s32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35168 {
35169     (void)ditherMode;
35170
35171     ma_copy_memory_64(dst, src, count * sizeof(ma_int32));
35172 }
35173
35174
35175 static MA_INLINE void ma_pcm_s32_to_f32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35176 {
35177     float* dst_f32 = (float*)dst;
35178     const ma_int32* src_s32 = (const ma_int32*)src;
35179
35180     ma_uint64 i;
35181     for (i = 0; i < count; i += 1) {
35182         double x = src_s32[i];
35183
35184 #if 0
35185         x = x + 2147483648.0;
35186         x = x * 0.0000000004656612873077392578125;
35187         x = x - 1;
35188 #else
35189         x = x / 2147483648.0;
35190 #endif
35191
35192         dst_f32[i] = (float)x;
35193     }
35194
35195     (void)ditherMode;   /* No dithering for s32 -> f32. */
35196 }
35197
35198 static MA_INLINE void ma_pcm_s32_to_f32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35199 {
35200     ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode);
35201 }
35202
35203 #if defined(MA_SUPPORT_SSE2)
35204 static MA_INLINE void ma_pcm_s32_to_f32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35205 {
35206     ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
35207 }
35208 #endif
35209 #if defined(MA_SUPPORT_AVX2)
35210 static MA_INLINE void ma_pcm_s32_to_f32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35211 {
35212     ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
35213 }
35214 #endif
35215 #if defined(MA_SUPPORT_NEON)
35216 static MA_INLINE void ma_pcm_s32_to_f32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35217 {
35218     ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
35219 }
35220 #endif
35221
35222 MA_API void ma_pcm_s32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35223 {
35224 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35225     ma_pcm_s32_to_f32__reference(dst, src, count, ditherMode);
35226 #else
35227     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35228         if (ma_has_avx2()) {
35229             ma_pcm_s32_to_f32__avx2(dst, src, count, ditherMode);
35230         } else
35231     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35232         if (ma_has_sse2()) {
35233             ma_pcm_s32_to_f32__sse2(dst, src, count, ditherMode);
35234         } else
35235     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35236         if (ma_has_neon()) {
35237             ma_pcm_s32_to_f32__neon(dst, src, count, ditherMode);
35238         } else
35239     #endif
35240         {
35241             ma_pcm_s32_to_f32__optimized(dst, src, count, ditherMode);
35242         }
35243 #endif
35244 }
35245
35246
35247 static MA_INLINE void ma_pcm_interleave_s32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35248 {
35249     ma_int32* dst_s32 = (ma_int32*)dst;
35250     const ma_int32** src_s32 = (const ma_int32**)src;
35251
35252     ma_uint64 iFrame;
35253     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35254         ma_uint32 iChannel;
35255         for (iChannel = 0; iChannel < channels; iChannel += 1) {
35256             dst_s32[iFrame*channels + iChannel] = src_s32[iChannel][iFrame];
35257         }
35258     }
35259 }
35260
35261 static MA_INLINE void ma_pcm_interleave_s32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35262 {
35263     ma_pcm_interleave_s32__reference(dst, src, frameCount, channels);
35264 }
35265
35266 MA_API void ma_pcm_interleave_s32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35267 {
35268 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35269     ma_pcm_interleave_s32__reference(dst, src, frameCount, channels);
35270 #else
35271     ma_pcm_interleave_s32__optimized(dst, src, frameCount, channels);
35272 #endif
35273 }
35274
35275
35276 static MA_INLINE void ma_pcm_deinterleave_s32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35277 {
35278     ma_int32** dst_s32 = (ma_int32**)dst;
35279     const ma_int32* src_s32 = (const ma_int32*)src;
35280
35281     ma_uint64 iFrame;
35282     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35283         ma_uint32 iChannel;
35284         for (iChannel = 0; iChannel < channels; iChannel += 1) {
35285             dst_s32[iChannel][iFrame] = src_s32[iFrame*channels + iChannel];
35286         }
35287     }
35288 }
35289
35290 static MA_INLINE void ma_pcm_deinterleave_s32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35291 {
35292     ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels);
35293 }
35294
35295 MA_API void ma_pcm_deinterleave_s32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
35296 {
35297 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35298     ma_pcm_deinterleave_s32__reference(dst, src, frameCount, channels);
35299 #else
35300     ma_pcm_deinterleave_s32__optimized(dst, src, frameCount, channels);
35301 #endif
35302 }
35303
35304
35305 /* f32 */
35306 static MA_INLINE void ma_pcm_f32_to_u8__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35307 {
35308     ma_uint64 i;
35309
35310     ma_uint8* dst_u8 = (ma_uint8*)dst;
35311     const float* src_f32 = (const float*)src;
35312
35313     float ditherMin = 0;
35314     float ditherMax = 0;
35315     if (ditherMode != ma_dither_mode_none) {
35316         ditherMin = 1.0f / -128;
35317         ditherMax = 1.0f /  127;
35318     }
35319
35320     for (i = 0; i < count; i += 1) {
35321         float x = src_f32[i];
35322         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
35323         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35324         x = x + 1;                                  /* -1..1 to 0..2 */
35325         x = x * 127.5f;                             /* 0..2 to 0..255 */
35326
35327         dst_u8[i] = (ma_uint8)x;
35328     }
35329 }
35330
35331 static MA_INLINE void ma_pcm_f32_to_u8__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35332 {
35333     ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode);
35334 }
35335
35336 #if defined(MA_SUPPORT_SSE2)
35337 static MA_INLINE void ma_pcm_f32_to_u8__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35338 {
35339     ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
35340 }
35341 #endif
35342 #if defined(MA_SUPPORT_AVX2)
35343 static MA_INLINE void ma_pcm_f32_to_u8__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35344 {
35345     ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
35346 }
35347 #endif
35348 #if defined(MA_SUPPORT_NEON)
35349 static MA_INLINE void ma_pcm_f32_to_u8__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35350 {
35351     ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
35352 }
35353 #endif
35354
35355 MA_API void ma_pcm_f32_to_u8(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35356 {
35357 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35358     ma_pcm_f32_to_u8__reference(dst, src, count, ditherMode);
35359 #else
35360     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35361         if (ma_has_avx2()) {
35362             ma_pcm_f32_to_u8__avx2(dst, src, count, ditherMode);
35363         } else
35364     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35365         if (ma_has_sse2()) {
35366             ma_pcm_f32_to_u8__sse2(dst, src, count, ditherMode);
35367         } else
35368     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35369         if (ma_has_neon()) {
35370             ma_pcm_f32_to_u8__neon(dst, src, count, ditherMode);
35371         } else
35372     #endif
35373         {
35374             ma_pcm_f32_to_u8__optimized(dst, src, count, ditherMode);
35375         }
35376 #endif
35377 }
35378
35379 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35380 static MA_INLINE void ma_pcm_f32_to_s16__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35381 {
35382     ma_uint64 i;
35383
35384     ma_int16* dst_s16 = (ma_int16*)dst;
35385     const float* src_f32 = (const float*)src;
35386
35387     float ditherMin = 0;
35388     float ditherMax = 0;
35389     if (ditherMode != ma_dither_mode_none) {
35390         ditherMin = 1.0f / -32768;
35391         ditherMax = 1.0f /  32767;
35392     }
35393
35394     for (i = 0; i < count; i += 1) {
35395         float x = src_f32[i];
35396         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
35397         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35398
35399 #if 0
35400         /* The accurate way. */
35401         x = x + 1;                                  /* -1..1 to 0..2 */
35402         x = x * 32767.5f;                           /* 0..2 to 0..65535 */
35403         x = x - 32768.0f;                           /* 0...65535 to -32768..32767 */
35404 #else
35405         /* The fast way. */
35406         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
35407 #endif
35408
35409         dst_s16[i] = (ma_int16)x;
35410     }
35411 }
35412 #else
35413 static MA_INLINE void ma_pcm_f32_to_s16__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35414 {
35415     ma_uint64 i;
35416     ma_uint64 i4;
35417     ma_uint64 count4;
35418
35419     ma_int16* dst_s16 = (ma_int16*)dst;
35420     const float* src_f32 = (const float*)src;
35421
35422     float ditherMin = 0;
35423     float ditherMax = 0;
35424     if (ditherMode != ma_dither_mode_none) {
35425         ditherMin = 1.0f / -32768;
35426         ditherMax = 1.0f /  32767;
35427     }
35428
35429     /* Unrolled. */
35430     i = 0;
35431     count4 = count >> 2;
35432     for (i4 = 0; i4 < count4; i4 += 1) {
35433         float d0 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
35434         float d1 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
35435         float d2 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
35436         float d3 = ma_dither_f32(ditherMode, ditherMin, ditherMax);
35437
35438         float x0 = src_f32[i+0];
35439         float x1 = src_f32[i+1];
35440         float x2 = src_f32[i+2];
35441         float x3 = src_f32[i+3];
35442
35443         x0 = x0 + d0;
35444         x1 = x1 + d1;
35445         x2 = x2 + d2;
35446         x3 = x3 + d3;
35447
35448         x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0));
35449         x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1));
35450         x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2));
35451         x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3));
35452
35453         x0 = x0 * 32767.0f;
35454         x1 = x1 * 32767.0f;
35455         x2 = x2 * 32767.0f;
35456         x3 = x3 * 32767.0f;
35457
35458         dst_s16[i+0] = (ma_int16)x0;
35459         dst_s16[i+1] = (ma_int16)x1;
35460         dst_s16[i+2] = (ma_int16)x2;
35461         dst_s16[i+3] = (ma_int16)x3;
35462
35463         i += 4;
35464     }
35465
35466     /* Leftover. */
35467     for (; i < count; i += 1) {
35468         float x = src_f32[i];
35469         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
35470         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35471         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
35472
35473         dst_s16[i] = (ma_int16)x;
35474     }
35475 }
35476
35477 #if defined(MA_SUPPORT_SSE2)
35478 static MA_INLINE void ma_pcm_f32_to_s16__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35479 {
35480     ma_uint64 i;
35481     ma_uint64 i8;
35482     ma_uint64 count8;
35483     ma_int16* dst_s16;
35484     const float* src_f32;
35485     float ditherMin;
35486     float ditherMax;
35487
35488     /* Both the input and output buffers need to be aligned to 16 bytes. */
35489     if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) {
35490         ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
35491         return;
35492     }
35493
35494     dst_s16 = (ma_int16*)dst;
35495     src_f32 = (const float*)src;
35496
35497     ditherMin = 0;
35498     ditherMax = 0;
35499     if (ditherMode != ma_dither_mode_none) {
35500         ditherMin = 1.0f / -32768;
35501         ditherMax = 1.0f /  32767;
35502     }
35503
35504     i = 0;
35505
35506     /* SSE2. SSE allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */
35507     count8 = count >> 3;
35508     for (i8 = 0; i8 < count8; i8 += 1) {
35509         __m128 d0;
35510         __m128 d1;
35511         __m128 x0;
35512         __m128 x1;
35513
35514         if (ditherMode == ma_dither_mode_none) {
35515             d0 = _mm_set1_ps(0);
35516             d1 = _mm_set1_ps(0);
35517         } else if (ditherMode == ma_dither_mode_rectangle) {
35518             d0 = _mm_set_ps(
35519                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35520                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35521                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35522                 ma_dither_f32_rectangle(ditherMin, ditherMax)
35523             );
35524             d1 = _mm_set_ps(
35525                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35526                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35527                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35528                 ma_dither_f32_rectangle(ditherMin, ditherMax)
35529             );
35530         } else {
35531             d0 = _mm_set_ps(
35532                 ma_dither_f32_triangle(ditherMin, ditherMax),
35533                 ma_dither_f32_triangle(ditherMin, ditherMax),
35534                 ma_dither_f32_triangle(ditherMin, ditherMax),
35535                 ma_dither_f32_triangle(ditherMin, ditherMax)
35536             );
35537             d1 = _mm_set_ps(
35538                 ma_dither_f32_triangle(ditherMin, ditherMax),
35539                 ma_dither_f32_triangle(ditherMin, ditherMax),
35540                 ma_dither_f32_triangle(ditherMin, ditherMax),
35541                 ma_dither_f32_triangle(ditherMin, ditherMax)
35542             );
35543         }
35544
35545         x0 = *((__m128*)(src_f32 + i) + 0);
35546         x1 = *((__m128*)(src_f32 + i) + 1);
35547
35548         x0 = _mm_add_ps(x0, d0);
35549         x1 = _mm_add_ps(x1, d1);
35550
35551         x0 = _mm_mul_ps(x0, _mm_set1_ps(32767.0f));
35552         x1 = _mm_mul_ps(x1, _mm_set1_ps(32767.0f));
35553
35554         _mm_stream_si128(((__m128i*)(dst_s16 + i)), _mm_packs_epi32(_mm_cvttps_epi32(x0), _mm_cvttps_epi32(x1)));
35555
35556         i += 8;
35557     }
35558
35559
35560     /* Leftover. */
35561     for (; i < count; i += 1) {
35562         float x = src_f32[i];
35563         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
35564         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35565         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
35566
35567         dst_s16[i] = (ma_int16)x;
35568     }
35569 }
35570 #endif  /* SSE2 */
35571
35572 #if defined(MA_SUPPORT_AVX2)
35573 static MA_INLINE void ma_pcm_f32_to_s16__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35574 {
35575     ma_uint64 i;
35576     ma_uint64 i16;
35577     ma_uint64 count16;
35578     ma_int16* dst_s16;
35579     const float* src_f32;
35580     float ditherMin;
35581     float ditherMax;
35582
35583     /* Both the input and output buffers need to be aligned to 32 bytes. */
35584     if ((((ma_uintptr)dst & 31) != 0) || (((ma_uintptr)src & 31) != 0)) {
35585         ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
35586         return;
35587     }
35588
35589     dst_s16 = (ma_int16*)dst;
35590     src_f32 = (const float*)src;
35591
35592     ditherMin = 0;
35593     ditherMax = 0;
35594     if (ditherMode != ma_dither_mode_none) {
35595         ditherMin = 1.0f / -32768;
35596         ditherMax = 1.0f /  32767;
35597     }
35598
35599     i = 0;
35600
35601     /* AVX2. AVX2 allows us to output 16 s16's at a time which means our loop is unrolled 16 times. */
35602     count16 = count >> 4;
35603     for (i16 = 0; i16 < count16; i16 += 1) {
35604         __m256 d0;
35605         __m256 d1;
35606         __m256 x0;
35607         __m256 x1;
35608         __m256i i0;
35609         __m256i i1;
35610         __m256i p0;
35611         __m256i p1;
35612         __m256i r;
35613
35614         if (ditherMode == ma_dither_mode_none) {
35615             d0 = _mm256_set1_ps(0);
35616             d1 = _mm256_set1_ps(0);
35617         } else if (ditherMode == ma_dither_mode_rectangle) {
35618             d0 = _mm256_set_ps(
35619                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35620                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35621                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35622                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35623                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35624                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35625                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35626                 ma_dither_f32_rectangle(ditherMin, ditherMax)
35627             );
35628             d1 = _mm256_set_ps(
35629                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35630                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35631                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35632                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35633                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35634                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35635                 ma_dither_f32_rectangle(ditherMin, ditherMax),
35636                 ma_dither_f32_rectangle(ditherMin, ditherMax)
35637             );
35638         } else {
35639             d0 = _mm256_set_ps(
35640                 ma_dither_f32_triangle(ditherMin, ditherMax),
35641                 ma_dither_f32_triangle(ditherMin, ditherMax),
35642                 ma_dither_f32_triangle(ditherMin, ditherMax),
35643                 ma_dither_f32_triangle(ditherMin, ditherMax),
35644                 ma_dither_f32_triangle(ditherMin, ditherMax),
35645                 ma_dither_f32_triangle(ditherMin, ditherMax),
35646                 ma_dither_f32_triangle(ditherMin, ditherMax),
35647                 ma_dither_f32_triangle(ditherMin, ditherMax)
35648             );
35649             d1 = _mm256_set_ps(
35650                 ma_dither_f32_triangle(ditherMin, ditherMax),
35651                 ma_dither_f32_triangle(ditherMin, ditherMax),
35652                 ma_dither_f32_triangle(ditherMin, ditherMax),
35653                 ma_dither_f32_triangle(ditherMin, ditherMax),
35654                 ma_dither_f32_triangle(ditherMin, ditherMax),
35655                 ma_dither_f32_triangle(ditherMin, ditherMax),
35656                 ma_dither_f32_triangle(ditherMin, ditherMax),
35657                 ma_dither_f32_triangle(ditherMin, ditherMax)
35658             );
35659         }
35660
35661         x0 = *((__m256*)(src_f32 + i) + 0);
35662         x1 = *((__m256*)(src_f32 + i) + 1);
35663
35664         x0 = _mm256_add_ps(x0, d0);
35665         x1 = _mm256_add_ps(x1, d1);
35666
35667         x0 = _mm256_mul_ps(x0, _mm256_set1_ps(32767.0f));
35668         x1 = _mm256_mul_ps(x1, _mm256_set1_ps(32767.0f));
35669
35670         /* Computing the final result is a little more complicated for AVX2 than SSE2. */
35671         i0 = _mm256_cvttps_epi32(x0);
35672         i1 = _mm256_cvttps_epi32(x1);
35673         p0 = _mm256_permute2x128_si256(i0, i1, 0 | 32);
35674         p1 = _mm256_permute2x128_si256(i0, i1, 1 | 48);
35675         r  = _mm256_packs_epi32(p0, p1);
35676
35677         _mm256_stream_si256(((__m256i*)(dst_s16 + i)), r);
35678
35679         i += 16;
35680     }
35681
35682
35683     /* Leftover. */
35684     for (; i < count; i += 1) {
35685         float x = src_f32[i];
35686         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
35687         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35688         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
35689
35690         dst_s16[i] = (ma_int16)x;
35691     }
35692 }
35693 #endif  /* AVX2 */
35694
35695 #if defined(MA_SUPPORT_NEON)
35696 static MA_INLINE void ma_pcm_f32_to_s16__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35697 {
35698     ma_uint64 i;
35699     ma_uint64 i8;
35700     ma_uint64 count8;
35701     ma_int16* dst_s16;
35702     const float* src_f32;
35703     float ditherMin;
35704     float ditherMax;
35705
35706     if (!ma_has_neon()) {
35707         return ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
35708     }
35709
35710     /* Both the input and output buffers need to be aligned to 16 bytes. */
35711     if ((((ma_uintptr)dst & 15) != 0) || (((ma_uintptr)src & 15) != 0)) {
35712         ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
35713         return;
35714     }
35715
35716     dst_s16 = (ma_int16*)dst;
35717     src_f32 = (const float*)src;
35718
35719     ditherMin = 0;
35720     ditherMax = 0;
35721     if (ditherMode != ma_dither_mode_none) {
35722         ditherMin = 1.0f / -32768;
35723         ditherMax = 1.0f /  32767;
35724     }
35725
35726     i = 0;
35727
35728     /* NEON. NEON allows us to output 8 s16's at a time which means our loop is unrolled 8 times. */
35729     count8 = count >> 3;
35730     for (i8 = 0; i8 < count8; i8 += 1) {
35731         float32x4_t d0;
35732         float32x4_t d1;
35733         float32x4_t x0;
35734         float32x4_t x1;
35735         int32x4_t i0;
35736         int32x4_t i1;
35737
35738         if (ditherMode == ma_dither_mode_none) {
35739             d0 = vmovq_n_f32(0);
35740             d1 = vmovq_n_f32(0);
35741         } else if (ditherMode == ma_dither_mode_rectangle) {
35742             float d0v[4];
35743             d0v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35744             d0v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35745             d0v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35746             d0v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35747             d0 = vld1q_f32(d0v);
35748
35749             float d1v[4];
35750             d1v[0] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35751             d1v[1] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35752             d1v[2] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35753             d1v[3] = ma_dither_f32_rectangle(ditherMin, ditherMax);
35754             d1 = vld1q_f32(d1v);
35755         } else {
35756             float d0v[4];
35757             d0v[0] = ma_dither_f32_triangle(ditherMin, ditherMax);
35758             d0v[1] = ma_dither_f32_triangle(ditherMin, ditherMax);
35759             d0v[2] = ma_dither_f32_triangle(ditherMin, ditherMax);
35760             d0v[3] = ma_dither_f32_triangle(ditherMin, ditherMax);
35761             d0 = vld1q_f32(d0v);
35762
35763             float d1v[4];
35764             d1v[0] = ma_dither_f32_triangle(ditherMin, ditherMax);
35765             d1v[1] = ma_dither_f32_triangle(ditherMin, ditherMax);
35766             d1v[2] = ma_dither_f32_triangle(ditherMin, ditherMax);
35767             d1v[3] = ma_dither_f32_triangle(ditherMin, ditherMax);
35768             d1 = vld1q_f32(d1v);
35769         }
35770
35771         x0 = *((float32x4_t*)(src_f32 + i) + 0);
35772         x1 = *((float32x4_t*)(src_f32 + i) + 1);
35773
35774         x0 = vaddq_f32(x0, d0);
35775         x1 = vaddq_f32(x1, d1);
35776
35777         x0 = vmulq_n_f32(x0, 32767.0f);
35778         x1 = vmulq_n_f32(x1, 32767.0f);
35779
35780         i0 = vcvtq_s32_f32(x0);
35781         i1 = vcvtq_s32_f32(x1);
35782         *((int16x8_t*)(dst_s16 + i)) = vcombine_s16(vqmovn_s32(i0), vqmovn_s32(i1));
35783
35784         i += 8;
35785     }
35786
35787
35788     /* Leftover. */
35789     for (; i < count; i += 1) {
35790         float x = src_f32[i];
35791         x = x + ma_dither_f32(ditherMode, ditherMin, ditherMax);
35792         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35793         x = x * 32767.0f;                           /* -1..1 to -32767..32767 */
35794
35795         dst_s16[i] = (ma_int16)x;
35796     }
35797 }
35798 #endif  /* Neon */
35799 #endif  /* MA_USE_REFERENCE_CONVERSION_APIS */
35800
35801 MA_API void ma_pcm_f32_to_s16(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35802 {
35803 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35804     ma_pcm_f32_to_s16__reference(dst, src, count, ditherMode);
35805 #else
35806     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35807         if (ma_has_avx2()) {
35808             ma_pcm_f32_to_s16__avx2(dst, src, count, ditherMode);
35809         } else
35810     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35811         if (ma_has_sse2()) {
35812             ma_pcm_f32_to_s16__sse2(dst, src, count, ditherMode);
35813         } else
35814     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35815         if (ma_has_neon()) {
35816             ma_pcm_f32_to_s16__neon(dst, src, count, ditherMode);
35817         } else
35818     #endif
35819         {
35820             ma_pcm_f32_to_s16__optimized(dst, src, count, ditherMode);
35821         }
35822 #endif
35823 }
35824
35825
35826 static MA_INLINE void ma_pcm_f32_to_s24__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35827 {
35828     ma_uint8* dst_s24 = (ma_uint8*)dst;
35829     const float* src_f32 = (const float*)src;
35830
35831     ma_uint64 i;
35832     for (i = 0; i < count; i += 1) {
35833         ma_int32 r;
35834         float x = src_f32[i];
35835         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35836
35837 #if 0
35838         /* The accurate way. */
35839         x = x + 1;                                  /* -1..1 to 0..2 */
35840         x = x * 8388607.5f;                         /* 0..2 to 0..16777215 */
35841         x = x - 8388608.0f;                         /* 0..16777215 to -8388608..8388607 */
35842 #else
35843         /* The fast way. */
35844         x = x * 8388607.0f;                         /* -1..1 to -8388607..8388607 */
35845 #endif
35846
35847         r = (ma_int32)x;
35848         dst_s24[(i*3)+0] = (ma_uint8)((r & 0x0000FF) >>  0);
35849         dst_s24[(i*3)+1] = (ma_uint8)((r & 0x00FF00) >>  8);
35850         dst_s24[(i*3)+2] = (ma_uint8)((r & 0xFF0000) >> 16);
35851     }
35852
35853     (void)ditherMode;   /* No dithering for f32 -> s24. */
35854 }
35855
35856 static MA_INLINE void ma_pcm_f32_to_s24__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35857 {
35858     ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode);
35859 }
35860
35861 #if defined(MA_SUPPORT_SSE2)
35862 static MA_INLINE void ma_pcm_f32_to_s24__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35863 {
35864     ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
35865 }
35866 #endif
35867 #if defined(MA_SUPPORT_AVX2)
35868 static MA_INLINE void ma_pcm_f32_to_s24__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35869 {
35870     ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
35871 }
35872 #endif
35873 #if defined(MA_SUPPORT_NEON)
35874 static MA_INLINE void ma_pcm_f32_to_s24__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35875 {
35876     ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
35877 }
35878 #endif
35879
35880 MA_API void ma_pcm_f32_to_s24(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35881 {
35882 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35883     ma_pcm_f32_to_s24__reference(dst, src, count, ditherMode);
35884 #else
35885     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35886         if (ma_has_avx2()) {
35887             ma_pcm_f32_to_s24__avx2(dst, src, count, ditherMode);
35888         } else
35889     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35890         if (ma_has_sse2()) {
35891             ma_pcm_f32_to_s24__sse2(dst, src, count, ditherMode);
35892         } else
35893     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35894         if (ma_has_neon()) {
35895             ma_pcm_f32_to_s24__neon(dst, src, count, ditherMode);
35896         } else
35897     #endif
35898         {
35899             ma_pcm_f32_to_s24__optimized(dst, src, count, ditherMode);
35900         }
35901 #endif
35902 }
35903
35904
35905 static MA_INLINE void ma_pcm_f32_to_s32__reference(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35906 {
35907     ma_int32* dst_s32 = (ma_int32*)dst;
35908     const float* src_f32 = (const float*)src;
35909
35910     ma_uint32 i;
35911     for (i = 0; i < count; i += 1) {
35912         double x = src_f32[i];
35913         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));    /* clip */
35914
35915 #if 0
35916         /* The accurate way. */
35917         x = x + 1;                                  /* -1..1 to 0..2 */
35918         x = x * 2147483647.5;                       /* 0..2 to 0..4294967295 */
35919         x = x - 2147483648.0;                       /* 0...4294967295 to -2147483648..2147483647 */
35920 #else
35921         /* The fast way. */
35922         x = x * 2147483647.0;                       /* -1..1 to -2147483647..2147483647 */
35923 #endif
35924
35925         dst_s32[i] = (ma_int32)x;
35926     }
35927
35928     (void)ditherMode;   /* No dithering for f32 -> s32. */
35929 }
35930
35931 static MA_INLINE void ma_pcm_f32_to_s32__optimized(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35932 {
35933     ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode);
35934 }
35935
35936 #if defined(MA_SUPPORT_SSE2)
35937 static MA_INLINE void ma_pcm_f32_to_s32__sse2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35938 {
35939     ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
35940 }
35941 #endif
35942 #if defined(MA_SUPPORT_AVX2)
35943 static MA_INLINE void ma_pcm_f32_to_s32__avx2(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35944 {
35945     ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
35946 }
35947 #endif
35948 #if defined(MA_SUPPORT_NEON)
35949 static MA_INLINE void ma_pcm_f32_to_s32__neon(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35950 {
35951     ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
35952 }
35953 #endif
35954
35955 MA_API void ma_pcm_f32_to_s32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35956 {
35957 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
35958     ma_pcm_f32_to_s32__reference(dst, src, count, ditherMode);
35959 #else
35960     #  if MA_PREFERRED_SIMD == MA_SIMD_AVX2
35961         if (ma_has_avx2()) {
35962             ma_pcm_f32_to_s32__avx2(dst, src, count, ditherMode);
35963         } else
35964     #elif MA_PREFERRED_SIMD == MA_SIMD_SSE2
35965         if (ma_has_sse2()) {
35966             ma_pcm_f32_to_s32__sse2(dst, src, count, ditherMode);
35967         } else
35968     #elif MA_PREFERRED_SIMD == MA_SIMD_NEON
35969         if (ma_has_neon()) {
35970             ma_pcm_f32_to_s32__neon(dst, src, count, ditherMode);
35971         } else
35972     #endif
35973         {
35974             ma_pcm_f32_to_s32__optimized(dst, src, count, ditherMode);
35975         }
35976 #endif
35977 }
35978
35979
35980 MA_API void ma_pcm_f32_to_f32(void* dst, const void* src, ma_uint64 count, ma_dither_mode ditherMode)
35981 {
35982     (void)ditherMode;
35983
35984     ma_copy_memory_64(dst, src, count * sizeof(float));
35985 }
35986
35987
35988 static void ma_pcm_interleave_f32__reference(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
35989 {
35990     float* dst_f32 = (float*)dst;
35991     const float** src_f32 = (const float**)src;
35992
35993     ma_uint64 iFrame;
35994     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
35995         ma_uint32 iChannel;
35996         for (iChannel = 0; iChannel < channels; iChannel += 1) {
35997             dst_f32[iFrame*channels + iChannel] = src_f32[iChannel][iFrame];
35998         }
35999     }
36000 }
36001
36002 static void ma_pcm_interleave_f32__optimized(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36003 {
36004     ma_pcm_interleave_f32__reference(dst, src, frameCount, channels);
36005 }
36006
36007 MA_API void ma_pcm_interleave_f32(void* dst, const void** src, ma_uint64 frameCount, ma_uint32 channels)
36008 {
36009 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36010     ma_pcm_interleave_f32__reference(dst, src, frameCount, channels);
36011 #else
36012     ma_pcm_interleave_f32__optimized(dst, src, frameCount, channels);
36013 #endif
36014 }
36015
36016
36017 static void ma_pcm_deinterleave_f32__reference(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36018 {
36019     float** dst_f32 = (float**)dst;
36020     const float* src_f32 = (const float*)src;
36021
36022     ma_uint64 iFrame;
36023     for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
36024         ma_uint32 iChannel;
36025         for (iChannel = 0; iChannel < channels; iChannel += 1) {
36026             dst_f32[iChannel][iFrame] = src_f32[iFrame*channels + iChannel];
36027         }
36028     }
36029 }
36030
36031 static void ma_pcm_deinterleave_f32__optimized(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36032 {
36033     ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels);
36034 }
36035
36036 MA_API void ma_pcm_deinterleave_f32(void** dst, const void* src, ma_uint64 frameCount, ma_uint32 channels)
36037 {
36038 #ifdef MA_USE_REFERENCE_CONVERSION_APIS
36039     ma_pcm_deinterleave_f32__reference(dst, src, frameCount, channels);
36040 #else
36041     ma_pcm_deinterleave_f32__optimized(dst, src, frameCount, channels);
36042 #endif
36043 }
36044
36045
36046 MA_API void ma_pcm_convert(void* pOut, ma_format formatOut, const void* pIn, ma_format formatIn, ma_uint64 sampleCount, ma_dither_mode ditherMode)
36047 {
36048     if (formatOut == formatIn) {
36049         ma_copy_memory_64(pOut, pIn, sampleCount * ma_get_bytes_per_sample(formatOut));
36050         return;
36051     }
36052
36053     switch (formatIn)
36054     {
36055         case ma_format_u8:
36056         {
36057             switch (formatOut)
36058             {
36059                 case ma_format_s16: ma_pcm_u8_to_s16(pOut, pIn, sampleCount, ditherMode); return;
36060                 case ma_format_s24: ma_pcm_u8_to_s24(pOut, pIn, sampleCount, ditherMode); return;
36061                 case ma_format_s32: ma_pcm_u8_to_s32(pOut, pIn, sampleCount, ditherMode); return;
36062                 case ma_format_f32: ma_pcm_u8_to_f32(pOut, pIn, sampleCount, ditherMode); return;
36063                 default: break;
36064             }
36065         } break;
36066
36067         case ma_format_s16:
36068         {
36069             switch (formatOut)
36070             {
36071                 case ma_format_u8:  ma_pcm_s16_to_u8( pOut, pIn, sampleCount, ditherMode); return;
36072                 case ma_format_s24: ma_pcm_s16_to_s24(pOut, pIn, sampleCount, ditherMode); return;
36073                 case ma_format_s32: ma_pcm_s16_to_s32(pOut, pIn, sampleCount, ditherMode); return;
36074                 case ma_format_f32: ma_pcm_s16_to_f32(pOut, pIn, sampleCount, ditherMode); return;
36075                 default: break;
36076             }
36077         } break;
36078
36079         case ma_format_s24:
36080         {
36081             switch (formatOut)
36082             {
36083                 case ma_format_u8:  ma_pcm_s24_to_u8( pOut, pIn, sampleCount, ditherMode); return;
36084                 case ma_format_s16: ma_pcm_s24_to_s16(pOut, pIn, sampleCount, ditherMode); return;
36085                 case ma_format_s32: ma_pcm_s24_to_s32(pOut, pIn, sampleCount, ditherMode); return;
36086                 case ma_format_f32: ma_pcm_s24_to_f32(pOut, pIn, sampleCount, ditherMode); return;
36087                 default: break;
36088             }
36089         } break;
36090
36091         case ma_format_s32:
36092         {
36093             switch (formatOut)
36094             {
36095                 case ma_format_u8:  ma_pcm_s32_to_u8( pOut, pIn, sampleCount, ditherMode); return;
36096                 case ma_format_s16: ma_pcm_s32_to_s16(pOut, pIn, sampleCount, ditherMode); return;
36097                 case ma_format_s24: ma_pcm_s32_to_s24(pOut, pIn, sampleCount, ditherMode); return;
36098                 case ma_format_f32: ma_pcm_s32_to_f32(pOut, pIn, sampleCount, ditherMode); return;
36099                 default: break;
36100             }
36101         } break;
36102
36103         case ma_format_f32:
36104         {
36105             switch (formatOut)
36106             {
36107                 case ma_format_u8:  ma_pcm_f32_to_u8( pOut, pIn, sampleCount, ditherMode); return;
36108                 case ma_format_s16: ma_pcm_f32_to_s16(pOut, pIn, sampleCount, ditherMode); return;
36109                 case ma_format_s24: ma_pcm_f32_to_s24(pOut, pIn, sampleCount, ditherMode); return;
36110                 case ma_format_s32: ma_pcm_f32_to_s32(pOut, pIn, sampleCount, ditherMode); return;
36111                 default: break;
36112             }
36113         } break;
36114
36115         default: break;
36116     }
36117 }
36118
36119 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)
36120 {
36121     ma_pcm_convert(pOut, formatOut, pIn, formatIn, frameCount * channels, ditherMode);
36122 }
36123
36124 MA_API void ma_deinterleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void* pInterleavedPCMFrames, void** ppDeinterleavedPCMFrames)
36125 {
36126     if (pInterleavedPCMFrames == NULL || ppDeinterleavedPCMFrames == NULL) {
36127         return; /* Invalid args. */
36128     }
36129
36130     /* For efficiency we do this per format. */
36131     switch (format) {
36132         case ma_format_s16:
36133         {
36134             const ma_int16* pSrcS16 = (const ma_int16*)pInterleavedPCMFrames;
36135             ma_uint64 iPCMFrame;
36136             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
36137                 ma_uint32 iChannel;
36138                 for (iChannel = 0; iChannel < channels; ++iChannel) {
36139                     ma_int16* pDstS16 = (ma_int16*)ppDeinterleavedPCMFrames[iChannel];
36140                     pDstS16[iPCMFrame] = pSrcS16[iPCMFrame*channels+iChannel];
36141                 }
36142             }
36143         } break;
36144
36145         case ma_format_f32:
36146         {
36147             const float* pSrcF32 = (const float*)pInterleavedPCMFrames;
36148             ma_uint64 iPCMFrame;
36149             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
36150                 ma_uint32 iChannel;
36151                 for (iChannel = 0; iChannel < channels; ++iChannel) {
36152                     float* pDstF32 = (float*)ppDeinterleavedPCMFrames[iChannel];
36153                     pDstF32[iPCMFrame] = pSrcF32[iPCMFrame*channels+iChannel];
36154                 }
36155             }
36156         } break;
36157
36158         default:
36159         {
36160             ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format);
36161             ma_uint64 iPCMFrame;
36162             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
36163                 ma_uint32 iChannel;
36164                 for (iChannel = 0; iChannel < channels; ++iChannel) {
36165                           void* pDst = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes);
36166                     const void* pSrc = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes);
36167                     memcpy(pDst, pSrc, sampleSizeInBytes);
36168                 }
36169             }
36170         } break;
36171     }
36172 }
36173
36174 MA_API void ma_interleave_pcm_frames(ma_format format, ma_uint32 channels, ma_uint64 frameCount, const void** ppDeinterleavedPCMFrames, void* pInterleavedPCMFrames)
36175 {
36176     switch (format)
36177     {
36178         case ma_format_s16:
36179         {
36180             ma_int16* pDstS16 = (ma_int16*)pInterleavedPCMFrames;
36181             ma_uint64 iPCMFrame;
36182             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
36183                 ma_uint32 iChannel;
36184                 for (iChannel = 0; iChannel < channels; ++iChannel) {
36185                     const ma_int16* pSrcS16 = (const ma_int16*)ppDeinterleavedPCMFrames[iChannel];
36186                     pDstS16[iPCMFrame*channels+iChannel] = pSrcS16[iPCMFrame];
36187                 }
36188             }
36189         } break;
36190
36191         case ma_format_f32:
36192         {
36193             float* pDstF32 = (float*)pInterleavedPCMFrames;
36194             ma_uint64 iPCMFrame;
36195             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
36196                 ma_uint32 iChannel;
36197                 for (iChannel = 0; iChannel < channels; ++iChannel) {
36198                     const float* pSrcF32 = (const float*)ppDeinterleavedPCMFrames[iChannel];
36199                     pDstF32[iPCMFrame*channels+iChannel] = pSrcF32[iPCMFrame];
36200                 }
36201             }
36202         } break;
36203
36204         default:
36205         {
36206             ma_uint32 sampleSizeInBytes = ma_get_bytes_per_sample(format);
36207             ma_uint64 iPCMFrame;
36208             for (iPCMFrame = 0; iPCMFrame < frameCount; ++iPCMFrame) {
36209                 ma_uint32 iChannel;
36210                 for (iChannel = 0; iChannel < channels; ++iChannel) {
36211                           void* pDst = ma_offset_ptr(pInterleavedPCMFrames, (iPCMFrame*channels+iChannel)*sampleSizeInBytes);
36212                     const void* pSrc = ma_offset_ptr(ppDeinterleavedPCMFrames[iChannel], iPCMFrame*sampleSizeInBytes);
36213                     memcpy(pDst, pSrc, sampleSizeInBytes);
36214                 }
36215             }
36216         } break;
36217     }
36218 }
36219
36220
36221 /**************************************************************************************************************************************************************
36222
36223 Biquad Filter
36224
36225 **************************************************************************************************************************************************************/
36226 #ifndef MA_BIQUAD_FIXED_POINT_SHIFT
36227 #define MA_BIQUAD_FIXED_POINT_SHIFT 14
36228 #endif
36229
36230 static ma_int32 ma_biquad_float_to_fp(double x)
36231 {
36232     return (ma_int32)(x * (1 << MA_BIQUAD_FIXED_POINT_SHIFT));
36233 }
36234
36235 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)
36236 {
36237     ma_biquad_config config;
36238
36239     MA_ZERO_OBJECT(&config);
36240     config.format = format;
36241     config.channels = channels;
36242     config.b0 = b0;
36243     config.b1 = b1;
36244     config.b2 = b2;
36245     config.a0 = a0;
36246     config.a1 = a1;
36247     config.a2 = a2;
36248
36249     return config;
36250 }
36251
36252 MA_API ma_result ma_biquad_init(const ma_biquad_config* pConfig, ma_biquad* pBQ)
36253 {
36254     if (pBQ == NULL) {
36255         return MA_INVALID_ARGS;
36256     }
36257
36258     MA_ZERO_OBJECT(pBQ);
36259
36260     if (pConfig == NULL) {
36261         return MA_INVALID_ARGS;
36262     }
36263
36264     if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
36265         return MA_INVALID_ARGS;
36266     }
36267
36268     return ma_biquad_reinit(pConfig, pBQ);
36269 }
36270
36271 MA_API ma_result ma_biquad_reinit(const ma_biquad_config* pConfig, ma_biquad* pBQ)
36272 {
36273     if (pBQ == NULL || pConfig == NULL) {
36274         return MA_INVALID_ARGS;
36275     }
36276
36277     if (pConfig->a0 == 0) {
36278         return MA_INVALID_ARGS; /* Division by zero. */
36279     }
36280
36281     /* Only supporting f32 and s16. */
36282     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
36283         return MA_INVALID_ARGS;
36284     }
36285
36286     /* The format cannot be changed after initialization. */
36287     if (pBQ->format != ma_format_unknown && pBQ->format != pConfig->format) {
36288         return MA_INVALID_OPERATION;
36289     }
36290
36291     /* The channel count cannot be changed after initialization. */
36292     if (pBQ->channels != 0 && pBQ->channels != pConfig->channels) {
36293         return MA_INVALID_OPERATION;
36294     }
36295
36296
36297     pBQ->format   = pConfig->format;
36298     pBQ->channels = pConfig->channels;
36299
36300     /* Normalize. */
36301     if (pConfig->format == ma_format_f32) {
36302         pBQ->b0.f32 = (float)(pConfig->b0 / pConfig->a0);
36303         pBQ->b1.f32 = (float)(pConfig->b1 / pConfig->a0);
36304         pBQ->b2.f32 = (float)(pConfig->b2 / pConfig->a0);
36305         pBQ->a1.f32 = (float)(pConfig->a1 / pConfig->a0);
36306         pBQ->a2.f32 = (float)(pConfig->a2 / pConfig->a0);
36307     } else {
36308         pBQ->b0.s32 = ma_biquad_float_to_fp(pConfig->b0 / pConfig->a0);
36309         pBQ->b1.s32 = ma_biquad_float_to_fp(pConfig->b1 / pConfig->a0);
36310         pBQ->b2.s32 = ma_biquad_float_to_fp(pConfig->b2 / pConfig->a0);
36311         pBQ->a1.s32 = ma_biquad_float_to_fp(pConfig->a1 / pConfig->a0);
36312         pBQ->a2.s32 = ma_biquad_float_to_fp(pConfig->a2 / pConfig->a0);
36313     }
36314
36315     return MA_SUCCESS;
36316 }
36317
36318 static MA_INLINE void ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(ma_biquad* pBQ, float* pY, const float* pX)
36319 {
36320     ma_uint32 c;
36321     const ma_uint32 channels = pBQ->channels;
36322     const float b0 = pBQ->b0.f32;
36323     const float b1 = pBQ->b1.f32;
36324     const float b2 = pBQ->b2.f32;
36325     const float a1 = pBQ->a1.f32;
36326     const float a2 = pBQ->a2.f32;
36327
36328     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
36329     for (c = 0; c < channels; c += 1) {
36330         float r1 = pBQ->r1[c].f32;
36331         float r2 = pBQ->r2[c].f32;
36332         float x  = pX[c];
36333         float y;
36334
36335         y  = b0*x        + r1;
36336         r1 = b1*x - a1*y + r2;
36337         r2 = b2*x - a2*y;
36338
36339         pY[c]          = y;
36340         pBQ->r1[c].f32 = r1;
36341         pBQ->r2[c].f32 = r2;
36342     }
36343 }
36344
36345 static MA_INLINE void ma_biquad_process_pcm_frame_f32(ma_biquad* pBQ, float* pY, const float* pX)
36346 {
36347     ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX);
36348 }
36349
36350 static MA_INLINE void ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX)
36351 {
36352     ma_uint32 c;
36353     const ma_uint32 channels = pBQ->channels;
36354     const ma_int32 b0 = pBQ->b0.s32;
36355     const ma_int32 b1 = pBQ->b1.s32;
36356     const ma_int32 b2 = pBQ->b2.s32;
36357     const ma_int32 a1 = pBQ->a1.s32;
36358     const ma_int32 a2 = pBQ->a2.s32;
36359
36360     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
36361     for (c = 0; c < channels; c += 1) {
36362         ma_int32 r1 = pBQ->r1[c].s32;
36363         ma_int32 r2 = pBQ->r2[c].s32;
36364         ma_int32 x  = pX[c];
36365         ma_int32 y;
36366
36367         y  = (b0*x        + r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
36368         r1 = (b1*x - a1*y + r2);
36369         r2 = (b2*x - a2*y);
36370
36371         pY[c]          = (ma_int16)ma_clamp(y, -32768, 32767);
36372         pBQ->r1[c].s32 = r1;
36373         pBQ->r2[c].s32 = r2;
36374     }
36375 }
36376
36377 static MA_INLINE void ma_biquad_process_pcm_frame_s16(ma_biquad* pBQ, ma_int16* pY, const ma_int16* pX)
36378 {
36379     ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX);
36380 }
36381
36382 MA_API ma_result ma_biquad_process_pcm_frames(ma_biquad* pBQ, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
36383 {
36384     ma_uint32 n;
36385
36386     if (pBQ == NULL || pFramesOut == NULL || pFramesIn == NULL) {
36387         return MA_INVALID_ARGS;
36388     }
36389
36390     /* 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. */
36391
36392     if (pBQ->format == ma_format_f32) {
36393         /* */ float* pY = (      float*)pFramesOut;
36394         const float* pX = (const float*)pFramesIn;
36395
36396         for (n = 0; n < frameCount; n += 1) {
36397             ma_biquad_process_pcm_frame_f32__direct_form_2_transposed(pBQ, pY, pX);
36398             pY += pBQ->channels;
36399             pX += pBQ->channels;
36400         }
36401     } else if (pBQ->format == ma_format_s16) {
36402         /* */ ma_int16* pY = (      ma_int16*)pFramesOut;
36403         const ma_int16* pX = (const ma_int16*)pFramesIn;
36404
36405         for (n = 0; n < frameCount; n += 1) {
36406             ma_biquad_process_pcm_frame_s16__direct_form_2_transposed(pBQ, pY, pX);
36407             pY += pBQ->channels;
36408             pX += pBQ->channels;
36409         }
36410     } else {
36411         MA_ASSERT(MA_FALSE);
36412         return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
36413     }
36414
36415     return MA_SUCCESS;
36416 }
36417
36418 MA_API ma_uint32 ma_biquad_get_latency(const ma_biquad* pBQ)
36419 {
36420     if (pBQ == NULL) {
36421         return 0;
36422     }
36423
36424     return 2;
36425 }
36426
36427
36428 /**************************************************************************************************************************************************************
36429
36430 Low-Pass Filter
36431
36432 **************************************************************************************************************************************************************/
36433 MA_API ma_lpf1_config ma_lpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
36434 {
36435     ma_lpf1_config config;
36436
36437     MA_ZERO_OBJECT(&config);
36438     config.format = format;
36439     config.channels = channels;
36440     config.sampleRate = sampleRate;
36441     config.cutoffFrequency = cutoffFrequency;
36442     config.q = 0.5;
36443
36444     return config;
36445 }
36446
36447 MA_API ma_lpf2_config ma_lpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
36448 {
36449     ma_lpf2_config config;
36450
36451     MA_ZERO_OBJECT(&config);
36452     config.format = format;
36453     config.channels = channels;
36454     config.sampleRate = sampleRate;
36455     config.cutoffFrequency = cutoffFrequency;
36456     config.q = q;
36457
36458     /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
36459     if (config.q == 0) {
36460         config.q = 0.707107;
36461     }
36462
36463     return config;
36464 }
36465
36466
36467 MA_API ma_result ma_lpf1_init(const ma_lpf1_config* pConfig, ma_lpf1* pLPF)
36468 {
36469     if (pLPF == NULL) {
36470         return MA_INVALID_ARGS;
36471     }
36472
36473     MA_ZERO_OBJECT(pLPF);
36474
36475     if (pConfig == NULL) {
36476         return MA_INVALID_ARGS;
36477     }
36478
36479     if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
36480         return MA_INVALID_ARGS;
36481     }
36482
36483     return ma_lpf1_reinit(pConfig, pLPF);
36484 }
36485
36486 MA_API ma_result ma_lpf1_reinit(const ma_lpf1_config* pConfig, ma_lpf1* pLPF)
36487 {
36488     double a;
36489
36490     if (pLPF == NULL || pConfig == NULL) {
36491         return MA_INVALID_ARGS;
36492     }
36493
36494     /* Only supporting f32 and s16. */
36495     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
36496         return MA_INVALID_ARGS;
36497     }
36498
36499     /* The format cannot be changed after initialization. */
36500     if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) {
36501         return MA_INVALID_OPERATION;
36502     }
36503
36504     /* The channel count cannot be changed after initialization. */
36505     if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) {
36506         return MA_INVALID_OPERATION;
36507     }
36508
36509     pLPF->format   = pConfig->format;
36510     pLPF->channels = pConfig->channels;
36511
36512     a = ma_exp(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate);
36513     if (pConfig->format == ma_format_f32) {
36514         pLPF->a.f32 = (float)a;
36515     } else {
36516         pLPF->a.s32 = ma_biquad_float_to_fp(a);
36517     }
36518
36519     return MA_SUCCESS;
36520 }
36521
36522 static MA_INLINE void ma_lpf1_process_pcm_frame_f32(ma_lpf1* pLPF, float* pY, const float* pX)
36523 {
36524     ma_uint32 c;
36525     const ma_uint32 channels = pLPF->channels;
36526     const float a = pLPF->a.f32;
36527     const float b = 1 - a;
36528
36529     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
36530     for (c = 0; c < channels; c += 1) {
36531         float r1 = pLPF->r1[c].f32;
36532         float x  = pX[c];
36533         float y;
36534
36535         y = b*x + a*r1;
36536
36537         pY[c]           = y;
36538         pLPF->r1[c].f32 = y;
36539     }
36540 }
36541
36542 static MA_INLINE void ma_lpf1_process_pcm_frame_s16(ma_lpf1* pLPF, ma_int16* pY, const ma_int16* pX)
36543 {
36544     ma_uint32 c;
36545     const ma_uint32 channels = pLPF->channels;
36546     const ma_int32 a = pLPF->a.s32;
36547     const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a);
36548
36549     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
36550     for (c = 0; c < channels; c += 1) {
36551         ma_int32 r1 = pLPF->r1[c].s32;
36552         ma_int32 x  = pX[c];
36553         ma_int32 y;
36554
36555         y = (b*x + a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
36556
36557         pY[c]           = (ma_int16)y;
36558         pLPF->r1[c].s32 = (ma_int32)y;
36559     }
36560 }
36561
36562 MA_API ma_result ma_lpf1_process_pcm_frames(ma_lpf1* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
36563 {
36564     ma_uint32 n;
36565
36566     if (pLPF == NULL || pFramesOut == NULL || pFramesIn == NULL) {
36567         return MA_INVALID_ARGS;
36568     }
36569
36570     /* 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. */
36571
36572     if (pLPF->format == ma_format_f32) {
36573         /* */ float* pY = (      float*)pFramesOut;
36574         const float* pX = (const float*)pFramesIn;
36575
36576         for (n = 0; n < frameCount; n += 1) {
36577             ma_lpf1_process_pcm_frame_f32(pLPF, pY, pX);
36578             pY += pLPF->channels;
36579             pX += pLPF->channels;
36580         }
36581     } else if (pLPF->format == ma_format_s16) {
36582         /* */ ma_int16* pY = (      ma_int16*)pFramesOut;
36583         const ma_int16* pX = (const ma_int16*)pFramesIn;
36584
36585         for (n = 0; n < frameCount; n += 1) {
36586             ma_lpf1_process_pcm_frame_s16(pLPF, pY, pX);
36587             pY += pLPF->channels;
36588             pX += pLPF->channels;
36589         }
36590     } else {
36591         MA_ASSERT(MA_FALSE);
36592         return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
36593     }
36594
36595     return MA_SUCCESS;
36596 }
36597
36598 MA_API ma_uint32 ma_lpf1_get_latency(const ma_lpf1* pLPF)
36599 {
36600     if (pLPF == NULL) {
36601         return 0;
36602     }
36603
36604     return 1;
36605 }
36606
36607
36608 static MA_INLINE ma_biquad_config ma_lpf2__get_biquad_config(const ma_lpf2_config* pConfig)
36609 {
36610     ma_biquad_config bqConfig;
36611     double q;
36612     double w;
36613     double s;
36614     double c;
36615     double a;
36616
36617     MA_ASSERT(pConfig != NULL);
36618
36619     q = pConfig->q;
36620     w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
36621     s = ma_sin(w);
36622     c = ma_cos(w);
36623     a = s / (2*q);
36624
36625     bqConfig.b0 = (1 - c) / 2;
36626     bqConfig.b1 =  1 - c;
36627     bqConfig.b2 = (1 - c) / 2;
36628     bqConfig.a0 =  1 + a;
36629     bqConfig.a1 = -2 * c;
36630     bqConfig.a2 =  1 - a;
36631
36632     bqConfig.format   = pConfig->format;
36633     bqConfig.channels = pConfig->channels;
36634
36635     return bqConfig;
36636 }
36637
36638 MA_API ma_result ma_lpf2_init(const ma_lpf2_config* pConfig, ma_lpf2* pLPF)
36639 {
36640     ma_result result;
36641     ma_biquad_config bqConfig;
36642
36643     if (pLPF == NULL) {
36644         return MA_INVALID_ARGS;
36645     }
36646
36647     MA_ZERO_OBJECT(pLPF);
36648
36649     if (pConfig == NULL) {
36650         return MA_INVALID_ARGS;
36651     }
36652
36653     bqConfig = ma_lpf2__get_biquad_config(pConfig);
36654     result = ma_biquad_init(&bqConfig, &pLPF->bq);
36655     if (result != MA_SUCCESS) {
36656         return result;
36657     }
36658
36659     return MA_SUCCESS;
36660 }
36661
36662 MA_API ma_result ma_lpf2_reinit(const ma_lpf2_config* pConfig, ma_lpf2* pLPF)
36663 {
36664     ma_result result;
36665     ma_biquad_config bqConfig;
36666
36667     if (pLPF == NULL || pConfig == NULL) {
36668         return MA_INVALID_ARGS;
36669     }
36670
36671     bqConfig = ma_lpf2__get_biquad_config(pConfig);
36672     result = ma_biquad_reinit(&bqConfig, &pLPF->bq);
36673     if (result != MA_SUCCESS) {
36674         return result;
36675     }
36676
36677     return MA_SUCCESS;
36678 }
36679
36680 static MA_INLINE void ma_lpf2_process_pcm_frame_s16(ma_lpf2* pLPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
36681 {
36682     ma_biquad_process_pcm_frame_s16(&pLPF->bq, pFrameOut, pFrameIn);
36683 }
36684
36685 static MA_INLINE void ma_lpf2_process_pcm_frame_f32(ma_lpf2* pLPF, float* pFrameOut, const float* pFrameIn)
36686 {
36687     ma_biquad_process_pcm_frame_f32(&pLPF->bq, pFrameOut, pFrameIn);
36688 }
36689
36690 MA_API ma_result ma_lpf2_process_pcm_frames(ma_lpf2* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
36691 {
36692     if (pLPF == NULL) {
36693         return MA_INVALID_ARGS;
36694     }
36695
36696     return ma_biquad_process_pcm_frames(&pLPF->bq, pFramesOut, pFramesIn, frameCount);
36697 }
36698
36699 MA_API ma_uint32 ma_lpf2_get_latency(const ma_lpf2* pLPF)
36700 {
36701     if (pLPF == NULL) {
36702         return 0;
36703     }
36704
36705     return ma_biquad_get_latency(&pLPF->bq);
36706 }
36707
36708
36709 MA_API ma_lpf_config ma_lpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
36710 {
36711     ma_lpf_config config;
36712
36713     MA_ZERO_OBJECT(&config);
36714     config.format          = format;
36715     config.channels        = channels;
36716     config.sampleRate      = sampleRate;
36717     config.cutoffFrequency = cutoffFrequency;
36718     config.order           = ma_min(order, MA_MAX_FILTER_ORDER);
36719
36720     return config;
36721 }
36722
36723 static ma_result ma_lpf_reinit__internal(const ma_lpf_config* pConfig, ma_lpf* pLPF, ma_bool32 isNew)
36724 {
36725     ma_result result;
36726     ma_uint32 lpf1Count;
36727     ma_uint32 lpf2Count;
36728     ma_uint32 ilpf1;
36729     ma_uint32 ilpf2;
36730
36731     if (pLPF == NULL || pConfig == NULL) {
36732         return MA_INVALID_ARGS;
36733     }
36734
36735     /* Only supporting f32 and s16. */
36736     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
36737         return MA_INVALID_ARGS;
36738     }
36739
36740     /* The format cannot be changed after initialization. */
36741     if (pLPF->format != ma_format_unknown && pLPF->format != pConfig->format) {
36742         return MA_INVALID_OPERATION;
36743     }
36744
36745     /* The channel count cannot be changed after initialization. */
36746     if (pLPF->channels != 0 && pLPF->channels != pConfig->channels) {
36747         return MA_INVALID_OPERATION;
36748     }
36749
36750     if (pConfig->order > MA_MAX_FILTER_ORDER) {
36751         return MA_INVALID_ARGS;
36752     }
36753
36754     lpf1Count = pConfig->order % 2;
36755     lpf2Count = pConfig->order / 2;
36756
36757     MA_ASSERT(lpf1Count <= ma_countof(pLPF->lpf1));
36758     MA_ASSERT(lpf2Count <= ma_countof(pLPF->lpf2));
36759
36760     /* The filter order can't change between reinits. */
36761     if (!isNew) {
36762         if (pLPF->lpf1Count != lpf1Count || pLPF->lpf2Count != lpf2Count) {
36763             return MA_INVALID_OPERATION;
36764         }
36765     }
36766
36767     for (ilpf1 = 0; ilpf1 < lpf1Count; ilpf1 += 1) {
36768         ma_lpf1_config lpf1Config = ma_lpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
36769
36770         if (isNew) {
36771             result = ma_lpf1_init(&lpf1Config, &pLPF->lpf1[ilpf1]);
36772         } else {
36773             result = ma_lpf1_reinit(&lpf1Config, &pLPF->lpf1[ilpf1]);
36774         }
36775
36776         if (result != MA_SUCCESS) {
36777             return result;
36778         }
36779     }
36780
36781     for (ilpf2 = 0; ilpf2 < lpf2Count; ilpf2 += 1) {
36782         ma_lpf2_config lpf2Config;
36783         double q;
36784         double a;
36785
36786         /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */
36787         if (lpf1Count == 1) {
36788             a = (1 + ilpf2*1) * (MA_PI_D/(pConfig->order*1));   /* Odd order. */
36789         } else {
36790             a = (1 + ilpf2*2) * (MA_PI_D/(pConfig->order*2));   /* Even order. */
36791         }
36792         q = 1 / (2*ma_cos(a));
36793
36794         lpf2Config = ma_lpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
36795
36796         if (isNew) {
36797             result = ma_lpf2_init(&lpf2Config, &pLPF->lpf2[ilpf2]);
36798         } else {
36799             result = ma_lpf2_reinit(&lpf2Config, &pLPF->lpf2[ilpf2]);
36800         }
36801
36802         if (result != MA_SUCCESS) {
36803             return result;
36804         }
36805     }
36806
36807     pLPF->lpf1Count  = lpf1Count;
36808     pLPF->lpf2Count  = lpf2Count;
36809     pLPF->format     = pConfig->format;
36810     pLPF->channels   = pConfig->channels;
36811     pLPF->sampleRate = pConfig->sampleRate;
36812
36813     return MA_SUCCESS;
36814 }
36815
36816 MA_API ma_result ma_lpf_init(const ma_lpf_config* pConfig, ma_lpf* pLPF)
36817 {
36818     if (pLPF == NULL) {
36819         return MA_INVALID_ARGS;
36820     }
36821
36822     MA_ZERO_OBJECT(pLPF);
36823
36824     if (pConfig == NULL) {
36825         return MA_INVALID_ARGS;
36826     }
36827
36828     return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_TRUE);
36829 }
36830
36831 MA_API ma_result ma_lpf_reinit(const ma_lpf_config* pConfig, ma_lpf* pLPF)
36832 {
36833     return ma_lpf_reinit__internal(pConfig, pLPF, /*isNew*/MA_FALSE);
36834 }
36835
36836 static MA_INLINE void ma_lpf_process_pcm_frame_f32(ma_lpf* pLPF, float* pY, const void* pX)
36837 {
36838     ma_uint32 ilpf1;
36839     ma_uint32 ilpf2;
36840
36841     MA_ASSERT(pLPF->format == ma_format_f32);
36842
36843     MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels));
36844
36845     for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
36846         ma_lpf1_process_pcm_frame_f32(&pLPF->lpf1[ilpf1], pY, pY);
36847     }
36848
36849     for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
36850         ma_lpf2_process_pcm_frame_f32(&pLPF->lpf2[ilpf2], pY, pY);
36851     }
36852 }
36853
36854 static MA_INLINE void ma_lpf_process_pcm_frame_s16(ma_lpf* pLPF, ma_int16* pY, const ma_int16* pX)
36855 {
36856     ma_uint32 ilpf1;
36857     ma_uint32 ilpf2;
36858
36859     MA_ASSERT(pLPF->format == ma_format_s16);
36860
36861     MA_COPY_MEMORY(pY, pX, ma_get_bytes_per_frame(pLPF->format, pLPF->channels));
36862
36863     for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
36864         ma_lpf1_process_pcm_frame_s16(&pLPF->lpf1[ilpf1], pY, pY);
36865     }
36866
36867     for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
36868         ma_lpf2_process_pcm_frame_s16(&pLPF->lpf2[ilpf2], pY, pY);
36869     }
36870 }
36871
36872 MA_API ma_result ma_lpf_process_pcm_frames(ma_lpf* pLPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
36873 {
36874     ma_result result;
36875     ma_uint32 ilpf1;
36876     ma_uint32 ilpf2;
36877
36878     if (pLPF == NULL) {
36879         return MA_INVALID_ARGS;
36880     }
36881
36882     /* Faster path for in-place. */
36883     if (pFramesOut == pFramesIn) {
36884         for (ilpf1 = 0; ilpf1 < pLPF->lpf1Count; ilpf1 += 1) {
36885             result = ma_lpf1_process_pcm_frames(&pLPF->lpf1[ilpf1], pFramesOut, pFramesOut, frameCount);
36886             if (result != MA_SUCCESS) {
36887                 return result;
36888             }
36889         }
36890
36891         for (ilpf2 = 0; ilpf2 < pLPF->lpf2Count; ilpf2 += 1) {
36892             result = ma_lpf2_process_pcm_frames(&pLPF->lpf2[ilpf2], pFramesOut, pFramesOut, frameCount);
36893             if (result != MA_SUCCESS) {
36894                 return result;
36895             }
36896         }
36897     }
36898
36899     /* Slightly slower path for copying. */
36900     if (pFramesOut != pFramesIn) {
36901         ma_uint32 iFrame;
36902
36903         /*  */ if (pLPF->format == ma_format_f32) {
36904             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
36905             const float* pFramesInF32  = (const float*)pFramesIn;
36906
36907             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
36908                 ma_lpf_process_pcm_frame_f32(pLPF, pFramesOutF32, pFramesInF32);
36909                 pFramesOutF32 += pLPF->channels;
36910                 pFramesInF32  += pLPF->channels;
36911             }
36912         } else if (pLPF->format == ma_format_s16) {
36913             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
36914             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
36915
36916             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
36917                 ma_lpf_process_pcm_frame_s16(pLPF, pFramesOutS16, pFramesInS16);
36918                 pFramesOutS16 += pLPF->channels;
36919                 pFramesInS16  += pLPF->channels;
36920             }
36921         } else {
36922             MA_ASSERT(MA_FALSE);
36923             return MA_INVALID_OPERATION;    /* Should never hit this. */
36924         }
36925     }
36926
36927     return MA_SUCCESS;
36928 }
36929
36930 MA_API ma_uint32 ma_lpf_get_latency(const ma_lpf* pLPF)
36931 {
36932     if (pLPF == NULL) {
36933         return 0;
36934     }
36935
36936     return pLPF->lpf2Count*2 + pLPF->lpf1Count;
36937 }
36938
36939
36940 /**************************************************************************************************************************************************************
36941
36942 High-Pass Filtering
36943
36944 **************************************************************************************************************************************************************/
36945 MA_API ma_hpf1_config ma_hpf1_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency)
36946 {
36947     ma_hpf1_config config;
36948
36949     MA_ZERO_OBJECT(&config);
36950     config.format = format;
36951     config.channels = channels;
36952     config.sampleRate = sampleRate;
36953     config.cutoffFrequency = cutoffFrequency;
36954
36955     return config;
36956 }
36957
36958 MA_API ma_hpf2_config ma_hpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
36959 {
36960     ma_hpf2_config config;
36961
36962     MA_ZERO_OBJECT(&config);
36963     config.format = format;
36964     config.channels = channels;
36965     config.sampleRate = sampleRate;
36966     config.cutoffFrequency = cutoffFrequency;
36967     config.q = q;
36968
36969     /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
36970     if (config.q == 0) {
36971         config.q = 0.707107;
36972     }
36973
36974     return config;
36975 }
36976
36977
36978 MA_API ma_result ma_hpf1_init(const ma_hpf1_config* pConfig, ma_hpf1* pHPF)
36979 {
36980     if (pHPF == NULL) {
36981         return MA_INVALID_ARGS;
36982     }
36983
36984     MA_ZERO_OBJECT(pHPF);
36985
36986     if (pConfig == NULL) {
36987         return MA_INVALID_ARGS;
36988     }
36989
36990     if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
36991         return MA_INVALID_ARGS;
36992     }
36993
36994     return ma_hpf1_reinit(pConfig, pHPF);
36995 }
36996
36997 MA_API ma_result ma_hpf1_reinit(const ma_hpf1_config* pConfig, ma_hpf1* pHPF)
36998 {
36999     double a;
37000
37001     if (pHPF == NULL || pConfig == NULL) {
37002         return MA_INVALID_ARGS;
37003     }
37004
37005     /* Only supporting f32 and s16. */
37006     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
37007         return MA_INVALID_ARGS;
37008     }
37009
37010     /* The format cannot be changed after initialization. */
37011     if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) {
37012         return MA_INVALID_OPERATION;
37013     }
37014
37015     /* The channel count cannot be changed after initialization. */
37016     if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) {
37017         return MA_INVALID_OPERATION;
37018     }
37019
37020     pHPF->format   = pConfig->format;
37021     pHPF->channels = pConfig->channels;
37022
37023     a = ma_exp(-2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate);
37024     if (pConfig->format == ma_format_f32) {
37025         pHPF->a.f32 = (float)a;
37026     } else {
37027         pHPF->a.s32 = ma_biquad_float_to_fp(a);
37028     }
37029
37030     return MA_SUCCESS;
37031 }
37032
37033 static MA_INLINE void ma_hpf1_process_pcm_frame_f32(ma_hpf1* pHPF, float* pY, const float* pX)
37034 {
37035     ma_uint32 c;
37036     const ma_uint32 channels = pHPF->channels;
37037     const float a = 1 - pHPF->a.f32;
37038     const float b = 1 - a;
37039
37040     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
37041     for (c = 0; c < channels; c += 1) {
37042         float r1 = pHPF->r1[c].f32;
37043         float x  = pX[c];
37044         float y;
37045
37046         y = b*x - a*r1;
37047
37048         pY[c]           = y;
37049         pHPF->r1[c].f32 = y;
37050     }
37051 }
37052
37053 static MA_INLINE void ma_hpf1_process_pcm_frame_s16(ma_hpf1* pHPF, ma_int16* pY, const ma_int16* pX)
37054 {
37055     ma_uint32 c;
37056     const ma_uint32 channels = pHPF->channels;
37057     const ma_int32 a = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - pHPF->a.s32);
37058     const ma_int32 b = ((1 << MA_BIQUAD_FIXED_POINT_SHIFT) - a);
37059
37060     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
37061     for (c = 0; c < channels; c += 1) {
37062         ma_int32 r1 = pHPF->r1[c].s32;
37063         ma_int32 x  = pX[c];
37064         ma_int32 y;
37065
37066         y = (b*x - a*r1) >> MA_BIQUAD_FIXED_POINT_SHIFT;
37067
37068         pY[c]           = (ma_int16)y;
37069         pHPF->r1[c].s32 = (ma_int32)y;
37070     }
37071 }
37072
37073 MA_API ma_result ma_hpf1_process_pcm_frames(ma_hpf1* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
37074 {
37075     ma_uint32 n;
37076
37077     if (pHPF == NULL || pFramesOut == NULL || pFramesIn == NULL) {
37078         return MA_INVALID_ARGS;
37079     }
37080
37081     /* 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. */
37082
37083     if (pHPF->format == ma_format_f32) {
37084         /* */ float* pY = (      float*)pFramesOut;
37085         const float* pX = (const float*)pFramesIn;
37086
37087         for (n = 0; n < frameCount; n += 1) {
37088             ma_hpf1_process_pcm_frame_f32(pHPF, pY, pX);
37089             pY += pHPF->channels;
37090             pX += pHPF->channels;
37091         }
37092     } else if (pHPF->format == ma_format_s16) {
37093         /* */ ma_int16* pY = (      ma_int16*)pFramesOut;
37094         const ma_int16* pX = (const ma_int16*)pFramesIn;
37095
37096         for (n = 0; n < frameCount; n += 1) {
37097             ma_hpf1_process_pcm_frame_s16(pHPF, pY, pX);
37098             pY += pHPF->channels;
37099             pX += pHPF->channels;
37100         }
37101     } else {
37102         MA_ASSERT(MA_FALSE);
37103         return MA_INVALID_ARGS; /* Format not supported. Should never hit this because it's checked in ma_biquad_init() and ma_biquad_reinit(). */
37104     }
37105
37106     return MA_SUCCESS;
37107 }
37108
37109 MA_API ma_uint32 ma_hpf1_get_latency(const ma_hpf1* pHPF)
37110 {
37111     if (pHPF == NULL) {
37112         return 0;
37113     }
37114
37115     return 1;
37116 }
37117
37118
37119 static MA_INLINE ma_biquad_config ma_hpf2__get_biquad_config(const ma_hpf2_config* pConfig)
37120 {
37121     ma_biquad_config bqConfig;
37122     double q;
37123     double w;
37124     double s;
37125     double c;
37126     double a;
37127
37128     MA_ASSERT(pConfig != NULL);
37129
37130     q = pConfig->q;
37131     w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
37132     s = ma_sin(w);
37133     c = ma_cos(w);
37134     a = s / (2*q);
37135
37136     bqConfig.b0 =  (1 + c) / 2;
37137     bqConfig.b1 = -(1 + c);
37138     bqConfig.b2 =  (1 + c) / 2;
37139     bqConfig.a0 =   1 + a;
37140     bqConfig.a1 =  -2 * c;
37141     bqConfig.a2 =   1 - a;
37142
37143     bqConfig.format   = pConfig->format;
37144     bqConfig.channels = pConfig->channels;
37145
37146     return bqConfig;
37147 }
37148
37149 MA_API ma_result ma_hpf2_init(const ma_hpf2_config* pConfig, ma_hpf2* pHPF)
37150 {
37151     ma_result result;
37152     ma_biquad_config bqConfig;
37153
37154     if (pHPF == NULL) {
37155         return MA_INVALID_ARGS;
37156     }
37157
37158     MA_ZERO_OBJECT(pHPF);
37159
37160     if (pConfig == NULL) {
37161         return MA_INVALID_ARGS;
37162     }
37163
37164     bqConfig = ma_hpf2__get_biquad_config(pConfig);
37165     result = ma_biquad_init(&bqConfig, &pHPF->bq);
37166     if (result != MA_SUCCESS) {
37167         return result;
37168     }
37169
37170     return MA_SUCCESS;
37171 }
37172
37173 MA_API ma_result ma_hpf2_reinit(const ma_hpf2_config* pConfig, ma_hpf2* pHPF)
37174 {
37175     ma_result result;
37176     ma_biquad_config bqConfig;
37177
37178     if (pHPF == NULL || pConfig == NULL) {
37179         return MA_INVALID_ARGS;
37180     }
37181
37182     bqConfig = ma_hpf2__get_biquad_config(pConfig);
37183     result = ma_biquad_reinit(&bqConfig, &pHPF->bq);
37184     if (result != MA_SUCCESS) {
37185         return result;
37186     }
37187
37188     return MA_SUCCESS;
37189 }
37190
37191 static MA_INLINE void ma_hpf2_process_pcm_frame_s16(ma_hpf2* pHPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
37192 {
37193     ma_biquad_process_pcm_frame_s16(&pHPF->bq, pFrameOut, pFrameIn);
37194 }
37195
37196 static MA_INLINE void ma_hpf2_process_pcm_frame_f32(ma_hpf2* pHPF, float* pFrameOut, const float* pFrameIn)
37197 {
37198     ma_biquad_process_pcm_frame_f32(&pHPF->bq, pFrameOut, pFrameIn);
37199 }
37200
37201 MA_API ma_result ma_hpf2_process_pcm_frames(ma_hpf2* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
37202 {
37203     if (pHPF == NULL) {
37204         return MA_INVALID_ARGS;
37205     }
37206
37207     return ma_biquad_process_pcm_frames(&pHPF->bq, pFramesOut, pFramesIn, frameCount);
37208 }
37209
37210 MA_API ma_uint32 ma_hpf2_get_latency(const ma_hpf2* pHPF)
37211 {
37212     if (pHPF == NULL) {
37213         return 0;
37214     }
37215
37216     return ma_biquad_get_latency(&pHPF->bq);
37217 }
37218
37219
37220 MA_API ma_hpf_config ma_hpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
37221 {
37222     ma_hpf_config config;
37223
37224     MA_ZERO_OBJECT(&config);
37225     config.format          = format;
37226     config.channels        = channels;
37227     config.sampleRate      = sampleRate;
37228     config.cutoffFrequency = cutoffFrequency;
37229     config.order           = ma_min(order, MA_MAX_FILTER_ORDER);
37230
37231     return config;
37232 }
37233
37234 static ma_result ma_hpf_reinit__internal(const ma_hpf_config* pConfig, ma_hpf* pHPF, ma_bool32 isNew)
37235 {
37236     ma_result result;
37237     ma_uint32 hpf1Count;
37238     ma_uint32 hpf2Count;
37239     ma_uint32 ihpf1;
37240     ma_uint32 ihpf2;
37241
37242     if (pHPF == NULL || pConfig == NULL) {
37243         return MA_INVALID_ARGS;
37244     }
37245
37246     /* Only supporting f32 and s16. */
37247     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
37248         return MA_INVALID_ARGS;
37249     }
37250
37251     /* The format cannot be changed after initialization. */
37252     if (pHPF->format != ma_format_unknown && pHPF->format != pConfig->format) {
37253         return MA_INVALID_OPERATION;
37254     }
37255
37256     /* The channel count cannot be changed after initialization. */
37257     if (pHPF->channels != 0 && pHPF->channels != pConfig->channels) {
37258         return MA_INVALID_OPERATION;
37259     }
37260
37261     if (pConfig->order > MA_MAX_FILTER_ORDER) {
37262         return MA_INVALID_ARGS;
37263     }
37264
37265     hpf1Count = pConfig->order % 2;
37266     hpf2Count = pConfig->order / 2;
37267
37268     MA_ASSERT(hpf1Count <= ma_countof(pHPF->hpf1));
37269     MA_ASSERT(hpf2Count <= ma_countof(pHPF->hpf2));
37270
37271     /* The filter order can't change between reinits. */
37272     if (!isNew) {
37273         if (pHPF->hpf1Count != hpf1Count || pHPF->hpf2Count != hpf2Count) {
37274             return MA_INVALID_OPERATION;
37275         }
37276     }
37277
37278     for (ihpf1 = 0; ihpf1 < hpf1Count; ihpf1 += 1) {
37279         ma_hpf1_config hpf1Config = ma_hpf1_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency);
37280
37281         if (isNew) {
37282             result = ma_hpf1_init(&hpf1Config, &pHPF->hpf1[ihpf1]);
37283         } else {
37284             result = ma_hpf1_reinit(&hpf1Config, &pHPF->hpf1[ihpf1]);
37285         }
37286
37287         if (result != MA_SUCCESS) {
37288             return result;
37289         }
37290     }
37291
37292     for (ihpf2 = 0; ihpf2 < hpf2Count; ihpf2 += 1) {
37293         ma_hpf2_config hpf2Config;
37294         double q;
37295         double a;
37296
37297         /* Tempting to use 0.707107, but won't result in a Butterworth filter if the order is > 2. */
37298         if (hpf1Count == 1) {
37299             a = (1 + ihpf2*1) * (MA_PI_D/(pConfig->order*1));   /* Odd order. */
37300         } else {
37301             a = (1 + ihpf2*2) * (MA_PI_D/(pConfig->order*2));   /* Even order. */
37302         }
37303         q = 1 / (2*ma_cos(a));
37304
37305         hpf2Config = ma_hpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
37306
37307         if (isNew) {
37308             result = ma_hpf2_init(&hpf2Config, &pHPF->hpf2[ihpf2]);
37309         } else {
37310             result = ma_hpf2_reinit(&hpf2Config, &pHPF->hpf2[ihpf2]);
37311         }
37312
37313         if (result != MA_SUCCESS) {
37314             return result;
37315         }
37316     }
37317
37318     pHPF->hpf1Count  = hpf1Count;
37319     pHPF->hpf2Count  = hpf2Count;
37320     pHPF->format     = pConfig->format;
37321     pHPF->channels   = pConfig->channels;
37322     pHPF->sampleRate = pConfig->sampleRate;
37323
37324     return MA_SUCCESS;
37325 }
37326
37327 MA_API ma_result ma_hpf_init(const ma_hpf_config* pConfig, ma_hpf* pHPF)
37328 {
37329     if (pHPF == NULL) {
37330         return MA_INVALID_ARGS;
37331     }
37332
37333     MA_ZERO_OBJECT(pHPF);
37334
37335     if (pConfig == NULL) {
37336         return MA_INVALID_ARGS;
37337     }
37338
37339     return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_TRUE);
37340 }
37341
37342 MA_API ma_result ma_hpf_reinit(const ma_hpf_config* pConfig, ma_hpf* pHPF)
37343 {
37344     return ma_hpf_reinit__internal(pConfig, pHPF, /*isNew*/MA_FALSE);
37345 }
37346
37347 MA_API ma_result ma_hpf_process_pcm_frames(ma_hpf* pHPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
37348 {
37349     ma_result result;
37350     ma_uint32 ihpf1;
37351     ma_uint32 ihpf2;
37352
37353     if (pHPF == NULL) {
37354         return MA_INVALID_ARGS;
37355     }
37356
37357     /* Faster path for in-place. */
37358     if (pFramesOut == pFramesIn) {
37359         for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
37360             result = ma_hpf1_process_pcm_frames(&pHPF->hpf1[ihpf1], pFramesOut, pFramesOut, frameCount);
37361             if (result != MA_SUCCESS) {
37362                 return result;
37363             }
37364         }
37365
37366         for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
37367             result = ma_hpf2_process_pcm_frames(&pHPF->hpf2[ihpf2], pFramesOut, pFramesOut, frameCount);
37368             if (result != MA_SUCCESS) {
37369                 return result;
37370             }
37371         }
37372     }
37373
37374     /* Slightly slower path for copying. */
37375     if (pFramesOut != pFramesIn) {
37376         ma_uint32 iFrame;
37377
37378         /*  */ if (pHPF->format == ma_format_f32) {
37379             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
37380             const float* pFramesInF32  = (const float*)pFramesIn;
37381
37382             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
37383                 MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pHPF->format, pHPF->channels));
37384
37385                 for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
37386                     ma_hpf1_process_pcm_frame_f32(&pHPF->hpf1[ihpf1], pFramesOutF32, pFramesOutF32);
37387                 }
37388
37389                 for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
37390                     ma_hpf2_process_pcm_frame_f32(&pHPF->hpf2[ihpf2], pFramesOutF32, pFramesOutF32);
37391                 }
37392
37393                 pFramesOutF32 += pHPF->channels;
37394                 pFramesInF32  += pHPF->channels;
37395             }
37396         } else if (pHPF->format == ma_format_s16) {
37397             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
37398             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
37399
37400             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
37401                 MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pHPF->format, pHPF->channels));
37402
37403                 for (ihpf1 = 0; ihpf1 < pHPF->hpf1Count; ihpf1 += 1) {
37404                     ma_hpf1_process_pcm_frame_s16(&pHPF->hpf1[ihpf1], pFramesOutS16, pFramesOutS16);
37405                 }
37406
37407                 for (ihpf2 = 0; ihpf2 < pHPF->hpf2Count; ihpf2 += 1) {
37408                     ma_hpf2_process_pcm_frame_s16(&pHPF->hpf2[ihpf2], pFramesOutS16, pFramesOutS16);
37409                 }
37410
37411                 pFramesOutS16 += pHPF->channels;
37412                 pFramesInS16  += pHPF->channels;
37413             }
37414         } else {
37415             MA_ASSERT(MA_FALSE);
37416             return MA_INVALID_OPERATION;    /* Should never hit this. */
37417         }
37418     }
37419
37420     return MA_SUCCESS;
37421 }
37422
37423 MA_API ma_uint32 ma_hpf_get_latency(const ma_hpf* pHPF)
37424 {
37425     if (pHPF == NULL) {
37426         return 0;
37427     }
37428
37429     return pHPF->hpf2Count*2 + pHPF->hpf1Count;
37430 }
37431
37432
37433 /**************************************************************************************************************************************************************
37434
37435 Band-Pass Filtering
37436
37437 **************************************************************************************************************************************************************/
37438 MA_API ma_bpf2_config ma_bpf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, double q)
37439 {
37440     ma_bpf2_config config;
37441
37442     MA_ZERO_OBJECT(&config);
37443     config.format = format;
37444     config.channels = channels;
37445     config.sampleRate = sampleRate;
37446     config.cutoffFrequency = cutoffFrequency;
37447     config.q = q;
37448
37449     /* Q cannot be 0 or else it'll result in a division by 0. In this case just default to 0.707107. */
37450     if (config.q == 0) {
37451         config.q = 0.707107;
37452     }
37453
37454     return config;
37455 }
37456
37457
37458 static MA_INLINE ma_biquad_config ma_bpf2__get_biquad_config(const ma_bpf2_config* pConfig)
37459 {
37460     ma_biquad_config bqConfig;
37461     double q;
37462     double w;
37463     double s;
37464     double c;
37465     double a;
37466
37467     MA_ASSERT(pConfig != NULL);
37468
37469     q = pConfig->q;
37470     w = 2 * MA_PI_D * pConfig->cutoffFrequency / pConfig->sampleRate;
37471     s = ma_sin(w);
37472     c = ma_cos(w);
37473     a = s / (2*q);
37474
37475     bqConfig.b0 =  q * a;
37476     bqConfig.b1 =  0;
37477     bqConfig.b2 = -q * a;
37478     bqConfig.a0 =  1 + a;
37479     bqConfig.a1 = -2 * c;
37480     bqConfig.a2 =  1 - a;
37481
37482     bqConfig.format   = pConfig->format;
37483     bqConfig.channels = pConfig->channels;
37484
37485     return bqConfig;
37486 }
37487
37488 MA_API ma_result ma_bpf2_init(const ma_bpf2_config* pConfig, ma_bpf2* pBPF)
37489 {
37490     ma_result result;
37491     ma_biquad_config bqConfig;
37492
37493     if (pBPF == NULL) {
37494         return MA_INVALID_ARGS;
37495     }
37496
37497     MA_ZERO_OBJECT(pBPF);
37498
37499     if (pConfig == NULL) {
37500         return MA_INVALID_ARGS;
37501     }
37502
37503     bqConfig = ma_bpf2__get_biquad_config(pConfig);
37504     result = ma_biquad_init(&bqConfig, &pBPF->bq);
37505     if (result != MA_SUCCESS) {
37506         return result;
37507     }
37508
37509     return MA_SUCCESS;
37510 }
37511
37512 MA_API ma_result ma_bpf2_reinit(const ma_bpf2_config* pConfig, ma_bpf2* pBPF)
37513 {
37514     ma_result result;
37515     ma_biquad_config bqConfig;
37516
37517     if (pBPF == NULL || pConfig == NULL) {
37518         return MA_INVALID_ARGS;
37519     }
37520
37521     bqConfig = ma_bpf2__get_biquad_config(pConfig);
37522     result = ma_biquad_reinit(&bqConfig, &pBPF->bq);
37523     if (result != MA_SUCCESS) {
37524         return result;
37525     }
37526
37527     return MA_SUCCESS;
37528 }
37529
37530 static MA_INLINE void ma_bpf2_process_pcm_frame_s16(ma_bpf2* pBPF, ma_int16* pFrameOut, const ma_int16* pFrameIn)
37531 {
37532     ma_biquad_process_pcm_frame_s16(&pBPF->bq, pFrameOut, pFrameIn);
37533 }
37534
37535 static MA_INLINE void ma_bpf2_process_pcm_frame_f32(ma_bpf2* pBPF, float* pFrameOut, const float* pFrameIn)
37536 {
37537     ma_biquad_process_pcm_frame_f32(&pBPF->bq, pFrameOut, pFrameIn);
37538 }
37539
37540 MA_API ma_result ma_bpf2_process_pcm_frames(ma_bpf2* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
37541 {
37542     if (pBPF == NULL) {
37543         return MA_INVALID_ARGS;
37544     }
37545
37546     return ma_biquad_process_pcm_frames(&pBPF->bq, pFramesOut, pFramesIn, frameCount);
37547 }
37548
37549 MA_API ma_uint32 ma_bpf2_get_latency(const ma_bpf2* pBPF)
37550 {
37551     if (pBPF == NULL) {
37552         return 0;
37553     }
37554
37555     return ma_biquad_get_latency(&pBPF->bq);
37556 }
37557
37558
37559 MA_API ma_bpf_config ma_bpf_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order)
37560 {
37561     ma_bpf_config config;
37562
37563     MA_ZERO_OBJECT(&config);
37564     config.format          = format;
37565     config.channels        = channels;
37566     config.sampleRate      = sampleRate;
37567     config.cutoffFrequency = cutoffFrequency;
37568     config.order           = ma_min(order, MA_MAX_FILTER_ORDER);
37569
37570     return config;
37571 }
37572
37573 static ma_result ma_bpf_reinit__internal(const ma_bpf_config* pConfig, ma_bpf* pBPF, ma_bool32 isNew)
37574 {
37575     ma_result result;
37576     ma_uint32 bpf2Count;
37577     ma_uint32 ibpf2;
37578
37579     if (pBPF == NULL || pConfig == NULL) {
37580         return MA_INVALID_ARGS;
37581     }
37582
37583     /* Only supporting f32 and s16. */
37584     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
37585         return MA_INVALID_ARGS;
37586     }
37587
37588     /* The format cannot be changed after initialization. */
37589     if (pBPF->format != ma_format_unknown && pBPF->format != pConfig->format) {
37590         return MA_INVALID_OPERATION;
37591     }
37592
37593     /* The channel count cannot be changed after initialization. */
37594     if (pBPF->channels != 0 && pBPF->channels != pConfig->channels) {
37595         return MA_INVALID_OPERATION;
37596     }
37597
37598     if (pConfig->order > MA_MAX_FILTER_ORDER) {
37599         return MA_INVALID_ARGS;
37600     }
37601
37602     /* We must have an even number of order. */
37603     if ((pConfig->order & 0x1) != 0) {
37604         return MA_INVALID_ARGS;
37605     }
37606
37607     bpf2Count = pConfig->order / 2;
37608
37609     MA_ASSERT(bpf2Count <= ma_countof(pBPF->bpf2));
37610
37611     /* The filter order can't change between reinits. */
37612     if (!isNew) {
37613         if (pBPF->bpf2Count != bpf2Count) {
37614             return MA_INVALID_OPERATION;
37615         }
37616     }
37617
37618     for (ibpf2 = 0; ibpf2 < bpf2Count; ibpf2 += 1) {
37619         ma_bpf2_config bpf2Config;
37620         double q;
37621
37622         /* TODO: Calculate Q to make this a proper Butterworth filter. */
37623         q = 0.707107;
37624
37625         bpf2Config = ma_bpf2_config_init(pConfig->format, pConfig->channels, pConfig->sampleRate, pConfig->cutoffFrequency, q);
37626
37627         if (isNew) {
37628             result = ma_bpf2_init(&bpf2Config, &pBPF->bpf2[ibpf2]);
37629         } else {
37630             result = ma_bpf2_reinit(&bpf2Config, &pBPF->bpf2[ibpf2]);
37631         }
37632
37633         if (result != MA_SUCCESS) {
37634             return result;
37635         }
37636     }
37637
37638     pBPF->bpf2Count = bpf2Count;
37639     pBPF->format    = pConfig->format;
37640     pBPF->channels  = pConfig->channels;
37641
37642     return MA_SUCCESS;
37643 }
37644
37645 MA_API ma_result ma_bpf_init(const ma_bpf_config* pConfig, ma_bpf* pBPF)
37646 {
37647     if (pBPF == NULL) {
37648         return MA_INVALID_ARGS;
37649     }
37650
37651     MA_ZERO_OBJECT(pBPF);
37652
37653     if (pConfig == NULL) {
37654         return MA_INVALID_ARGS;
37655     }
37656
37657     return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_TRUE);
37658 }
37659
37660 MA_API ma_result ma_bpf_reinit(const ma_bpf_config* pConfig, ma_bpf* pBPF)
37661 {
37662     return ma_bpf_reinit__internal(pConfig, pBPF, /*isNew*/MA_FALSE);
37663 }
37664
37665 MA_API ma_result ma_bpf_process_pcm_frames(ma_bpf* pBPF, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
37666 {
37667     ma_result result;
37668     ma_uint32 ibpf2;
37669
37670     if (pBPF == NULL) {
37671         return MA_INVALID_ARGS;
37672     }
37673
37674     /* Faster path for in-place. */
37675     if (pFramesOut == pFramesIn) {
37676         for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
37677             result = ma_bpf2_process_pcm_frames(&pBPF->bpf2[ibpf2], pFramesOut, pFramesOut, frameCount);
37678             if (result != MA_SUCCESS) {
37679                 return result;
37680             }
37681         }
37682     }
37683
37684     /* Slightly slower path for copying. */
37685     if (pFramesOut != pFramesIn) {
37686         ma_uint32 iFrame;
37687
37688         /*  */ if (pBPF->format == ma_format_f32) {
37689             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
37690             const float* pFramesInF32  = (const float*)pFramesIn;
37691
37692             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
37693                 MA_COPY_MEMORY(pFramesOutF32, pFramesInF32, ma_get_bytes_per_frame(pBPF->format, pBPF->channels));
37694
37695                 for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
37696                     ma_bpf2_process_pcm_frame_f32(&pBPF->bpf2[ibpf2], pFramesOutF32, pFramesOutF32);
37697                 }
37698
37699                 pFramesOutF32 += pBPF->channels;
37700                 pFramesInF32  += pBPF->channels;
37701             }
37702         } else if (pBPF->format == ma_format_s16) {
37703             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
37704             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
37705
37706             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
37707                 MA_COPY_MEMORY(pFramesOutS16, pFramesInS16, ma_get_bytes_per_frame(pBPF->format, pBPF->channels));
37708
37709                 for (ibpf2 = 0; ibpf2 < pBPF->bpf2Count; ibpf2 += 1) {
37710                     ma_bpf2_process_pcm_frame_s16(&pBPF->bpf2[ibpf2], pFramesOutS16, pFramesOutS16);
37711                 }
37712
37713                 pFramesOutS16 += pBPF->channels;
37714                 pFramesInS16  += pBPF->channels;
37715             }
37716         } else {
37717             MA_ASSERT(MA_FALSE);
37718             return MA_INVALID_OPERATION;    /* Should never hit this. */
37719         }
37720     }
37721
37722     return MA_SUCCESS;
37723 }
37724
37725 MA_API ma_uint32 ma_bpf_get_latency(const ma_bpf* pBPF)
37726 {
37727     if (pBPF == NULL) {
37728         return 0;
37729     }
37730
37731     return pBPF->bpf2Count*2;
37732 }
37733
37734
37735 /**************************************************************************************************************************************************************
37736
37737 Notching Filter
37738
37739 **************************************************************************************************************************************************************/
37740 MA_API ma_notch2_config ma_notch2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency)
37741 {
37742     ma_notch2_config config;
37743
37744     MA_ZERO_OBJECT(&config);
37745     config.format     = format;
37746     config.channels   = channels;
37747     config.sampleRate = sampleRate;
37748     config.q          = q;
37749     config.frequency  = frequency;
37750
37751     if (config.q == 0) {
37752         config.q = 0.707107;
37753     }
37754
37755     return config;
37756 }
37757
37758
37759 static MA_INLINE ma_biquad_config ma_notch2__get_biquad_config(const ma_notch2_config* pConfig)
37760 {
37761     ma_biquad_config bqConfig;
37762     double q;
37763     double w;
37764     double s;
37765     double c;
37766     double a;
37767
37768     MA_ASSERT(pConfig != NULL);
37769
37770     q = pConfig->q;
37771     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
37772     s = ma_sin(w);
37773     c = ma_cos(w);
37774     a = s / (2*q);
37775
37776     bqConfig.b0 =  1;
37777     bqConfig.b1 = -2 * c;
37778     bqConfig.b2 =  1;
37779     bqConfig.a0 =  1 + a;
37780     bqConfig.a1 = -2 * c;
37781     bqConfig.a2 =  1 - a;
37782
37783     bqConfig.format   = pConfig->format;
37784     bqConfig.channels = pConfig->channels;
37785
37786     return bqConfig;
37787 }
37788
37789 MA_API ma_result ma_notch2_init(const ma_notch2_config* pConfig, ma_notch2* pFilter)
37790 {
37791     ma_result result;
37792     ma_biquad_config bqConfig;
37793
37794     if (pFilter == NULL) {
37795         return MA_INVALID_ARGS;
37796     }
37797
37798     MA_ZERO_OBJECT(pFilter);
37799
37800     if (pConfig == NULL) {
37801         return MA_INVALID_ARGS;
37802     }
37803
37804     bqConfig = ma_notch2__get_biquad_config(pConfig);
37805     result = ma_biquad_init(&bqConfig, &pFilter->bq);
37806     if (result != MA_SUCCESS) {
37807         return result;
37808     }
37809
37810     return MA_SUCCESS;
37811 }
37812
37813 MA_API ma_result ma_notch2_reinit(const ma_notch2_config* pConfig, ma_notch2* pFilter)
37814 {
37815     ma_result result;
37816     ma_biquad_config bqConfig;
37817
37818     if (pFilter == NULL || pConfig == NULL) {
37819         return MA_INVALID_ARGS;
37820     }
37821
37822     bqConfig = ma_notch2__get_biquad_config(pConfig);
37823     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
37824     if (result != MA_SUCCESS) {
37825         return result;
37826     }
37827
37828     return MA_SUCCESS;
37829 }
37830
37831 static MA_INLINE void ma_notch2_process_pcm_frame_s16(ma_notch2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
37832 {
37833     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
37834 }
37835
37836 static MA_INLINE void ma_notch2_process_pcm_frame_f32(ma_notch2* pFilter, float* pFrameOut, const float* pFrameIn)
37837 {
37838     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
37839 }
37840
37841 MA_API ma_result ma_notch2_process_pcm_frames(ma_notch2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
37842 {
37843     if (pFilter == NULL) {
37844         return MA_INVALID_ARGS;
37845     }
37846
37847     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
37848 }
37849
37850 MA_API ma_uint32 ma_notch2_get_latency(const ma_notch2* pFilter)
37851 {
37852     if (pFilter == NULL) {
37853         return 0;
37854     }
37855
37856     return ma_biquad_get_latency(&pFilter->bq);
37857 }
37858
37859
37860
37861 /**************************************************************************************************************************************************************
37862
37863 Peaking EQ Filter
37864
37865 **************************************************************************************************************************************************************/
37866 MA_API ma_peak2_config ma_peak2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency)
37867 {
37868     ma_peak2_config config;
37869
37870     MA_ZERO_OBJECT(&config);
37871     config.format     = format;
37872     config.channels   = channels;
37873     config.sampleRate = sampleRate;
37874     config.gainDB     = gainDB;
37875     config.q          = q;
37876     config.frequency  = frequency;
37877
37878     if (config.q == 0) {
37879         config.q = 0.707107;
37880     }
37881
37882     return config;
37883 }
37884
37885
37886 static MA_INLINE ma_biquad_config ma_peak2__get_biquad_config(const ma_peak2_config* pConfig)
37887 {
37888     ma_biquad_config bqConfig;
37889     double q;
37890     double w;
37891     double s;
37892     double c;
37893     double a;
37894     double A;
37895
37896     MA_ASSERT(pConfig != NULL);
37897
37898     q = pConfig->q;
37899     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
37900     s = ma_sin(w);
37901     c = ma_cos(w);
37902     a = s / (2*q);
37903     A = ma_pow(10, (pConfig->gainDB / 40));
37904
37905     bqConfig.b0 =  1 + (a * A);
37906     bqConfig.b1 = -2 * c;
37907     bqConfig.b2 =  1 - (a * A);
37908     bqConfig.a0 =  1 + (a / A);
37909     bqConfig.a1 = -2 * c;
37910     bqConfig.a2 =  1 - (a / A);
37911
37912     bqConfig.format   = pConfig->format;
37913     bqConfig.channels = pConfig->channels;
37914
37915     return bqConfig;
37916 }
37917
37918 MA_API ma_result ma_peak2_init(const ma_peak2_config* pConfig, ma_peak2* pFilter)
37919 {
37920     ma_result result;
37921     ma_biquad_config bqConfig;
37922
37923     if (pFilter == NULL) {
37924         return MA_INVALID_ARGS;
37925     }
37926
37927     MA_ZERO_OBJECT(pFilter);
37928
37929     if (pConfig == NULL) {
37930         return MA_INVALID_ARGS;
37931     }
37932
37933     bqConfig = ma_peak2__get_biquad_config(pConfig);
37934     result = ma_biquad_init(&bqConfig, &pFilter->bq);
37935     if (result != MA_SUCCESS) {
37936         return result;
37937     }
37938
37939     return MA_SUCCESS;
37940 }
37941
37942 MA_API ma_result ma_peak2_reinit(const ma_peak2_config* pConfig, ma_peak2* pFilter)
37943 {
37944     ma_result result;
37945     ma_biquad_config bqConfig;
37946
37947     if (pFilter == NULL || pConfig == NULL) {
37948         return MA_INVALID_ARGS;
37949     }
37950
37951     bqConfig = ma_peak2__get_biquad_config(pConfig);
37952     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
37953     if (result != MA_SUCCESS) {
37954         return result;
37955     }
37956
37957     return MA_SUCCESS;
37958 }
37959
37960 static MA_INLINE void ma_peak2_process_pcm_frame_s16(ma_peak2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
37961 {
37962     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
37963 }
37964
37965 static MA_INLINE void ma_peak2_process_pcm_frame_f32(ma_peak2* pFilter, float* pFrameOut, const float* pFrameIn)
37966 {
37967     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
37968 }
37969
37970 MA_API ma_result ma_peak2_process_pcm_frames(ma_peak2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
37971 {
37972     if (pFilter == NULL) {
37973         return MA_INVALID_ARGS;
37974     }
37975
37976     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
37977 }
37978
37979 MA_API ma_uint32 ma_peak2_get_latency(const ma_peak2* pFilter)
37980 {
37981     if (pFilter == NULL) {
37982         return 0;
37983     }
37984
37985     return ma_biquad_get_latency(&pFilter->bq);
37986 }
37987
37988
37989 /**************************************************************************************************************************************************************
37990
37991 Low Shelf Filter
37992
37993 **************************************************************************************************************************************************************/
37994 MA_API ma_loshelf2_config ma_loshelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
37995 {
37996     ma_loshelf2_config config;
37997
37998     MA_ZERO_OBJECT(&config);
37999     config.format     = format;
38000     config.channels   = channels;
38001     config.sampleRate = sampleRate;
38002     config.gainDB     = gainDB;
38003     config.shelfSlope = shelfSlope;
38004     config.frequency  = frequency;
38005
38006     return config;
38007 }
38008
38009
38010 static MA_INLINE ma_biquad_config ma_loshelf2__get_biquad_config(const ma_loshelf2_config* pConfig)
38011 {
38012     ma_biquad_config bqConfig;
38013     double w;
38014     double s;
38015     double c;
38016     double A;
38017     double S;
38018     double a;
38019     double sqrtA;
38020
38021     MA_ASSERT(pConfig != NULL);
38022
38023     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
38024     s = ma_sin(w);
38025     c = ma_cos(w);
38026     A = ma_pow(10, (pConfig->gainDB / 40));
38027     S = pConfig->shelfSlope;
38028     a = s/2 * ma_sqrt((A + 1/A) * (1/S - 1) + 2);
38029     sqrtA = 2*ma_sqrt(A)*a;
38030
38031     bqConfig.b0 =  A * ((A + 1) - (A - 1)*c + sqrtA);
38032     bqConfig.b1 =  2 * A * ((A - 1) - (A + 1)*c);
38033     bqConfig.b2 =  A * ((A + 1) - (A - 1)*c - sqrtA);
38034     bqConfig.a0 =  (A + 1) + (A - 1)*c + sqrtA;
38035     bqConfig.a1 = -2 * ((A - 1) + (A + 1)*c);
38036     bqConfig.a2 =  (A + 1) + (A - 1)*c - sqrtA;
38037
38038     bqConfig.format   = pConfig->format;
38039     bqConfig.channels = pConfig->channels;
38040
38041     return bqConfig;
38042 }
38043
38044 MA_API ma_result ma_loshelf2_init(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter)
38045 {
38046     ma_result result;
38047     ma_biquad_config bqConfig;
38048
38049     if (pFilter == NULL) {
38050         return MA_INVALID_ARGS;
38051     }
38052
38053     MA_ZERO_OBJECT(pFilter);
38054
38055     if (pConfig == NULL) {
38056         return MA_INVALID_ARGS;
38057     }
38058
38059     bqConfig = ma_loshelf2__get_biquad_config(pConfig);
38060     result = ma_biquad_init(&bqConfig, &pFilter->bq);
38061     if (result != MA_SUCCESS) {
38062         return result;
38063     }
38064
38065     return MA_SUCCESS;
38066 }
38067
38068 MA_API ma_result ma_loshelf2_reinit(const ma_loshelf2_config* pConfig, ma_loshelf2* pFilter)
38069 {
38070     ma_result result;
38071     ma_biquad_config bqConfig;
38072
38073     if (pFilter == NULL || pConfig == NULL) {
38074         return MA_INVALID_ARGS;
38075     }
38076
38077     bqConfig = ma_loshelf2__get_biquad_config(pConfig);
38078     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
38079     if (result != MA_SUCCESS) {
38080         return result;
38081     }
38082
38083     return MA_SUCCESS;
38084 }
38085
38086 static MA_INLINE void ma_loshelf2_process_pcm_frame_s16(ma_loshelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
38087 {
38088     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
38089 }
38090
38091 static MA_INLINE void ma_loshelf2_process_pcm_frame_f32(ma_loshelf2* pFilter, float* pFrameOut, const float* pFrameIn)
38092 {
38093     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
38094 }
38095
38096 MA_API ma_result ma_loshelf2_process_pcm_frames(ma_loshelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
38097 {
38098     if (pFilter == NULL) {
38099         return MA_INVALID_ARGS;
38100     }
38101
38102     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
38103 }
38104
38105 MA_API ma_uint32 ma_loshelf2_get_latency(const ma_loshelf2* pFilter)
38106 {
38107     if (pFilter == NULL) {
38108         return 0;
38109     }
38110
38111     return ma_biquad_get_latency(&pFilter->bq);
38112 }
38113
38114
38115 /**************************************************************************************************************************************************************
38116
38117 High Shelf Filter
38118
38119 **************************************************************************************************************************************************************/
38120 MA_API ma_hishelf2_config ma_hishelf2_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double shelfSlope, double frequency)
38121 {
38122     ma_hishelf2_config config;
38123
38124     MA_ZERO_OBJECT(&config);
38125     config.format     = format;
38126     config.channels   = channels;
38127     config.sampleRate = sampleRate;
38128     config.gainDB     = gainDB;
38129     config.shelfSlope = shelfSlope;
38130     config.frequency  = frequency;
38131
38132     return config;
38133 }
38134
38135
38136 static MA_INLINE ma_biquad_config ma_hishelf2__get_biquad_config(const ma_hishelf2_config* pConfig)
38137 {
38138     ma_biquad_config bqConfig;
38139     double w;
38140     double s;
38141     double c;
38142     double A;
38143     double S;
38144     double a;
38145     double sqrtA;
38146
38147     MA_ASSERT(pConfig != NULL);
38148
38149     w = 2 * MA_PI_D * pConfig->frequency / pConfig->sampleRate;
38150     s = ma_sin(w);
38151     c = ma_cos(w);
38152     A = ma_pow(10, (pConfig->gainDB / 40));
38153     S = pConfig->shelfSlope;
38154     a = s/2 * ma_sqrt((A + 1/A) * (1/S - 1) + 2);
38155     sqrtA = 2*ma_sqrt(A)*a;
38156
38157     bqConfig.b0 =  A * ((A + 1) + (A - 1)*c + sqrtA);
38158     bqConfig.b1 = -2 * A * ((A - 1) + (A + 1)*c);
38159     bqConfig.b2 =  A * ((A + 1) + (A - 1)*c - sqrtA);
38160     bqConfig.a0 =  (A + 1) - (A - 1)*c + sqrtA;
38161     bqConfig.a1 =  2 * ((A - 1) - (A + 1)*c);
38162     bqConfig.a2 =  (A + 1) - (A - 1)*c - sqrtA;
38163
38164     bqConfig.format   = pConfig->format;
38165     bqConfig.channels = pConfig->channels;
38166
38167     return bqConfig;
38168 }
38169
38170 MA_API ma_result ma_hishelf2_init(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter)
38171 {
38172     ma_result result;
38173     ma_biquad_config bqConfig;
38174
38175     if (pFilter == NULL) {
38176         return MA_INVALID_ARGS;
38177     }
38178
38179     MA_ZERO_OBJECT(pFilter);
38180
38181     if (pConfig == NULL) {
38182         return MA_INVALID_ARGS;
38183     }
38184
38185     bqConfig = ma_hishelf2__get_biquad_config(pConfig);
38186     result = ma_biquad_init(&bqConfig, &pFilter->bq);
38187     if (result != MA_SUCCESS) {
38188         return result;
38189     }
38190
38191     return MA_SUCCESS;
38192 }
38193
38194 MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter)
38195 {
38196     ma_result result;
38197     ma_biquad_config bqConfig;
38198
38199     if (pFilter == NULL || pConfig == NULL) {
38200         return MA_INVALID_ARGS;
38201     }
38202
38203     bqConfig = ma_hishelf2__get_biquad_config(pConfig);
38204     result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
38205     if (result != MA_SUCCESS) {
38206         return result;
38207     }
38208
38209     return MA_SUCCESS;
38210 }
38211
38212 static MA_INLINE void ma_hishelf2_process_pcm_frame_s16(ma_hishelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
38213 {
38214     ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
38215 }
38216
38217 static MA_INLINE void ma_hishelf2_process_pcm_frame_f32(ma_hishelf2* pFilter, float* pFrameOut, const float* pFrameIn)
38218 {
38219     ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
38220 }
38221
38222 MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
38223 {
38224     if (pFilter == NULL) {
38225         return MA_INVALID_ARGS;
38226     }
38227
38228     return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
38229 }
38230
38231 MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter)
38232 {
38233     if (pFilter == NULL) {
38234         return 0;
38235     }
38236
38237     return ma_biquad_get_latency(&pFilter->bq);
38238 }
38239
38240
38241
38242 /**************************************************************************************************************************************************************
38243
38244 Resampling
38245
38246 **************************************************************************************************************************************************************/
38247 MA_API ma_linear_resampler_config ma_linear_resampler_config_init(ma_format format, ma_uint32 channels, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
38248 {
38249     ma_linear_resampler_config config;
38250     MA_ZERO_OBJECT(&config);
38251     config.format           = format;
38252     config.channels         = channels;
38253     config.sampleRateIn     = sampleRateIn;
38254     config.sampleRateOut    = sampleRateOut;
38255     config.lpfOrder         = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
38256     config.lpfNyquistFactor = 1;
38257
38258     return config;
38259 }
38260
38261 static void ma_linear_resampler_adjust_timer_for_new_rate(ma_linear_resampler* pResampler, ma_uint32 oldSampleRateOut, ma_uint32 newSampleRateOut)
38262 {
38263     /*
38264     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
38265     be based on the old sample rate, but we are needing to adjust it to that it's based on the new sample rate.
38266     */
38267     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. */
38268     ma_uint32 oldRateTimeFract = pResampler->inTimeFrac % oldSampleRateOut;
38269
38270     pResampler->inTimeFrac =
38271          (oldRateTimeWhole * newSampleRateOut) +
38272         ((oldRateTimeFract * newSampleRateOut) / oldSampleRateOut);
38273
38274     /* Make sure the fractional part is less than the output sample rate. */
38275     pResampler->inTimeInt += pResampler->inTimeFrac / pResampler->config.sampleRateOut;
38276     pResampler->inTimeFrac = pResampler->inTimeFrac % pResampler->config.sampleRateOut;
38277 }
38278
38279 static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut, ma_bool32 isResamplerAlreadyInitialized)
38280 {
38281     ma_result result;
38282     ma_uint32 gcf;
38283     ma_uint32 lpfSampleRate;
38284     double lpfCutoffFrequency;
38285     ma_lpf_config lpfConfig;
38286     ma_uint32 oldSampleRateOut; /* Required for adjusting time advance down the bottom. */
38287
38288     if (pResampler == NULL) {
38289         return MA_INVALID_ARGS;
38290     }
38291
38292     if (sampleRateIn == 0 || sampleRateOut == 0) {
38293         return MA_INVALID_ARGS;
38294     }
38295
38296     oldSampleRateOut = pResampler->config.sampleRateOut;
38297
38298     pResampler->config.sampleRateIn  = sampleRateIn;
38299     pResampler->config.sampleRateOut = sampleRateOut;
38300
38301     /* Simplify the sample rate. */
38302     gcf = ma_gcf_u32(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut);
38303     pResampler->config.sampleRateIn  /= gcf;
38304     pResampler->config.sampleRateOut /= gcf;
38305
38306     /* Always initialize the low-pass filter, even when the order is 0. */
38307     if (pResampler->config.lpfOrder > MA_MAX_FILTER_ORDER) {
38308         return MA_INVALID_ARGS;
38309     }
38310
38311     lpfSampleRate      = (ma_uint32)(ma_max(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut));
38312     lpfCutoffFrequency = (   double)(ma_min(pResampler->config.sampleRateIn, pResampler->config.sampleRateOut) * 0.5 * pResampler->config.lpfNyquistFactor);
38313
38314     lpfConfig = ma_lpf_config_init(pResampler->config.format, pResampler->config.channels, lpfSampleRate, lpfCutoffFrequency, pResampler->config.lpfOrder);
38315
38316     /*
38317     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
38318     getting cleared. Instead we re-initialize the filter which will maintain any cached frames.
38319     */
38320     if (isResamplerAlreadyInitialized) {
38321         result = ma_lpf_reinit(&lpfConfig, &pResampler->lpf);
38322     } else {
38323         result = ma_lpf_init(&lpfConfig, &pResampler->lpf);
38324     }
38325
38326     if (result != MA_SUCCESS) {
38327         return result;
38328     }
38329
38330
38331     pResampler->inAdvanceInt  = pResampler->config.sampleRateIn / pResampler->config.sampleRateOut;
38332     pResampler->inAdvanceFrac = pResampler->config.sampleRateIn % pResampler->config.sampleRateOut;
38333
38334     /* Our timer was based on the old rate. We need to adjust it so that it's based on the new rate. */
38335     ma_linear_resampler_adjust_timer_for_new_rate(pResampler, oldSampleRateOut, pResampler->config.sampleRateOut);
38336
38337     return MA_SUCCESS;
38338 }
38339
38340 MA_API ma_result ma_linear_resampler_init(const ma_linear_resampler_config* pConfig, ma_linear_resampler* pResampler)
38341 {
38342     ma_result result;
38343
38344     if (pResampler == NULL) {
38345         return MA_INVALID_ARGS;
38346     }
38347
38348     MA_ZERO_OBJECT(pResampler);
38349
38350     if (pConfig == NULL) {
38351         return MA_INVALID_ARGS;
38352     }
38353
38354     if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
38355         return MA_INVALID_ARGS;
38356     }
38357
38358     pResampler->config = *pConfig;
38359
38360     /* Setting the rate will set up the filter and time advances for us. */
38361     result = ma_linear_resampler_set_rate_internal(pResampler, pConfig->sampleRateIn, pConfig->sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_FALSE);
38362     if (result != MA_SUCCESS) {
38363         return result;
38364     }
38365
38366     pResampler->inTimeInt  = 1;  /* Set this to one to force an input sample to always be loaded for the first output frame. */
38367     pResampler->inTimeFrac = 0;
38368
38369     return MA_SUCCESS;
38370 }
38371
38372 MA_API void ma_linear_resampler_uninit(ma_linear_resampler* pResampler)
38373 {
38374     if (pResampler == NULL) {
38375         return;
38376     }
38377 }
38378
38379 static MA_INLINE ma_int16 ma_linear_resampler_mix_s16(ma_int16 x, ma_int16 y, ma_int32 a, const ma_int32 shift)
38380 {
38381     ma_int32 b;
38382     ma_int32 c;
38383     ma_int32 r;
38384
38385     MA_ASSERT(a <= (1<<shift));
38386
38387     b = x * ((1<<shift) - a);
38388     c = y * a;
38389     r = b + c;
38390
38391     return (ma_int16)(r >> shift);
38392 }
38393
38394 static void ma_linear_resampler_interpolate_frame_s16(ma_linear_resampler* pResampler, ma_int16* MA_RESTRICT pFrameOut)
38395 {
38396     ma_uint32 c;
38397     ma_uint32 a;
38398     const ma_uint32 channels = pResampler->config.channels;
38399     const ma_uint32 shift = 12;
38400
38401     MA_ASSERT(pResampler != NULL);
38402     MA_ASSERT(pFrameOut  != NULL);
38403
38404     a = (pResampler->inTimeFrac << shift) / pResampler->config.sampleRateOut;
38405
38406     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
38407     for (c = 0; c < channels; c += 1) {
38408         ma_int16 s = ma_linear_resampler_mix_s16(pResampler->x0.s16[c], pResampler->x1.s16[c], a, shift);
38409         pFrameOut[c] = s;
38410     }
38411 }
38412
38413
38414 static void ma_linear_resampler_interpolate_frame_f32(ma_linear_resampler* pResampler, float* MA_RESTRICT pFrameOut)
38415 {
38416     ma_uint32 c;
38417     float a;
38418     const ma_uint32 channels = pResampler->config.channels;
38419
38420     MA_ASSERT(pResampler != NULL);
38421     MA_ASSERT(pFrameOut  != NULL);
38422
38423     a = (float)pResampler->inTimeFrac / pResampler->config.sampleRateOut;
38424
38425     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
38426     for (c = 0; c < channels; c += 1) {
38427         float s = ma_mix_f32_fast(pResampler->x0.f32[c], pResampler->x1.f32[c], a);
38428         pFrameOut[c] = s;
38429     }
38430 }
38431
38432 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)
38433 {
38434     const ma_int16* pFramesInS16;
38435     /* */ ma_int16* pFramesOutS16;
38436     ma_uint64 frameCountIn;
38437     ma_uint64 frameCountOut;
38438     ma_uint64 framesProcessedIn;
38439     ma_uint64 framesProcessedOut;
38440
38441     MA_ASSERT(pResampler     != NULL);
38442     MA_ASSERT(pFrameCountIn  != NULL);
38443     MA_ASSERT(pFrameCountOut != NULL);
38444
38445     pFramesInS16       = (const ma_int16*)pFramesIn;
38446     pFramesOutS16      = (      ma_int16*)pFramesOut;
38447     frameCountIn       = *pFrameCountIn;
38448     frameCountOut      = *pFrameCountOut;
38449     framesProcessedIn  = 0;
38450     framesProcessedOut = 0;
38451
38452     while (framesProcessedOut < frameCountOut) {
38453         /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
38454         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
38455             ma_uint32 iChannel;
38456
38457             if (pFramesInS16 != NULL) {
38458                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38459                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
38460                     pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
38461                 }
38462                 pFramesInS16 += pResampler->config.channels;
38463             } else {
38464                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38465                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
38466                     pResampler->x1.s16[iChannel] = 0;
38467                 }
38468             }
38469
38470             /* Filter. */
38471             ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pResampler->x1.s16, pResampler->x1.s16);
38472
38473             framesProcessedIn     += 1;
38474             pResampler->inTimeInt -= 1;
38475         }
38476
38477         if (pResampler->inTimeInt > 0) {
38478             break;  /* Ran out of input data. */
38479         }
38480
38481         /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */
38482         if (pFramesOutS16 != NULL) {
38483             MA_ASSERT(pResampler->inTimeInt == 0);
38484             ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
38485
38486             pFramesOutS16 += pResampler->config.channels;
38487         }
38488
38489         framesProcessedOut += 1;
38490
38491         /* Advance time forward. */
38492         pResampler->inTimeInt  += pResampler->inAdvanceInt;
38493         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
38494         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
38495             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
38496             pResampler->inTimeInt  += 1;
38497         }
38498     }
38499
38500     *pFrameCountIn  = framesProcessedIn;
38501     *pFrameCountOut = framesProcessedOut;
38502
38503     return MA_SUCCESS;
38504 }
38505
38506 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)
38507 {
38508     const ma_int16* pFramesInS16;
38509     /* */ ma_int16* pFramesOutS16;
38510     ma_uint64 frameCountIn;
38511     ma_uint64 frameCountOut;
38512     ma_uint64 framesProcessedIn;
38513     ma_uint64 framesProcessedOut;
38514
38515     MA_ASSERT(pResampler     != NULL);
38516     MA_ASSERT(pFrameCountIn  != NULL);
38517     MA_ASSERT(pFrameCountOut != NULL);
38518
38519     pFramesInS16       = (const ma_int16*)pFramesIn;
38520     pFramesOutS16      = (      ma_int16*)pFramesOut;
38521     frameCountIn       = *pFrameCountIn;
38522     frameCountOut      = *pFrameCountOut;
38523     framesProcessedIn  = 0;
38524     framesProcessedOut = 0;
38525
38526     while (framesProcessedOut < frameCountOut) {
38527         /* Before interpolating we need to load the buffers. */
38528         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
38529             ma_uint32 iChannel;
38530
38531             if (pFramesInS16 != NULL) {
38532                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38533                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
38534                     pResampler->x1.s16[iChannel] = pFramesInS16[iChannel];
38535                 }
38536                 pFramesInS16 += pResampler->config.channels;
38537             } else {
38538                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38539                     pResampler->x0.s16[iChannel] = pResampler->x1.s16[iChannel];
38540                     pResampler->x1.s16[iChannel] = 0;
38541                 }
38542             }
38543
38544             framesProcessedIn     += 1;
38545             pResampler->inTimeInt -= 1;
38546         }
38547
38548         if (pResampler->inTimeInt > 0) {
38549             break;  /* Ran out of input data. */
38550         }
38551
38552         /* Getting here means the frames have been loaded and we can generate the next output frame. */
38553         if (pFramesOutS16 != NULL) {
38554             MA_ASSERT(pResampler->inTimeInt == 0);
38555             ma_linear_resampler_interpolate_frame_s16(pResampler, pFramesOutS16);
38556
38557             /* Filter. */
38558             ma_lpf_process_pcm_frame_s16(&pResampler->lpf, pFramesOutS16, pFramesOutS16);
38559
38560             pFramesOutS16 += pResampler->config.channels;
38561         }
38562
38563         framesProcessedOut += 1;
38564
38565         /* Advance time forward. */
38566         pResampler->inTimeInt  += pResampler->inAdvanceInt;
38567         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
38568         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
38569             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
38570             pResampler->inTimeInt  += 1;
38571         }
38572     }
38573
38574     *pFrameCountIn  = framesProcessedIn;
38575     *pFrameCountOut = framesProcessedOut;
38576
38577     return MA_SUCCESS;
38578 }
38579
38580 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)
38581 {
38582     MA_ASSERT(pResampler != NULL);
38583
38584     if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
38585         return ma_linear_resampler_process_pcm_frames_s16_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
38586     } else {
38587         return ma_linear_resampler_process_pcm_frames_s16_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
38588     }
38589 }
38590
38591
38592 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)
38593 {
38594     const float* pFramesInF32;
38595     /* */ float* pFramesOutF32;
38596     ma_uint64 frameCountIn;
38597     ma_uint64 frameCountOut;
38598     ma_uint64 framesProcessedIn;
38599     ma_uint64 framesProcessedOut;
38600
38601     MA_ASSERT(pResampler     != NULL);
38602     MA_ASSERT(pFrameCountIn  != NULL);
38603     MA_ASSERT(pFrameCountOut != NULL);
38604
38605     pFramesInF32       = (const float*)pFramesIn;
38606     pFramesOutF32      = (      float*)pFramesOut;
38607     frameCountIn       = *pFrameCountIn;
38608     frameCountOut      = *pFrameCountOut;
38609     framesProcessedIn  = 0;
38610     framesProcessedOut = 0;
38611
38612     while (framesProcessedOut < frameCountOut) {
38613         /* Before interpolating we need to load the buffers. When doing this we need to ensure we run every input sample through the filter. */
38614         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
38615             ma_uint32 iChannel;
38616
38617             if (pFramesInF32 != NULL) {
38618                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38619                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
38620                     pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
38621                 }
38622                 pFramesInF32 += pResampler->config.channels;
38623             } else {
38624                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38625                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
38626                     pResampler->x1.f32[iChannel] = 0;
38627                 }
38628             }
38629
38630             /* Filter. */
38631             ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pResampler->x1.f32, pResampler->x1.f32);
38632
38633             framesProcessedIn     += 1;
38634             pResampler->inTimeInt -= 1;
38635         }
38636
38637         if (pResampler->inTimeInt > 0) {
38638             break;  /* Ran out of input data. */
38639         }
38640
38641         /* Getting here means the frames have been loaded and filtered and we can generate the next output frame. */
38642         if (pFramesOutF32 != NULL) {
38643             MA_ASSERT(pResampler->inTimeInt == 0);
38644             ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
38645
38646             pFramesOutF32 += pResampler->config.channels;
38647         }
38648
38649         framesProcessedOut += 1;
38650
38651         /* Advance time forward. */
38652         pResampler->inTimeInt  += pResampler->inAdvanceInt;
38653         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
38654         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
38655             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
38656             pResampler->inTimeInt  += 1;
38657         }
38658     }
38659
38660     *pFrameCountIn  = framesProcessedIn;
38661     *pFrameCountOut = framesProcessedOut;
38662
38663     return MA_SUCCESS;
38664 }
38665
38666 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)
38667 {
38668     const float* pFramesInF32;
38669     /* */ float* pFramesOutF32;
38670     ma_uint64 frameCountIn;
38671     ma_uint64 frameCountOut;
38672     ma_uint64 framesProcessedIn;
38673     ma_uint64 framesProcessedOut;
38674
38675     MA_ASSERT(pResampler     != NULL);
38676     MA_ASSERT(pFrameCountIn  != NULL);
38677     MA_ASSERT(pFrameCountOut != NULL);
38678
38679     pFramesInF32       = (const float*)pFramesIn;
38680     pFramesOutF32      = (      float*)pFramesOut;
38681     frameCountIn       = *pFrameCountIn;
38682     frameCountOut      = *pFrameCountOut;
38683     framesProcessedIn  = 0;
38684     framesProcessedOut = 0;
38685
38686     while (framesProcessedOut < frameCountOut) {
38687         /* Before interpolating we need to load the buffers. */
38688         while (pResampler->inTimeInt > 0 && frameCountIn > framesProcessedIn) {
38689             ma_uint32 iChannel;
38690
38691             if (pFramesInF32 != NULL) {
38692                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38693                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
38694                     pResampler->x1.f32[iChannel] = pFramesInF32[iChannel];
38695                 }
38696                 pFramesInF32 += pResampler->config.channels;
38697             } else {
38698                 for (iChannel = 0; iChannel < pResampler->config.channels; iChannel += 1) {
38699                     pResampler->x0.f32[iChannel] = pResampler->x1.f32[iChannel];
38700                     pResampler->x1.f32[iChannel] = 0;
38701                 }
38702             }
38703
38704             framesProcessedIn     += 1;
38705             pResampler->inTimeInt -= 1;
38706         }
38707
38708         if (pResampler->inTimeInt > 0) {
38709             break;  /* Ran out of input data. */
38710         }
38711
38712         /* Getting here means the frames have been loaded and we can generate the next output frame. */
38713         if (pFramesOutF32 != NULL) {
38714             MA_ASSERT(pResampler->inTimeInt == 0);
38715             ma_linear_resampler_interpolate_frame_f32(pResampler, pFramesOutF32);
38716
38717             /* Filter. */
38718             ma_lpf_process_pcm_frame_f32(&pResampler->lpf, pFramesOutF32, pFramesOutF32);
38719
38720             pFramesOutF32 += pResampler->config.channels;
38721         }
38722
38723         framesProcessedOut += 1;
38724
38725         /* Advance time forward. */
38726         pResampler->inTimeInt  += pResampler->inAdvanceInt;
38727         pResampler->inTimeFrac += pResampler->inAdvanceFrac;
38728         if (pResampler->inTimeFrac >= pResampler->config.sampleRateOut) {
38729             pResampler->inTimeFrac -= pResampler->config.sampleRateOut;
38730             pResampler->inTimeInt  += 1;
38731         }
38732     }
38733
38734     *pFrameCountIn  = framesProcessedIn;
38735     *pFrameCountOut = framesProcessedOut;
38736
38737     return MA_SUCCESS;
38738 }
38739
38740 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)
38741 {
38742     MA_ASSERT(pResampler != NULL);
38743
38744     if (pResampler->config.sampleRateIn > pResampler->config.sampleRateOut) {
38745         return ma_linear_resampler_process_pcm_frames_f32_downsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
38746     } else {
38747         return ma_linear_resampler_process_pcm_frames_f32_upsample(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
38748     }
38749 }
38750
38751
38752 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)
38753 {
38754     if (pResampler == NULL) {
38755         return MA_INVALID_ARGS;
38756     }
38757
38758     /*  */ if (pResampler->config.format == ma_format_s16) {
38759         return ma_linear_resampler_process_pcm_frames_s16(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
38760     } else if (pResampler->config.format == ma_format_f32) {
38761         return ma_linear_resampler_process_pcm_frames_f32(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
38762     } else {
38763         /* 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(). */
38764         MA_ASSERT(MA_FALSE);
38765         return MA_INVALID_ARGS;
38766     }
38767 }
38768
38769
38770 MA_API ma_result ma_linear_resampler_set_rate(ma_linear_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
38771 {
38772     return ma_linear_resampler_set_rate_internal(pResampler, sampleRateIn, sampleRateOut, /* isResamplerAlreadyInitialized = */ MA_TRUE);
38773 }
38774
38775 MA_API ma_result ma_linear_resampler_set_rate_ratio(ma_linear_resampler* pResampler, float ratioInOut)
38776 {
38777     ma_uint32 n;
38778     ma_uint32 d;
38779
38780     d = 1000;
38781     n = (ma_uint32)(ratioInOut * d);
38782
38783     if (n == 0) {
38784         return MA_INVALID_ARGS; /* Ratio too small. */
38785     }
38786
38787     MA_ASSERT(n != 0);
38788
38789     return ma_linear_resampler_set_rate(pResampler, n, d);
38790 }
38791
38792
38793 MA_API ma_uint64 ma_linear_resampler_get_required_input_frame_count(const ma_linear_resampler* pResampler, ma_uint64 outputFrameCount)
38794 {
38795     ma_uint64 inputFrameCount;
38796
38797     if (pResampler == NULL) {
38798         return 0;
38799     }
38800
38801     if (outputFrameCount == 0) {
38802         return 0;
38803     }
38804
38805     /* Any whole input frames are consumed before the first output frame is generated. */
38806     inputFrameCount = pResampler->inTimeInt;
38807     outputFrameCount -= 1;
38808
38809     /* The rest of the output frames can be calculated in constant time. */
38810     inputFrameCount += outputFrameCount * pResampler->inAdvanceInt;
38811     inputFrameCount += (pResampler->inTimeFrac + (outputFrameCount * pResampler->inAdvanceFrac)) / pResampler->config.sampleRateOut;
38812
38813     return inputFrameCount;
38814 }
38815
38816 MA_API ma_uint64 ma_linear_resampler_get_expected_output_frame_count(const ma_linear_resampler* pResampler, ma_uint64 inputFrameCount)
38817 {
38818     ma_uint64 outputFrameCount;
38819     ma_uint64 preliminaryInputFrameCountFromFrac;
38820     ma_uint64 preliminaryInputFrameCount;
38821
38822     if (pResampler == NULL) {
38823         return 0;
38824     }
38825
38826     /*
38827     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
38828     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
38829     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
38830     of an extra output frame. This add-by-one logic is necessary due to how the data loading logic works when processing frames.
38831     */
38832     outputFrameCount = (inputFrameCount * pResampler->config.sampleRateOut) / pResampler->config.sampleRateIn;
38833
38834     /*
38835     We need to determine how many *whole* input frames will have been processed to generate our preliminary output frame count. This is
38836     used in the logic below to determine whether or not we need to add an extra output frame.
38837     */
38838     preliminaryInputFrameCountFromFrac = (pResampler->inTimeFrac + outputFrameCount*pResampler->inAdvanceFrac) / pResampler->config.sampleRateOut;
38839     preliminaryInputFrameCount         = (pResampler->inTimeInt  + outputFrameCount*pResampler->inAdvanceInt ) + preliminaryInputFrameCountFromFrac;
38840
38841     /*
38842     If the total number of *whole* input frames that would be required to generate our preliminary output frame count is greather than
38843     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
38844     to actually process. Otherwise we need to add the extra output frame.
38845     */
38846     if (preliminaryInputFrameCount <= inputFrameCount) {
38847         outputFrameCount += 1;
38848     }
38849
38850     return outputFrameCount;
38851 }
38852
38853 MA_API ma_uint64 ma_linear_resampler_get_input_latency(const ma_linear_resampler* pResampler)
38854 {
38855     if (pResampler == NULL) {
38856         return 0;
38857     }
38858
38859     return 1 + ma_lpf_get_latency(&pResampler->lpf);
38860 }
38861
38862 MA_API ma_uint64 ma_linear_resampler_get_output_latency(const ma_linear_resampler* pResampler)
38863 {
38864     if (pResampler == NULL) {
38865         return 0;
38866     }
38867
38868     return ma_linear_resampler_get_input_latency(pResampler) * pResampler->config.sampleRateOut / pResampler->config.sampleRateIn;
38869 }
38870
38871
38872 #if defined(ma_speex_resampler_h)
38873 #define MA_HAS_SPEEX_RESAMPLER
38874
38875 static ma_result ma_result_from_speex_err(int err)
38876 {
38877     switch (err)
38878     {
38879         case RESAMPLER_ERR_SUCCESS:      return MA_SUCCESS;
38880         case RESAMPLER_ERR_ALLOC_FAILED: return MA_OUT_OF_MEMORY;
38881         case RESAMPLER_ERR_BAD_STATE:    return MA_ERROR;
38882         case RESAMPLER_ERR_INVALID_ARG:  return MA_INVALID_ARGS;
38883         case RESAMPLER_ERR_PTR_OVERLAP:  return MA_INVALID_ARGS;
38884         case RESAMPLER_ERR_OVERFLOW:     return MA_ERROR;
38885         default: return MA_ERROR;
38886     }
38887 }
38888 #endif  /* ma_speex_resampler_h */
38889
38890 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)
38891 {
38892     ma_resampler_config config;
38893
38894     MA_ZERO_OBJECT(&config);
38895     config.format = format;
38896     config.channels = channels;
38897     config.sampleRateIn = sampleRateIn;
38898     config.sampleRateOut = sampleRateOut;
38899     config.algorithm = algorithm;
38900
38901     /* Linear. */
38902     config.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
38903     config.linear.lpfNyquistFactor = 1;
38904
38905     /* Speex. */
38906     config.speex.quality = 3;   /* Cannot leave this as 0 as that is actually a valid value for Speex resampling quality. */
38907
38908     return config;
38909 }
38910
38911 MA_API ma_result ma_resampler_init(const ma_resampler_config* pConfig, ma_resampler* pResampler)
38912 {
38913     ma_result result;
38914
38915     if (pResampler == NULL) {
38916         return MA_INVALID_ARGS;
38917     }
38918
38919     MA_ZERO_OBJECT(pResampler);
38920
38921     if (pConfig == NULL) {
38922         return MA_INVALID_ARGS;
38923     }
38924
38925     if (pConfig->format != ma_format_f32 && pConfig->format != ma_format_s16) {
38926         return MA_INVALID_ARGS;
38927     }
38928
38929     pResampler->config = *pConfig;
38930
38931     switch (pConfig->algorithm)
38932     {
38933         case ma_resample_algorithm_linear:
38934         {
38935             ma_linear_resampler_config linearConfig;
38936             linearConfig = ma_linear_resampler_config_init(pConfig->format, pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut);
38937             linearConfig.lpfOrder         = pConfig->linear.lpfOrder;
38938             linearConfig.lpfNyquistFactor = pConfig->linear.lpfNyquistFactor;
38939
38940             result = ma_linear_resampler_init(&linearConfig, &pResampler->state.linear);
38941             if (result != MA_SUCCESS) {
38942                 return result;
38943             }
38944         } break;
38945
38946         case ma_resample_algorithm_speex:
38947         {
38948         #if defined(MA_HAS_SPEEX_RESAMPLER)
38949             int speexErr;
38950             pResampler->state.speex.pSpeexResamplerState = speex_resampler_init(pConfig->channels, pConfig->sampleRateIn, pConfig->sampleRateOut, pConfig->speex.quality, &speexErr);
38951             if (pResampler->state.speex.pSpeexResamplerState == NULL) {
38952                 return ma_result_from_speex_err(speexErr);
38953             }
38954         #else
38955             /* Speex resampler not available. */
38956             return MA_NO_BACKEND;
38957         #endif
38958         } break;
38959
38960         default: return MA_INVALID_ARGS;
38961     }
38962
38963     return MA_SUCCESS;
38964 }
38965
38966 MA_API void ma_resampler_uninit(ma_resampler* pResampler)
38967 {
38968     if (pResampler == NULL) {
38969         return;
38970     }
38971
38972     if (pResampler->config.algorithm == ma_resample_algorithm_linear) {
38973         ma_linear_resampler_uninit(&pResampler->state.linear);
38974     }
38975
38976 #if defined(MA_HAS_SPEEX_RESAMPLER)
38977     if (pResampler->config.algorithm == ma_resample_algorithm_speex) {
38978         speex_resampler_destroy((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState);
38979     }
38980 #endif
38981 }
38982
38983 static ma_result ma_resampler_process_pcm_frames__read__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
38984 {
38985     return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
38986 }
38987
38988 #if defined(MA_HAS_SPEEX_RESAMPLER)
38989 static ma_result ma_resampler_process_pcm_frames__read__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
38990 {
38991     int speexErr;
38992     ma_uint64 frameCountOut;
38993     ma_uint64 frameCountIn;
38994     ma_uint64 framesProcessedOut;
38995     ma_uint64 framesProcessedIn;
38996     unsigned int framesPerIteration = UINT_MAX;
38997
38998     MA_ASSERT(pResampler     != NULL);
38999     MA_ASSERT(pFramesOut     != NULL);
39000     MA_ASSERT(pFrameCountOut != NULL);
39001     MA_ASSERT(pFrameCountIn  != NULL);
39002
39003     /*
39004     Reading from the Speex resampler requires a bit of dancing around for a few reasons. The first thing is that it's frame counts
39005     are in unsigned int's whereas ours is in ma_uint64. We therefore need to run the conversion in a loop. The other, more complicated
39006     problem, is that we need to keep track of the input time, similar to what we do with the linear resampler. The reason we need to
39007     do this is for ma_resampler_get_required_input_frame_count() and ma_resampler_get_expected_output_frame_count().
39008     */
39009     frameCountOut      = *pFrameCountOut;
39010     frameCountIn       = *pFrameCountIn;
39011     framesProcessedOut = 0;
39012     framesProcessedIn  = 0;
39013
39014     while (framesProcessedOut < frameCountOut && framesProcessedIn < frameCountIn) {
39015         unsigned int frameCountInThisIteration;
39016         unsigned int frameCountOutThisIteration;
39017         const void* pFramesInThisIteration;
39018         void* pFramesOutThisIteration;
39019
39020         frameCountInThisIteration = framesPerIteration;
39021         if ((ma_uint64)frameCountInThisIteration > (frameCountIn - framesProcessedIn)) {
39022             frameCountInThisIteration = (unsigned int)(frameCountIn - framesProcessedIn);
39023         }
39024
39025         frameCountOutThisIteration = framesPerIteration;
39026         if ((ma_uint64)frameCountOutThisIteration > (frameCountOut - framesProcessedOut)) {
39027             frameCountOutThisIteration = (unsigned int)(frameCountOut - framesProcessedOut);
39028         }
39029
39030         pFramesInThisIteration  = ma_offset_ptr(pFramesIn,  framesProcessedIn  * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels));
39031         pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels));
39032
39033         if (pResampler->config.format == ma_format_f32) {
39034             speexErr = speex_resampler_process_interleaved_float((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const float*)pFramesInThisIteration, &frameCountInThisIteration, (float*)pFramesOutThisIteration, &frameCountOutThisIteration);
39035         } else if (pResampler->config.format == ma_format_s16) {
39036             speexErr = speex_resampler_process_interleaved_int((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, (const spx_int16_t*)pFramesInThisIteration, &frameCountInThisIteration, (spx_int16_t*)pFramesOutThisIteration, &frameCountOutThisIteration);
39037         } else {
39038             /* Format not supported. Should never get here. */
39039             MA_ASSERT(MA_FALSE);
39040             return MA_INVALID_OPERATION;
39041         }
39042
39043         if (speexErr != RESAMPLER_ERR_SUCCESS) {
39044             return ma_result_from_speex_err(speexErr);
39045         }
39046
39047         framesProcessedIn  += frameCountInThisIteration;
39048         framesProcessedOut += frameCountOutThisIteration;
39049     }
39050
39051     *pFrameCountOut = framesProcessedOut;
39052     *pFrameCountIn  = framesProcessedIn;
39053
39054     return MA_SUCCESS;
39055 }
39056 #endif
39057
39058 static ma_result ma_resampler_process_pcm_frames__read(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
39059 {
39060     MA_ASSERT(pResampler != NULL);
39061     MA_ASSERT(pFramesOut != NULL);
39062
39063     /* pFramesOut is not NULL, which means we must have a capacity. */
39064     if (pFrameCountOut == NULL) {
39065         return MA_INVALID_ARGS;
39066     }
39067
39068     /* It doesn't make sense to not have any input frames to process. */
39069     if (pFrameCountIn == NULL || pFramesIn == NULL) {
39070         return MA_INVALID_ARGS;
39071     }
39072
39073     switch (pResampler->config.algorithm)
39074     {
39075         case ma_resample_algorithm_linear:
39076         {
39077             return ma_resampler_process_pcm_frames__read__linear(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
39078         }
39079
39080         case ma_resample_algorithm_speex:
39081         {
39082         #if defined(MA_HAS_SPEEX_RESAMPLER)
39083             return ma_resampler_process_pcm_frames__read__speex(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
39084         #else
39085             break;
39086         #endif
39087         }
39088
39089         default: break;
39090     }
39091
39092     /* Should never get here. */
39093     MA_ASSERT(MA_FALSE);
39094     return MA_INVALID_ARGS;
39095 }
39096
39097
39098 static ma_result ma_resampler_process_pcm_frames__seek__linear(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut)
39099 {
39100     MA_ASSERT(pResampler != NULL);
39101
39102     /* Seeking is supported natively by the linear resampler. */
39103     return ma_linear_resampler_process_pcm_frames(&pResampler->state.linear, pFramesIn, pFrameCountIn, NULL, pFrameCountOut);
39104 }
39105
39106 #if defined(MA_HAS_SPEEX_RESAMPLER)
39107 static ma_result ma_resampler_process_pcm_frames__seek__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut)
39108 {
39109     /* The generic seek method is implemented in on top of ma_resampler_process_pcm_frames__read() by just processing into a dummy buffer. */
39110     float devnull[4096];
39111     ma_uint64 totalOutputFramesToProcess;
39112     ma_uint64 totalOutputFramesProcessed;
39113     ma_uint64 totalInputFramesProcessed;
39114     ma_uint32 bpf;
39115     ma_result result;
39116
39117     MA_ASSERT(pResampler != NULL);
39118
39119     totalOutputFramesProcessed = 0;
39120     totalInputFramesProcessed = 0;
39121     bpf = ma_get_bytes_per_frame(pResampler->config.format, pResampler->config.channels);
39122
39123     if (pFrameCountOut != NULL) {
39124         /* Seek by output frames. */
39125         totalOutputFramesToProcess = *pFrameCountOut;
39126     } else {
39127         /* Seek by input frames. */
39128         MA_ASSERT(pFrameCountIn != NULL);
39129         totalOutputFramesToProcess = ma_resampler_get_expected_output_frame_count(pResampler, *pFrameCountIn);
39130     }
39131
39132     if (pFramesIn != NULL) {
39133         /* Process input data. */
39134         MA_ASSERT(pFrameCountIn != NULL);
39135         while (totalOutputFramesProcessed < totalOutputFramesToProcess && totalInputFramesProcessed < *pFrameCountIn) {
39136             ma_uint64 inputFramesToProcessThisIteration  = (*pFrameCountIn - totalInputFramesProcessed);
39137             ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed);
39138             if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) {
39139                 outputFramesToProcessThisIteration = sizeof(devnull) / bpf;
39140             }
39141
39142             result = ma_resampler_process_pcm_frames__read(pResampler, ma_offset_ptr(pFramesIn, totalInputFramesProcessed*bpf), &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration);
39143             if (result != MA_SUCCESS) {
39144                 return result;
39145             }
39146
39147             totalOutputFramesProcessed += outputFramesToProcessThisIteration;
39148             totalInputFramesProcessed  += inputFramesToProcessThisIteration;
39149         }
39150     } else {
39151         /* Don't process input data - just update timing and filter state as if zeroes were passed in. */
39152         while (totalOutputFramesProcessed < totalOutputFramesToProcess) {
39153             ma_uint64 inputFramesToProcessThisIteration  = 16384;
39154             ma_uint64 outputFramesToProcessThisIteration = (totalOutputFramesToProcess - totalOutputFramesProcessed);
39155             if (outputFramesToProcessThisIteration > sizeof(devnull) / bpf) {
39156                 outputFramesToProcessThisIteration = sizeof(devnull) / bpf;
39157             }
39158
39159             result = ma_resampler_process_pcm_frames__read(pResampler, NULL, &inputFramesToProcessThisIteration, ma_offset_ptr(devnull, totalOutputFramesProcessed*bpf), &outputFramesToProcessThisIteration);
39160             if (result != MA_SUCCESS) {
39161                 return result;
39162             }
39163
39164             totalOutputFramesProcessed += outputFramesToProcessThisIteration;
39165             totalInputFramesProcessed  += inputFramesToProcessThisIteration;
39166         }
39167     }
39168
39169
39170     if (pFrameCountIn != NULL) {
39171         *pFrameCountIn = totalInputFramesProcessed;
39172     }
39173     if (pFrameCountOut != NULL) {
39174         *pFrameCountOut = totalOutputFramesProcessed;
39175     }
39176
39177     return MA_SUCCESS;
39178 }
39179 #endif
39180
39181 static ma_result ma_resampler_process_pcm_frames__seek(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut)
39182 {
39183     MA_ASSERT(pResampler != NULL);
39184
39185     switch (pResampler->config.algorithm)
39186     {
39187         case ma_resample_algorithm_linear:
39188         {
39189             return ma_resampler_process_pcm_frames__seek__linear(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut);
39190         } break;
39191
39192         case ma_resample_algorithm_speex:
39193         {
39194         #if defined(MA_HAS_SPEEX_RESAMPLER)
39195             return ma_resampler_process_pcm_frames__seek__speex(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut);
39196         #else
39197             break;
39198         #endif
39199         };
39200
39201         default: break;
39202     }
39203
39204     /* Should never hit this. */
39205     MA_ASSERT(MA_FALSE);
39206     return MA_INVALID_ARGS;
39207 }
39208
39209
39210 MA_API ma_result ma_resampler_process_pcm_frames(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
39211 {
39212     if (pResampler == NULL) {
39213         return MA_INVALID_ARGS;
39214     }
39215
39216     if (pFrameCountOut == NULL && pFrameCountIn == NULL) {
39217         return MA_INVALID_ARGS;
39218     }
39219
39220     if (pFramesOut != NULL) {
39221         /* Reading. */
39222         return ma_resampler_process_pcm_frames__read(pResampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
39223     } else {
39224         /* Seeking. */
39225         return ma_resampler_process_pcm_frames__seek(pResampler, pFramesIn, pFrameCountIn, pFrameCountOut);
39226     }
39227 }
39228
39229 MA_API ma_result ma_resampler_set_rate(ma_resampler* pResampler, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
39230 {
39231     if (pResampler == NULL) {
39232         return MA_INVALID_ARGS;
39233     }
39234
39235     if (sampleRateIn == 0 || sampleRateOut == 0) {
39236         return MA_INVALID_ARGS;
39237     }
39238
39239     pResampler->config.sampleRateIn  = sampleRateIn;
39240     pResampler->config.sampleRateOut = sampleRateOut;
39241
39242     switch (pResampler->config.algorithm)
39243     {
39244         case ma_resample_algorithm_linear:
39245         {
39246             return ma_linear_resampler_set_rate(&pResampler->state.linear, sampleRateIn, sampleRateOut);
39247         } break;
39248
39249         case ma_resample_algorithm_speex:
39250         {
39251         #if defined(MA_HAS_SPEEX_RESAMPLER)
39252             return ma_result_from_speex_err(speex_resampler_set_rate((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, sampleRateIn, sampleRateOut));
39253         #else
39254             break;
39255         #endif
39256         };
39257
39258         default: break;
39259     }
39260
39261     /* Should never get here. */
39262     MA_ASSERT(MA_FALSE);
39263     return MA_INVALID_OPERATION;
39264 }
39265
39266 MA_API ma_result ma_resampler_set_rate_ratio(ma_resampler* pResampler, float ratio)
39267 {
39268     if (pResampler == NULL) {
39269         return MA_INVALID_ARGS;
39270     }
39271
39272     if (pResampler->config.algorithm == ma_resample_algorithm_linear) {
39273         return ma_linear_resampler_set_rate_ratio(&pResampler->state.linear, ratio);
39274     } else {
39275         /* Getting here means the backend does not have native support for setting the rate as a ratio so we just do it generically. */
39276         ma_uint32 n;
39277         ma_uint32 d;
39278
39279         d = 1000;
39280         n = (ma_uint32)(ratio * d);
39281
39282         if (n == 0) {
39283             return MA_INVALID_ARGS; /* Ratio too small. */
39284         }
39285
39286         MA_ASSERT(n != 0);
39287
39288         return ma_resampler_set_rate(pResampler, n, d);
39289     }
39290 }
39291
39292 MA_API ma_uint64 ma_resampler_get_required_input_frame_count(const ma_resampler* pResampler, ma_uint64 outputFrameCount)
39293 {
39294     if (pResampler == NULL) {
39295         return 0;
39296     }
39297
39298     if (outputFrameCount == 0) {
39299         return 0;
39300     }
39301
39302     switch (pResampler->config.algorithm)
39303     {
39304         case ma_resample_algorithm_linear:
39305         {
39306             return ma_linear_resampler_get_required_input_frame_count(&pResampler->state.linear, outputFrameCount);
39307         }
39308
39309         case ma_resample_algorithm_speex:
39310         {
39311         #if defined(MA_HAS_SPEEX_RESAMPLER)
39312             spx_uint64_t count;
39313             int speexErr = ma_speex_resampler_get_required_input_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, outputFrameCount, &count);
39314             if (speexErr != RESAMPLER_ERR_SUCCESS) {
39315                 return 0;
39316             }
39317
39318             return (ma_uint64)count;
39319         #else
39320             break;
39321         #endif
39322         }
39323
39324         default: break;
39325     }
39326
39327     /* Should never get here. */
39328     MA_ASSERT(MA_FALSE);
39329     return 0;
39330 }
39331
39332 MA_API ma_uint64 ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount)
39333 {
39334     if (pResampler == NULL) {
39335         return 0;   /* Invalid args. */
39336     }
39337
39338     if (inputFrameCount == 0) {
39339         return 0;
39340     }
39341
39342     switch (pResampler->config.algorithm)
39343     {
39344         case ma_resample_algorithm_linear:
39345         {
39346             return ma_linear_resampler_get_expected_output_frame_count(&pResampler->state.linear, inputFrameCount);
39347         }
39348
39349         case ma_resample_algorithm_speex:
39350         {
39351         #if defined(MA_HAS_SPEEX_RESAMPLER)
39352             spx_uint64_t count;
39353             int speexErr = ma_speex_resampler_get_expected_output_frame_count((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState, inputFrameCount, &count);
39354             if (speexErr != RESAMPLER_ERR_SUCCESS) {
39355                 return 0;
39356             }
39357
39358             return (ma_uint64)count;
39359         #else
39360             break;
39361         #endif
39362         }
39363
39364         default: break;
39365     }
39366
39367     /* Should never get here. */
39368     MA_ASSERT(MA_FALSE);
39369     return 0;
39370 }
39371
39372 MA_API ma_uint64 ma_resampler_get_input_latency(const ma_resampler* pResampler)
39373 {
39374     if (pResampler == NULL) {
39375         return 0;
39376     }
39377
39378     switch (pResampler->config.algorithm)
39379     {
39380         case ma_resample_algorithm_linear:
39381         {
39382             return ma_linear_resampler_get_input_latency(&pResampler->state.linear);
39383         }
39384
39385         case ma_resample_algorithm_speex:
39386         {
39387         #if defined(MA_HAS_SPEEX_RESAMPLER)
39388             return (ma_uint64)ma_speex_resampler_get_input_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState);
39389         #else
39390             break;
39391         #endif
39392         }
39393
39394         default: break;
39395     }
39396
39397     /* Should never get here. */
39398     MA_ASSERT(MA_FALSE);
39399     return 0;
39400 }
39401
39402 MA_API ma_uint64 ma_resampler_get_output_latency(const ma_resampler* pResampler)
39403 {
39404     if (pResampler == NULL) {
39405         return 0;
39406     }
39407
39408     switch (pResampler->config.algorithm)
39409     {
39410         case ma_resample_algorithm_linear:
39411         {
39412             return ma_linear_resampler_get_output_latency(&pResampler->state.linear);
39413         }
39414
39415         case ma_resample_algorithm_speex:
39416         {
39417         #if defined(MA_HAS_SPEEX_RESAMPLER)
39418             return (ma_uint64)ma_speex_resampler_get_output_latency((SpeexResamplerState*)pResampler->state.speex.pSpeexResamplerState);
39419         #else
39420             break;
39421         #endif
39422         }
39423
39424         default: break;
39425     }
39426
39427     /* Should never get here. */
39428     MA_ASSERT(MA_FALSE);
39429     return 0;
39430 }
39431
39432 /**************************************************************************************************************************************************************
39433
39434 Channel Conversion
39435
39436 **************************************************************************************************************************************************************/
39437 #ifndef MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT
39438 #define MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT  12
39439 #endif
39440
39441 #define MA_PLANE_LEFT      0
39442 #define MA_PLANE_RIGHT     1
39443 #define MA_PLANE_FRONT     2
39444 #define MA_PLANE_BACK      3
39445 #define MA_PLANE_BOTTOM    4
39446 #define MA_PLANE_TOP       5
39447
39448 static float g_maChannelPlaneRatios[MA_CHANNEL_POSITION_COUNT][6] = {
39449     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_NONE */
39450     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_MONO */
39451     { 0.5f,  0.0f,  0.5f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_LEFT */
39452     { 0.0f,  0.5f,  0.5f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_RIGHT */
39453     { 0.0f,  0.0f,  1.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_CENTER */
39454     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_LFE */
39455     { 0.5f,  0.0f,  0.0f,  0.5f,  0.0f,  0.0f},  /* MA_CHANNEL_BACK_LEFT */
39456     { 0.0f,  0.5f,  0.0f,  0.5f,  0.0f,  0.0f},  /* MA_CHANNEL_BACK_RIGHT */
39457     { 0.25f, 0.0f,  0.75f, 0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_LEFT_CENTER */
39458     { 0.0f,  0.25f, 0.75f, 0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_FRONT_RIGHT_CENTER */
39459     { 0.0f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f},  /* MA_CHANNEL_BACK_CENTER */
39460     { 1.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_SIDE_LEFT */
39461     { 0.0f,  1.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_SIDE_RIGHT */
39462     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  1.0f},  /* MA_CHANNEL_TOP_CENTER */
39463     { 0.33f, 0.0f,  0.33f, 0.0f,  0.0f,  0.34f}, /* MA_CHANNEL_TOP_FRONT_LEFT */
39464     { 0.0f,  0.0f,  0.5f,  0.0f,  0.0f,  0.5f},  /* MA_CHANNEL_TOP_FRONT_CENTER */
39465     { 0.0f,  0.33f, 0.33f, 0.0f,  0.0f,  0.34f}, /* MA_CHANNEL_TOP_FRONT_RIGHT */
39466     { 0.33f, 0.0f,  0.0f,  0.33f, 0.0f,  0.34f}, /* MA_CHANNEL_TOP_BACK_LEFT */
39467     { 0.0f,  0.0f,  0.0f,  0.5f,  0.0f,  0.5f},  /* MA_CHANNEL_TOP_BACK_CENTER */
39468     { 0.0f,  0.33f, 0.0f,  0.33f, 0.0f,  0.34f}, /* MA_CHANNEL_TOP_BACK_RIGHT */
39469     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_0 */
39470     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_1 */
39471     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_2 */
39472     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_3 */
39473     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_4 */
39474     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_5 */
39475     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_6 */
39476     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_7 */
39477     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_8 */
39478     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_9 */
39479     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_10 */
39480     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_11 */
39481     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_12 */
39482     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_13 */
39483     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_14 */
39484     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_15 */
39485     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_16 */
39486     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_17 */
39487     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_18 */
39488     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_19 */
39489     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_20 */
39490     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_21 */
39491     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_22 */
39492     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_23 */
39493     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_24 */
39494     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_25 */
39495     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_26 */
39496     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_27 */
39497     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_28 */
39498     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_29 */
39499     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_30 */
39500     { 0.0f,  0.0f,  0.0f,  0.0f,  0.0f,  0.0f},  /* MA_CHANNEL_AUX_31 */
39501 };
39502
39503 static float ma_calculate_channel_position_rectangular_weight(ma_channel channelPositionA, ma_channel channelPositionB)
39504 {
39505     /*
39506     Imagine the following simplified example: You have a single input speaker which is the front/left speaker which you want to convert to
39507     the following output configuration:
39508
39509      - front/left
39510      - side/left
39511      - back/left
39512
39513     The front/left output is easy - it the same speaker position so it receives the full contribution of the front/left input. The amount
39514     of contribution to apply to the side/left and back/left speakers, however, is a bit more complicated.
39515
39516     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
39517     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
39518     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
39519     receive some amount of contribution from front/left speaker. The amount of contribution depends on how many planes are shared between
39520     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
39521     across 3 spatial dimensions.
39522
39523     The first thing to do is figure out how each speaker's volume is spread over each of plane:
39524      - front/left:     2 planes (front and left)      = 1/2 = half it's total volume on each plane
39525      - side/left:      1 plane (left only)            = 1/1 = entire volume from left plane
39526      - back/left:      2 planes (back and left)       = 1/2 = half it's total volume on each plane
39527      - top/front/left: 3 planes (top, front and left) = 1/3 = one third it's total volume on each plane
39528
39529     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
39530     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
39531     taken by the other to produce the final contribution.
39532     */
39533
39534     /* Contribution = Sum(Volume to Give * Volume to Take) */
39535     float contribution =
39536         g_maChannelPlaneRatios[channelPositionA][0] * g_maChannelPlaneRatios[channelPositionB][0] +
39537         g_maChannelPlaneRatios[channelPositionA][1] * g_maChannelPlaneRatios[channelPositionB][1] +
39538         g_maChannelPlaneRatios[channelPositionA][2] * g_maChannelPlaneRatios[channelPositionB][2] +
39539         g_maChannelPlaneRatios[channelPositionA][3] * g_maChannelPlaneRatios[channelPositionB][3] +
39540         g_maChannelPlaneRatios[channelPositionA][4] * g_maChannelPlaneRatios[channelPositionB][4] +
39541         g_maChannelPlaneRatios[channelPositionA][5] * g_maChannelPlaneRatios[channelPositionB][5];
39542
39543     return contribution;
39544 }
39545
39546 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)
39547 {
39548     ma_channel_converter_config config;
39549
39550     /* Channel counts need to be clamped. */
39551     channelsIn  = ma_min(channelsIn,  ma_countof(config.channelMapIn));
39552     channelsOut = ma_min(channelsOut, ma_countof(config.channelMapOut));
39553
39554     MA_ZERO_OBJECT(&config);
39555     config.format      = format;
39556     config.channelsIn  = channelsIn;
39557     config.channelsOut = channelsOut;
39558     ma_channel_map_copy_or_default(config.channelMapIn,  pChannelMapIn,  channelsIn);
39559     ma_channel_map_copy_or_default(config.channelMapOut, pChannelMapOut, channelsOut);
39560     config.mixingMode  = mixingMode;
39561
39562     return config;
39563 }
39564
39565 static ma_int32 ma_channel_converter_float_to_fixed(float x)
39566 {
39567     return (ma_int32)(x * (1<<MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT));
39568 }
39569
39570 static ma_bool32 ma_is_spatial_channel_position(ma_channel channelPosition)
39571 {
39572     int i;
39573
39574     if (channelPosition == MA_CHANNEL_NONE || channelPosition == MA_CHANNEL_MONO || channelPosition == MA_CHANNEL_LFE) {
39575         return MA_FALSE;
39576     }
39577
39578     for (i = 0; i < 6; ++i) {   /* Each side of a cube. */
39579         if (g_maChannelPlaneRatios[channelPosition][i] != 0) {
39580             return MA_TRUE;
39581         }
39582     }
39583
39584     return MA_FALSE;
39585 }
39586
39587 MA_API ma_result ma_channel_converter_init(const ma_channel_converter_config* pConfig, ma_channel_converter* pConverter)
39588 {
39589     ma_uint32 iChannelIn;
39590     ma_uint32 iChannelOut;
39591
39592     if (pConverter == NULL) {
39593         return MA_INVALID_ARGS;
39594     }
39595
39596     MA_ZERO_OBJECT(pConverter);
39597
39598     if (pConfig == NULL) {
39599         return MA_INVALID_ARGS;
39600     }
39601
39602     /* Basic validation for channel counts. */
39603     if (pConfig->channelsIn  < MA_MIN_CHANNELS || pConfig->channelsIn  > MA_MAX_CHANNELS ||
39604         pConfig->channelsOut < MA_MIN_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) {
39605         return MA_INVALID_ARGS;
39606     }
39607
39608     if (!ma_channel_map_valid(pConfig->channelsIn, pConfig->channelMapIn)) {
39609         return MA_INVALID_ARGS; /* Invalid input channel map. */
39610     }
39611     if (!ma_channel_map_valid(pConfig->channelsOut, pConfig->channelMapOut)) {
39612         return MA_INVALID_ARGS; /* Invalid output channel map. */
39613     }
39614
39615     pConverter->format      = pConfig->format;
39616     pConverter->channelsIn  = pConfig->channelsIn;
39617     pConverter->channelsOut = pConfig->channelsOut;
39618     ma_channel_map_copy(pConverter->channelMapIn,  pConfig->channelMapIn,  pConfig->channelsIn);
39619     ma_channel_map_copy(pConverter->channelMapOut, pConfig->channelMapOut, pConfig->channelsOut);
39620     pConverter->mixingMode  = pConfig->mixingMode;
39621
39622     for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; iChannelIn += 1) {
39623         for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39624             if (pConverter->format == ma_format_f32) {
39625                 pConverter->weights.f32[iChannelIn][iChannelOut] = pConfig->weights[iChannelIn][iChannelOut];
39626             } else {
39627                 pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(pConfig->weights[iChannelIn][iChannelOut]);
39628             }
39629         }
39630     }
39631
39632
39633
39634     /* If the input and output channels and channel maps are the same we should use a passthrough. */
39635     if (pConverter->channelsIn == pConverter->channelsOut) {
39636         if (ma_channel_map_equal(pConverter->channelsIn, pConverter->channelMapIn, pConverter->channelMapOut)) {
39637             pConverter->isPassthrough = MA_TRUE;
39638         }
39639         if (ma_channel_map_blank(pConverter->channelsIn, pConverter->channelMapIn) || ma_channel_map_blank(pConverter->channelsOut, pConverter->channelMapOut)) {
39640             pConverter->isPassthrough = MA_TRUE;
39641         }
39642     }
39643
39644
39645     /*
39646     We can use a simple case for expanding the mono channel. This will used when expanding a mono input into any output so long
39647     as no LFE is present in the output.
39648     */
39649     if (!pConverter->isPassthrough) {
39650         if (pConverter->channelsIn == 1 && pConverter->channelMapIn[0] == MA_CHANNEL_MONO) {
39651             /* Optimal case if no LFE is in the output channel map. */
39652             pConverter->isSimpleMonoExpansion = MA_TRUE;
39653             if (ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, MA_CHANNEL_LFE)) {
39654                 pConverter->isSimpleMonoExpansion = MA_FALSE;
39655             }
39656         }
39657     }
39658
39659     /* Another optimized case is stereo to mono. */
39660     if (!pConverter->isPassthrough) {
39661         if (pConverter->channelsOut == 1 && pConverter->channelMapOut[0] == MA_CHANNEL_MONO && pConverter->channelsIn == 2) {
39662             /* Optimal case if no LFE is in the input channel map. */
39663             pConverter->isStereoToMono = MA_TRUE;
39664             if (ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, MA_CHANNEL_LFE)) {
39665                 pConverter->isStereoToMono = MA_FALSE;
39666             }
39667         }
39668     }
39669
39670
39671     /*
39672     Here is where we do a bit of pre-processing to know how each channel should be combined to make up the output. Rules:
39673
39674         1) If it's a passthrough, do nothing - it's just a simple memcpy().
39675         2) If the channel counts are the same and every channel position in the input map is present in the output map, use a
39676            simple shuffle. An example might be different 5.1 channel layouts.
39677         3) Otherwise channels are blended based on spatial locality.
39678     */
39679     if (!pConverter->isPassthrough) {
39680         if (pConverter->channelsIn == pConverter->channelsOut) {
39681             ma_bool32 areAllChannelPositionsPresent = MA_TRUE;
39682             for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39683                 ma_bool32 isInputChannelPositionInOutput = MA_FALSE;
39684                 for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39685                     if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) {
39686                         isInputChannelPositionInOutput = MA_TRUE;
39687                         break;
39688                     }
39689                 }
39690
39691                 if (!isInputChannelPositionInOutput) {
39692                     areAllChannelPositionsPresent = MA_FALSE;
39693                     break;
39694                 }
39695             }
39696
39697             if (areAllChannelPositionsPresent) {
39698                 pConverter->isSimpleShuffle = MA_TRUE;
39699
39700                 /*
39701                 All the router will be doing is rearranging channels which means all we need to do is use a shuffling table which is just
39702                 a mapping between the index of the input channel to the index of the output channel.
39703                 */
39704                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39705                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39706                         if (pConverter->channelMapIn[iChannelIn] == pConverter->channelMapOut[iChannelOut]) {
39707                             pConverter->shuffleTable[iChannelIn] = (ma_uint8)iChannelOut;
39708                             break;
39709                         }
39710                     }
39711                 }
39712             }
39713         }
39714     }
39715
39716
39717     /*
39718     Here is where weights are calculated. Note that we calculate the weights at all times, even when using a passthrough and simple
39719     shuffling. We use different algorithms for calculating weights depending on our mixing mode.
39720
39721     In simple mode we don't do any blending (except for converting between mono, which is done in a later step). Instead we just
39722     map 1:1 matching channels. In this mode, if no channels in the input channel map correspond to anything in the output channel
39723     map, nothing will be heard!
39724     */
39725
39726     /* In all cases we need to make sure all channels that are present in both channel maps have a 1:1 mapping. */
39727     for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39728         ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
39729
39730         for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39731             ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
39732
39733             if (channelPosIn == channelPosOut) {
39734                 if (pConverter->format == ma_format_f32) {
39735                     pConverter->weights.f32[iChannelIn][iChannelOut] = 1;
39736                 } else {
39737                     pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT);
39738                 }
39739             }
39740         }
39741     }
39742
39743     /*
39744     The mono channel is accumulated on all other channels, except LFE. Make sure in this loop we exclude output mono channels since
39745     they were handled in the pass above.
39746     */
39747     for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39748         ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
39749
39750         if (channelPosIn == MA_CHANNEL_MONO) {
39751             for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39752                 ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
39753
39754                 if (channelPosOut != MA_CHANNEL_NONE && channelPosOut != MA_CHANNEL_MONO && channelPosOut != MA_CHANNEL_LFE) {
39755                     if (pConverter->format == ma_format_f32) {
39756                         pConverter->weights.f32[iChannelIn][iChannelOut] = 1;
39757                     } else {
39758                         pConverter->weights.s16[iChannelIn][iChannelOut] = (1 << MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT);
39759                     }
39760                 }
39761             }
39762         }
39763     }
39764
39765     /* The output mono channel is the average of all non-none, non-mono and non-lfe input channels. */
39766     {
39767         ma_uint32 len = 0;
39768         for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39769             ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
39770
39771             if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) {
39772                 len += 1;
39773             }
39774         }
39775
39776         if (len > 0) {
39777             float monoWeight = 1.0f / len;
39778
39779             for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39780                 ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
39781
39782                 if (channelPosOut == MA_CHANNEL_MONO) {
39783                     for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39784                         ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
39785
39786                         if (channelPosIn != MA_CHANNEL_NONE && channelPosIn != MA_CHANNEL_MONO && channelPosIn != MA_CHANNEL_LFE) {
39787                             if (pConverter->format == ma_format_f32) {
39788                                 pConverter->weights.f32[iChannelIn][iChannelOut] = monoWeight;
39789                             } else {
39790                                 pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(monoWeight);
39791                             }
39792                         }
39793                     }
39794                 }
39795             }
39796         }
39797     }
39798
39799
39800     /* Input and output channels that are not present on the other side need to be blended in based on spatial locality. */
39801     switch (pConverter->mixingMode)
39802     {
39803         case ma_channel_mix_mode_rectangular:
39804         {
39805             /* Unmapped input channels. */
39806             for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39807                 ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
39808
39809                 if (ma_is_spatial_channel_position(channelPosIn)) {
39810                     if (!ma_channel_map_contains_channel_position(pConverter->channelsOut, pConverter->channelMapOut, channelPosIn)) {
39811                         for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39812                             ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
39813
39814                             if (ma_is_spatial_channel_position(channelPosOut)) {
39815                                 float weight = 0;
39816                                 if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) {
39817                                     weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut);
39818                                 }
39819
39820                                 /* Only apply the weight if we haven't already got some contribution from the respective channels. */
39821                                 if (pConverter->format == ma_format_f32) {
39822                                     if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) {
39823                                         pConverter->weights.f32[iChannelIn][iChannelOut] = weight;
39824                                     }
39825                                 } else {
39826                                     if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) {
39827                                         pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight);
39828                                     }
39829                                 }
39830                             }
39831                         }
39832                     }
39833                 }
39834             }
39835
39836             /* Unmapped output channels. */
39837             for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
39838                 ma_channel channelPosOut = pConverter->channelMapOut[iChannelOut];
39839
39840                 if (ma_is_spatial_channel_position(channelPosOut)) {
39841                     if (!ma_channel_map_contains_channel_position(pConverter->channelsIn, pConverter->channelMapIn, channelPosOut)) {
39842                         for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39843                             ma_channel channelPosIn = pConverter->channelMapIn[iChannelIn];
39844
39845                             if (ma_is_spatial_channel_position(channelPosIn)) {
39846                                 float weight = 0;
39847                                 if (pConverter->mixingMode == ma_channel_mix_mode_rectangular) {
39848                                     weight = ma_calculate_channel_position_rectangular_weight(channelPosIn, channelPosOut);
39849                                 }
39850
39851                                 /* Only apply the weight if we haven't already got some contribution from the respective channels. */
39852                                 if (pConverter->format == ma_format_f32) {
39853                                     if (pConverter->weights.f32[iChannelIn][iChannelOut] == 0) {
39854                                         pConverter->weights.f32[iChannelIn][iChannelOut] = weight;
39855                                     }
39856                                 } else {
39857                                     if (pConverter->weights.s16[iChannelIn][iChannelOut] == 0) {
39858                                         pConverter->weights.s16[iChannelIn][iChannelOut] = ma_channel_converter_float_to_fixed(weight);
39859                                     }
39860                                 }
39861                             }
39862                         }
39863                     }
39864                 }
39865             }
39866         } break;
39867
39868         case ma_channel_mix_mode_simple:
39869         {
39870             /* In simple mode, excess channels need to be silenced or dropped. */
39871             ma_uint32 iChannel;
39872             for (iChannel = 0; iChannel < ma_min(pConverter->channelsIn, pConverter->channelsOut); iChannel += 1) {
39873                 if (pConverter->format == ma_format_f32) {
39874                     if (pConverter->weights.f32[iChannel][iChannel] == 0) {
39875                         pConverter->weights.f32[iChannel][iChannel] = 1;
39876                     }
39877                 } else {
39878                     if (pConverter->weights.s16[iChannel][iChannel] == 0) {
39879                         pConverter->weights.s16[iChannel][iChannel] = ma_channel_converter_float_to_fixed(1);
39880                     }
39881                 }
39882             }
39883         } break;
39884
39885         case ma_channel_mix_mode_custom_weights:
39886         default:
39887         {
39888             /* Fallthrough. */
39889         } break;
39890     }
39891
39892
39893     return MA_SUCCESS;
39894 }
39895
39896 MA_API void ma_channel_converter_uninit(ma_channel_converter* pConverter)
39897 {
39898     if (pConverter == NULL) {
39899         return;
39900     }
39901 }
39902
39903 static ma_result ma_channel_converter_process_pcm_frames__passthrough(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
39904 {
39905     MA_ASSERT(pConverter != NULL);
39906     MA_ASSERT(pFramesOut != NULL);
39907     MA_ASSERT(pFramesIn  != NULL);
39908
39909     ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
39910     return MA_SUCCESS;
39911 }
39912
39913 static ma_result ma_channel_converter_process_pcm_frames__simple_shuffle(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
39914 {
39915     ma_uint32 iFrame;
39916     ma_uint32 iChannelIn;
39917
39918     MA_ASSERT(pConverter != NULL);
39919     MA_ASSERT(pFramesOut != NULL);
39920     MA_ASSERT(pFramesIn  != NULL);
39921     MA_ASSERT(pConverter->channelsIn == pConverter->channelsOut);
39922
39923     switch (pConverter->format)
39924     {
39925         case ma_format_u8:
39926         {
39927             /* */ ma_uint8* pFramesOutU8 = (      ma_uint8*)pFramesOut;
39928             const ma_uint8* pFramesInU8  = (const ma_uint8*)pFramesIn;
39929
39930             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
39931                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39932                     pFramesOutU8[pConverter->shuffleTable[iChannelIn]] = pFramesInU8[iChannelIn];
39933                 }
39934
39935                 pFramesOutU8 += pConverter->channelsOut;
39936                 pFramesInU8  += pConverter->channelsIn;
39937             }
39938         } break;
39939
39940         case ma_format_s16:
39941         {
39942             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
39943             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
39944
39945             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
39946                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39947                     pFramesOutS16[pConverter->shuffleTable[iChannelIn]] = pFramesInS16[iChannelIn];
39948                 }
39949
39950                 pFramesOutS16 += pConverter->channelsOut;
39951                 pFramesInS16  += pConverter->channelsIn;
39952             }
39953         } break;
39954
39955         case ma_format_s24:
39956         {
39957             /* */ ma_uint8* pFramesOutS24 = (      ma_uint8*)pFramesOut;
39958             const ma_uint8* pFramesInS24  = (const ma_uint8*)pFramesIn;
39959
39960             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
39961                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39962                     ma_uint32 iChannelOut = pConverter->shuffleTable[iChannelIn];
39963                     pFramesOutS24[iChannelOut*3 + 0] = pFramesInS24[iChannelIn*3 + 0];
39964                     pFramesOutS24[iChannelOut*3 + 1] = pFramesInS24[iChannelIn*3 + 1];
39965                     pFramesOutS24[iChannelOut*3 + 2] = pFramesInS24[iChannelIn*3 + 2];
39966                 }
39967
39968                 pFramesOutS24 += pConverter->channelsOut*3;
39969                 pFramesInS24  += pConverter->channelsIn*3;
39970             }
39971         } break;
39972
39973         case ma_format_s32:
39974         {
39975             /* */ ma_int32* pFramesOutS32 = (      ma_int32*)pFramesOut;
39976             const ma_int32* pFramesInS32  = (const ma_int32*)pFramesIn;
39977
39978             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
39979                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39980                     pFramesOutS32[pConverter->shuffleTable[iChannelIn]] = pFramesInS32[iChannelIn];
39981                 }
39982
39983                 pFramesOutS32 += pConverter->channelsOut;
39984                 pFramesInS32  += pConverter->channelsIn;
39985             }
39986         } break;
39987
39988         case ma_format_f32:
39989         {
39990             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
39991             const float* pFramesInF32  = (const float*)pFramesIn;
39992
39993             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
39994                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
39995                     pFramesOutF32[pConverter->shuffleTable[iChannelIn]] = pFramesInF32[iChannelIn];
39996                 }
39997
39998                 pFramesOutF32 += pConverter->channelsOut;
39999                 pFramesInF32  += pConverter->channelsIn;
40000             }
40001         } break;
40002
40003         default: return MA_INVALID_OPERATION;   /* Unknown format. */
40004     }
40005
40006     return MA_SUCCESS;
40007 }
40008
40009 static ma_result ma_channel_converter_process_pcm_frames__simple_mono_expansion(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
40010 {
40011     ma_uint64 iFrame;
40012
40013     MA_ASSERT(pConverter != NULL);
40014     MA_ASSERT(pFramesOut != NULL);
40015     MA_ASSERT(pFramesIn  != NULL);
40016     MA_ASSERT(pConverter->channelsIn == 1);
40017
40018     switch (pConverter->format)
40019     {
40020         case ma_format_u8:
40021         {
40022             /* */ ma_uint8* pFramesOutU8 = (      ma_uint8*)pFramesOut;
40023             const ma_uint8* pFramesInU8  = (const ma_uint8*)pFramesIn;
40024
40025             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40026                 ma_uint32 iChannel;
40027                 for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
40028                     pFramesOutU8[iFrame*pConverter->channelsOut + iChannel] = pFramesInU8[iFrame];
40029                 }
40030             }
40031         } break;
40032
40033         case ma_format_s16:
40034         {
40035             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
40036             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
40037
40038             if (pConverter->channelsOut == 2) {
40039                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40040                     pFramesOutS16[iFrame*2 + 0] = pFramesInS16[iFrame];
40041                     pFramesOutS16[iFrame*2 + 1] = pFramesInS16[iFrame];
40042                 }
40043             } else {
40044                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40045                     ma_uint32 iChannel;
40046                     for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
40047                         pFramesOutS16[iFrame*pConverter->channelsOut + iChannel] = pFramesInS16[iFrame];
40048                     }
40049                 }
40050             }
40051         } break;
40052
40053         case ma_format_s24:
40054         {
40055             /* */ ma_uint8* pFramesOutS24 = (      ma_uint8*)pFramesOut;
40056             const ma_uint8* pFramesInS24  = (const ma_uint8*)pFramesIn;
40057
40058             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40059                 ma_uint32 iChannel;
40060                 for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
40061                     ma_uint64 iSampleOut = iFrame*pConverter->channelsOut + iChannel;
40062                     ma_uint64 iSampleIn  = iFrame;
40063                     pFramesOutS24[iSampleOut*3 + 0] = pFramesInS24[iSampleIn*3 + 0];
40064                     pFramesOutS24[iSampleOut*3 + 1] = pFramesInS24[iSampleIn*3 + 1];
40065                     pFramesOutS24[iSampleOut*3 + 2] = pFramesInS24[iSampleIn*3 + 2];
40066                 }
40067             }
40068         } break;
40069
40070         case ma_format_s32:
40071         {
40072             /* */ ma_int32* pFramesOutS32 = (      ma_int32*)pFramesOut;
40073             const ma_int32* pFramesInS32  = (const ma_int32*)pFramesIn;
40074
40075             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40076                 ma_uint32 iChannel;
40077                 for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
40078                     pFramesOutS32[iFrame*pConverter->channelsOut + iChannel] = pFramesInS32[iFrame];
40079                 }
40080             }
40081         } break;
40082
40083         case ma_format_f32:
40084         {
40085             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
40086             const float* pFramesInF32  = (const float*)pFramesIn;
40087
40088             if (pConverter->channelsOut == 2) {
40089                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40090                     pFramesOutF32[iFrame*2 + 0] = pFramesInF32[iFrame];
40091                     pFramesOutF32[iFrame*2 + 1] = pFramesInF32[iFrame];
40092                 }
40093             } else {
40094                 for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40095                     ma_uint32 iChannel;
40096                     for (iChannel = 0; iChannel < pConverter->channelsOut; iChannel += 1) {
40097                         pFramesOutF32[iFrame*pConverter->channelsOut + iChannel] = pFramesInF32[iFrame];
40098                     }
40099                 }
40100             }
40101         } break;
40102
40103         default: return MA_INVALID_OPERATION;   /* Unknown format. */
40104     }
40105
40106     return MA_SUCCESS;
40107 }
40108
40109 static ma_result ma_channel_converter_process_pcm_frames__stereo_to_mono(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
40110 {
40111     ma_uint64 iFrame;
40112
40113     MA_ASSERT(pConverter != NULL);
40114     MA_ASSERT(pFramesOut != NULL);
40115     MA_ASSERT(pFramesIn  != NULL);
40116     MA_ASSERT(pConverter->channelsIn  == 2);
40117     MA_ASSERT(pConverter->channelsOut == 1);
40118
40119     switch (pConverter->format)
40120     {
40121         case ma_format_u8:
40122         {
40123             /* */ ma_uint8* pFramesOutU8 = (      ma_uint8*)pFramesOut;
40124             const ma_uint8* pFramesInU8  = (const ma_uint8*)pFramesIn;
40125
40126             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40127                 pFramesOutU8[iFrame] = ma_clip_u8((ma_int16)((ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*2+0]) + ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8[iFrame*2+1])) / 2));
40128             }
40129         } break;
40130
40131         case ma_format_s16:
40132         {
40133             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
40134             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
40135
40136             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40137                 pFramesOutS16[iFrame] = (ma_int16)(((ma_int32)pFramesInS16[iFrame*2+0] + (ma_int32)pFramesInS16[iFrame*2+1]) / 2);
40138             }
40139         } break;
40140
40141         case ma_format_s24:
40142         {
40143             /* */ ma_uint8* pFramesOutS24 = (      ma_uint8*)pFramesOut;
40144             const ma_uint8* pFramesInS24  = (const ma_uint8*)pFramesIn;
40145
40146             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40147                 ma_int64 s24_0 = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*2+0)*3]);
40148                 ma_int64 s24_1 = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24[(iFrame*2+1)*3]);
40149                 ma_pcm_sample_s32_to_s24_no_scale((s24_0 + s24_1) / 2, &pFramesOutS24[iFrame*3]);
40150             }
40151         } break;
40152
40153         case ma_format_s32:
40154         {
40155             /* */ ma_int32* pFramesOutS32 = (      ma_int32*)pFramesOut;
40156             const ma_int32* pFramesInS32  = (const ma_int32*)pFramesIn;
40157
40158             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40159                 pFramesOutS32[iFrame] = (ma_int16)(((ma_int32)pFramesInS32[iFrame*2+0] + (ma_int32)pFramesInS32[iFrame*2+1]) / 2);
40160             }
40161         } break;
40162
40163         case ma_format_f32:
40164         {
40165             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
40166             const float* pFramesInF32  = (const float*)pFramesIn;
40167
40168             for (iFrame = 0; iFrame < frameCount; ++iFrame) {
40169                 pFramesOutF32[iFrame] = (pFramesInF32[iFrame*2+0] + pFramesInF32[iFrame*2+0]) * 0.5f;
40170             }
40171         } break;
40172
40173         default: return MA_INVALID_OPERATION;   /* Unknown format. */
40174     }
40175
40176     return MA_SUCCESS;
40177 }
40178
40179 static ma_result ma_channel_converter_process_pcm_frames__weights(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
40180 {
40181     ma_uint32 iFrame;
40182     ma_uint32 iChannelIn;
40183     ma_uint32 iChannelOut;
40184
40185     MA_ASSERT(pConverter != NULL);
40186     MA_ASSERT(pFramesOut != NULL);
40187     MA_ASSERT(pFramesIn  != NULL);
40188
40189     /* This is the more complicated case. Each of the output channels is accumulated with 0 or more input channels. */
40190
40191     /* Clear. */
40192     ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
40193
40194     /* Accumulate. */
40195     switch (pConverter->format)
40196     {
40197         case ma_format_u8:
40198         {
40199             /* */ ma_uint8* pFramesOutU8 = (      ma_uint8*)pFramesOut;
40200             const ma_uint8* pFramesInU8  = (const ma_uint8*)pFramesIn;
40201
40202             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40203                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
40204                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
40205                         ma_int16 u8_O = ma_pcm_sample_u8_to_s16_no_scale(pFramesOutU8[iFrame*pConverter->channelsOut + iChannelOut]);
40206                         ma_int16 u8_I = ma_pcm_sample_u8_to_s16_no_scale(pFramesInU8 [iFrame*pConverter->channelsIn  + iChannelIn ]);
40207                         ma_int32 s    = (ma_int32)ma_clamp(u8_O + ((u8_I * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT), -128, 127);
40208                         pFramesOutU8[iFrame*pConverter->channelsOut + iChannelOut] = ma_clip_u8((ma_int16)s);
40209                     }
40210                 }
40211             }
40212         } break;
40213
40214         case ma_format_s16:
40215         {
40216             /* */ ma_int16* pFramesOutS16 = (      ma_int16*)pFramesOut;
40217             const ma_int16* pFramesInS16  = (const ma_int16*)pFramesIn;
40218
40219             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40220                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
40221                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
40222                         ma_int32 s = pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut];
40223                         s += (pFramesInS16[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT;
40224
40225                         pFramesOutS16[iFrame*pConverter->channelsOut + iChannelOut] = (ma_int16)ma_clamp(s, -32768, 32767);
40226                     }
40227                 }
40228             }
40229         } break;
40230
40231         case ma_format_s24:
40232         {
40233             /* */ ma_uint8* pFramesOutS24 = (      ma_uint8*)pFramesOut;
40234             const ma_uint8* pFramesInS24  = (const ma_uint8*)pFramesIn;
40235
40236             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40237                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
40238                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
40239                         ma_int64 s24_O = ma_pcm_sample_s24_to_s32_no_scale(&pFramesOutS24[(iFrame*pConverter->channelsOut + iChannelOut)*3]);
40240                         ma_int64 s24_I = ma_pcm_sample_s24_to_s32_no_scale(&pFramesInS24 [(iFrame*pConverter->channelsIn  + iChannelIn )*3]);
40241                         ma_int64 s24   = (ma_int32)ma_clamp(s24_O + ((s24_I * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT), -8388608, 8388607);
40242                         ma_pcm_sample_s32_to_s24_no_scale(s24, &pFramesOutS24[(iFrame*pConverter->channelsOut + iChannelOut)*3]);
40243                     }
40244                 }
40245             }
40246         } break;
40247
40248         case ma_format_s32:
40249         {
40250             /* */ ma_int32* pFramesOutS32 = (      ma_int32*)pFramesOut;
40251             const ma_int32* pFramesInS32  = (const ma_int32*)pFramesIn;
40252
40253             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40254                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
40255                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
40256                         ma_int64 s = pFramesOutS32[iFrame*pConverter->channelsOut + iChannelOut];
40257                         s += ((ma_int64)pFramesInS32[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.s16[iChannelIn][iChannelOut]) >> MA_CHANNEL_CONVERTER_FIXED_POINT_SHIFT;
40258
40259                         pFramesOutS32[iFrame*pConverter->channelsOut + iChannelOut] = ma_clip_s32(s);
40260                     }
40261                 }
40262             }
40263         } break;
40264
40265         case ma_format_f32:
40266         {
40267             /* */ float* pFramesOutF32 = (      float*)pFramesOut;
40268             const float* pFramesInF32  = (const float*)pFramesIn;
40269
40270             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
40271                 for (iChannelIn = 0; iChannelIn < pConverter->channelsIn; ++iChannelIn) {
40272                     for (iChannelOut = 0; iChannelOut < pConverter->channelsOut; ++iChannelOut) {
40273                         pFramesOutF32[iFrame*pConverter->channelsOut + iChannelOut] += pFramesInF32[iFrame*pConverter->channelsIn + iChannelIn] * pConverter->weights.f32[iChannelIn][iChannelOut];
40274                     }
40275                 }
40276             }
40277         } break;
40278
40279         default: return MA_INVALID_OPERATION;   /* Unknown format. */
40280     }
40281
40282     return MA_SUCCESS;
40283 }
40284
40285 MA_API ma_result ma_channel_converter_process_pcm_frames(ma_channel_converter* pConverter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
40286 {
40287     if (pConverter == NULL) {
40288         return MA_INVALID_ARGS;
40289     }
40290
40291     if (pFramesOut == NULL) {
40292         return MA_INVALID_ARGS;
40293     }
40294
40295     if (pFramesIn == NULL) {
40296         ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->format, pConverter->channelsOut));
40297         return MA_SUCCESS;
40298     }
40299
40300     if (pConverter->isPassthrough) {
40301         return ma_channel_converter_process_pcm_frames__passthrough(pConverter, pFramesOut, pFramesIn, frameCount);
40302     } else if (pConverter->isSimpleShuffle) {
40303         return ma_channel_converter_process_pcm_frames__simple_shuffle(pConverter, pFramesOut, pFramesIn, frameCount);
40304     } else if (pConverter->isSimpleMonoExpansion) {
40305         return ma_channel_converter_process_pcm_frames__simple_mono_expansion(pConverter, pFramesOut, pFramesIn, frameCount);
40306     } else if (pConverter->isStereoToMono) {
40307         return ma_channel_converter_process_pcm_frames__stereo_to_mono(pConverter, pFramesOut, pFramesIn, frameCount);
40308     } else {
40309         return ma_channel_converter_process_pcm_frames__weights(pConverter, pFramesOut, pFramesIn, frameCount);
40310     }
40311 }
40312
40313
40314 /**************************************************************************************************************************************************************
40315
40316 Data Conversion
40317
40318 **************************************************************************************************************************************************************/
40319 MA_API ma_data_converter_config ma_data_converter_config_init_default()
40320 {
40321     ma_data_converter_config config;
40322     MA_ZERO_OBJECT(&config);
40323
40324     config.ditherMode = ma_dither_mode_none;
40325     config.resampling.algorithm = ma_resample_algorithm_linear;
40326     config.resampling.allowDynamicSampleRate = MA_FALSE; /* Disable dynamic sample rates by default because dynamic rate adjustments should be quite rare and it allows an optimization for cases when the in and out sample rates are the same. */
40327
40328     /* Linear resampling defaults. */
40329     config.resampling.linear.lpfOrder = 1;
40330     config.resampling.linear.lpfNyquistFactor = 1;
40331
40332     /* Speex resampling defaults. */
40333     config.resampling.speex.quality = 3;
40334
40335     return config;
40336 }
40337
40338 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)
40339 {
40340     ma_data_converter_config config = ma_data_converter_config_init_default();
40341     config.formatIn      = formatIn;
40342     config.formatOut     = formatOut;
40343     config.channelsIn    = ma_min(channelsIn,  MA_MAX_CHANNELS);
40344     config.channelsOut   = ma_min(channelsOut, MA_MAX_CHANNELS);
40345     config.sampleRateIn  = sampleRateIn;
40346     config.sampleRateOut = sampleRateOut;
40347
40348     return config;
40349 }
40350
40351 MA_API ma_result ma_data_converter_init(const ma_data_converter_config* pConfig, ma_data_converter* pConverter)
40352 {
40353     ma_result result;
40354     ma_format midFormat;
40355
40356     if (pConverter == NULL) {
40357         return MA_INVALID_ARGS;
40358     }
40359
40360     MA_ZERO_OBJECT(pConverter);
40361
40362     if (pConfig == NULL) {
40363         return MA_INVALID_ARGS;
40364     }
40365
40366     pConverter->config = *pConfig;
40367
40368     /* Basic validation. */
40369     if (pConfig->channelsIn < MA_MIN_CHANNELS || pConfig->channelsOut < MA_MIN_CHANNELS ||
40370         pConfig->channelsIn > MA_MAX_CHANNELS || pConfig->channelsOut > MA_MAX_CHANNELS) {
40371         return MA_INVALID_ARGS;
40372     }
40373
40374     /*
40375     We want to avoid as much data conversion as possible. The channel converter and resampler both support s16 and f32 natively. We need to decide
40376     on the format to use for this stage. We call this the mid format because it's used in the middle stage of the conversion pipeline. If the output
40377     format is either s16 or f32 we use that one. If that is not the case it will do the same thing for the input format. If it's neither we just
40378     use f32.
40379     */
40380     /*  */ if (pConverter->config.formatOut == ma_format_s16 || pConverter->config.formatOut == ma_format_f32) {
40381         midFormat = pConverter->config.formatOut;
40382     } else if (pConverter->config.formatIn  == ma_format_s16 || pConverter->config.formatIn  == ma_format_f32) {
40383         midFormat = pConverter->config.formatIn;
40384     } else {
40385         midFormat = ma_format_f32;
40386     }
40387
40388     /* Channel converter. We always initialize this, but we check if it configures itself as a passthrough to determine whether or not it's needed. */
40389     {
40390         ma_uint32 iChannelIn;
40391         ma_uint32 iChannelOut;
40392         ma_channel_converter_config channelConverterConfig;
40393
40394         channelConverterConfig = ma_channel_converter_config_init(midFormat, pConverter->config.channelsIn, pConverter->config.channelMapIn, pConverter->config.channelsOut, pConverter->config.channelMapOut, pConverter->config.channelMixMode);
40395
40396         /* Channel weights. */
40397         for (iChannelIn = 0; iChannelIn < pConverter->config.channelsIn; iChannelIn += 1) {
40398             for (iChannelOut = 0; iChannelOut < pConverter->config.channelsOut; iChannelOut += 1) {
40399                 channelConverterConfig.weights[iChannelIn][iChannelOut] = pConverter->config.channelWeights[iChannelIn][iChannelOut];
40400             }
40401         }
40402
40403         result = ma_channel_converter_init(&channelConverterConfig, &pConverter->channelConverter);
40404         if (result != MA_SUCCESS) {
40405             return result;
40406         }
40407
40408         /* If the channel converter is not a passthrough we need to enable it. Otherwise we can skip it. */
40409         if (pConverter->channelConverter.isPassthrough == MA_FALSE) {
40410             pConverter->hasChannelConverter = MA_TRUE;
40411         }
40412     }
40413
40414
40415     /* Always enable dynamic sample rates if the input sample rate is different because we're always going to need a resampler in this case anyway. */
40416     if (pConverter->config.resampling.allowDynamicSampleRate == MA_FALSE) {
40417         pConverter->config.resampling.allowDynamicSampleRate = pConverter->config.sampleRateIn != pConverter->config.sampleRateOut;
40418     }
40419
40420     /* Resampler. */
40421     if (pConverter->config.resampling.allowDynamicSampleRate) {
40422         ma_resampler_config resamplerConfig;
40423         ma_uint32 resamplerChannels;
40424
40425         /* 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. */
40426         if (pConverter->config.channelsIn < pConverter->config.channelsOut) {
40427             resamplerChannels = pConverter->config.channelsIn;
40428         } else {
40429             resamplerChannels = pConverter->config.channelsOut;
40430         }
40431
40432         resamplerConfig = ma_resampler_config_init(midFormat, resamplerChannels, pConverter->config.sampleRateIn, pConverter->config.sampleRateOut, pConverter->config.resampling.algorithm);
40433         resamplerConfig.linear.lpfOrder         = pConverter->config.resampling.linear.lpfOrder;
40434         resamplerConfig.linear.lpfNyquistFactor = pConverter->config.resampling.linear.lpfNyquistFactor;
40435         resamplerConfig.speex.quality           = pConverter->config.resampling.speex.quality;
40436
40437         result = ma_resampler_init(&resamplerConfig, &pConverter->resampler);
40438         if (result != MA_SUCCESS) {
40439             return result;
40440         }
40441
40442         pConverter->hasResampler = MA_TRUE;
40443     }
40444
40445
40446     /* We can simplify pre- and post-format conversion if we have neither channel conversion nor resampling. */
40447     if (pConverter->hasChannelConverter == MA_FALSE && pConverter->hasResampler == MA_FALSE) {
40448         /* 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. */
40449         if (pConverter->config.formatIn == pConverter->config.formatOut) {
40450             /* The formats are the same so we can just pass through. */
40451             pConverter->hasPreFormatConversion  = MA_FALSE;
40452             pConverter->hasPostFormatConversion = MA_FALSE;
40453         } else {
40454             /* The formats are different so we need to do either pre- or post-format conversion. It doesn't matter which. */
40455             pConverter->hasPreFormatConversion  = MA_FALSE;
40456             pConverter->hasPostFormatConversion = MA_TRUE;
40457         }
40458     } else {
40459         /* We have a channel converter and/or resampler so we'll need channel conversion based on the mid format. */
40460         if (pConverter->config.formatIn != midFormat) {
40461             pConverter->hasPreFormatConversion = MA_TRUE;
40462         }
40463         if (pConverter->config.formatOut != midFormat) {
40464             pConverter->hasPostFormatConversion = MA_TRUE;
40465         }
40466     }
40467
40468     /* We can enable passthrough optimizations if applicable. Note that we'll only be able to do this if the sample rate is static. */
40469     if (pConverter->hasPreFormatConversion  == MA_FALSE &&
40470         pConverter->hasPostFormatConversion == MA_FALSE &&
40471         pConverter->hasChannelConverter     == MA_FALSE &&
40472         pConverter->hasResampler            == MA_FALSE) {
40473         pConverter->isPassthrough = MA_TRUE;
40474     }
40475
40476     return MA_SUCCESS;
40477 }
40478
40479 MA_API void ma_data_converter_uninit(ma_data_converter* pConverter)
40480 {
40481     if (pConverter == NULL) {
40482         return;
40483     }
40484
40485     if (pConverter->hasResampler) {
40486         ma_resampler_uninit(&pConverter->resampler);
40487     }
40488 }
40489
40490 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)
40491 {
40492     ma_uint64 frameCountIn;
40493     ma_uint64 frameCountOut;
40494     ma_uint64 frameCount;
40495
40496     MA_ASSERT(pConverter != NULL);
40497
40498     frameCountIn = 0;
40499     if (pFrameCountIn != NULL) {
40500         frameCountIn = *pFrameCountIn;
40501     }
40502
40503     frameCountOut = 0;
40504     if (pFrameCountOut != NULL) {
40505         frameCountOut = *pFrameCountOut;
40506     }
40507
40508     frameCount = ma_min(frameCountIn, frameCountOut);
40509
40510     if (pFramesOut != NULL) {
40511         if (pFramesIn != NULL) {
40512             ma_copy_memory_64(pFramesOut, pFramesIn, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
40513         } else {
40514             ma_zero_memory_64(pFramesOut,            frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
40515         }
40516     }
40517
40518     if (pFrameCountIn != NULL) {
40519         *pFrameCountIn = frameCount;
40520     }
40521     if (pFrameCountOut != NULL) {
40522         *pFrameCountOut = frameCount;
40523     }
40524
40525     return MA_SUCCESS;
40526 }
40527
40528 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)
40529 {
40530     ma_uint64 frameCountIn;
40531     ma_uint64 frameCountOut;
40532     ma_uint64 frameCount;
40533
40534     MA_ASSERT(pConverter != NULL);
40535
40536     frameCountIn = 0;
40537     if (pFrameCountIn != NULL) {
40538         frameCountIn = *pFrameCountIn;
40539     }
40540
40541     frameCountOut = 0;
40542     if (pFrameCountOut != NULL) {
40543         frameCountOut = *pFrameCountOut;
40544     }
40545
40546     frameCount = ma_min(frameCountIn, frameCountOut);
40547
40548     if (pFramesOut != NULL) {
40549         if (pFramesIn != NULL) {
40550             ma_convert_pcm_frames_format(pFramesOut, pConverter->config.formatOut, pFramesIn, pConverter->config.formatIn, frameCount, pConverter->config.channelsIn, pConverter->config.ditherMode);
40551         } else {
40552             ma_zero_memory_64(pFramesOut, frameCount * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
40553         }
40554     }
40555
40556     if (pFrameCountIn != NULL) {
40557         *pFrameCountIn = frameCount;
40558     }
40559     if (pFrameCountOut != NULL) {
40560         *pFrameCountOut = frameCount;
40561     }
40562
40563     return MA_SUCCESS;
40564 }
40565
40566
40567 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)
40568 {
40569     ma_result result = MA_SUCCESS;
40570     ma_uint64 frameCountIn;
40571     ma_uint64 frameCountOut;
40572     ma_uint64 framesProcessedIn;
40573     ma_uint64 framesProcessedOut;
40574
40575     MA_ASSERT(pConverter != NULL);
40576
40577     frameCountIn = 0;
40578     if (pFrameCountIn != NULL) {
40579         frameCountIn = *pFrameCountIn;
40580     }
40581
40582     frameCountOut = 0;
40583     if (pFrameCountOut != NULL) {
40584         frameCountOut = *pFrameCountOut;
40585     }
40586
40587     framesProcessedIn  = 0;
40588     framesProcessedOut = 0;
40589
40590     while (framesProcessedOut < frameCountOut) {
40591         ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
40592         const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
40593         const void* pFramesInThisIteration;
40594         /* */ void* pFramesOutThisIteration;
40595         ma_uint64 frameCountInThisIteration;
40596         ma_uint64 frameCountOutThisIteration;
40597
40598         if (pFramesIn != NULL) {
40599             pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessedIn * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
40600         } else {
40601             pFramesInThisIteration = NULL;
40602         }
40603
40604         if (pFramesOut != NULL) {
40605             pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
40606         } else {
40607             pFramesOutThisIteration = NULL;
40608         }
40609
40610         /* Do a pre format conversion if necessary. */
40611         if (pConverter->hasPreFormatConversion) {
40612             ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
40613             const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
40614
40615             frameCountInThisIteration  = (frameCountIn - framesProcessedIn);
40616             if (frameCountInThisIteration > tempBufferInCap) {
40617                 frameCountInThisIteration = tempBufferInCap;
40618             }
40619
40620             if (pConverter->hasPostFormatConversion) {
40621                if (frameCountInThisIteration > tempBufferOutCap) {
40622                    frameCountInThisIteration = tempBufferOutCap;
40623                }
40624             }
40625
40626             if (pFramesInThisIteration != NULL) {
40627                 ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
40628             } else {
40629                 MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn));
40630             }
40631
40632             frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
40633
40634             if (pConverter->hasPostFormatConversion) {
40635                 /* Both input and output conversion required. Output to the temp buffer. */
40636                 if (frameCountOutThisIteration > tempBufferOutCap) {
40637                     frameCountOutThisIteration = tempBufferOutCap;
40638                 }
40639
40640                 result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration);
40641             } else {
40642                 /* Only pre-format required. Output straight to the output buffer. */
40643                 result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferIn, &frameCountInThisIteration, pFramesOutThisIteration, &frameCountOutThisIteration);
40644             }
40645
40646             if (result != MA_SUCCESS) {
40647                 break;
40648             }
40649         } else {
40650             /* No pre-format required. Just read straight from the input buffer. */
40651             MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE);
40652
40653             frameCountInThisIteration  = (frameCountIn  - framesProcessedIn);
40654             frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
40655             if (frameCountOutThisIteration > tempBufferOutCap) {
40656                 frameCountOutThisIteration = tempBufferOutCap;
40657             }
40658
40659             result = ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesInThisIteration, &frameCountInThisIteration, pTempBufferOut, &frameCountOutThisIteration);
40660             if (result != MA_SUCCESS) {
40661                 break;
40662             }
40663         }
40664
40665         /* If we are doing a post format conversion we need to do that now. */
40666         if (pConverter->hasPostFormatConversion) {
40667             if (pFramesOutThisIteration != NULL) {
40668                 ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->resampler.config.channels, pConverter->config.ditherMode);
40669             }
40670         }
40671
40672         framesProcessedIn  += frameCountInThisIteration;
40673         framesProcessedOut += frameCountOutThisIteration;
40674
40675         MA_ASSERT(framesProcessedIn  <= frameCountIn);
40676         MA_ASSERT(framesProcessedOut <= frameCountOut);
40677
40678         if (frameCountOutThisIteration == 0) {
40679             break;  /* Consumed all of our input data. */
40680         }
40681     }
40682
40683     if (pFrameCountIn != NULL) {
40684         *pFrameCountIn = framesProcessedIn;
40685     }
40686     if (pFrameCountOut != NULL) {
40687         *pFrameCountOut = framesProcessedOut;
40688     }
40689
40690     return result;
40691 }
40692
40693 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)
40694 {
40695     MA_ASSERT(pConverter != NULL);
40696
40697     if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) {
40698         /* Neither pre- nor post-format required. This is simple case where only resampling is required. */
40699         return ma_resampler_process_pcm_frames(&pConverter->resampler, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
40700     } else {
40701         /* Format conversion required. */
40702         return ma_data_converter_process_pcm_frames__resample_with_format_conversion(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
40703     }
40704 }
40705
40706 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)
40707 {
40708     ma_result result;
40709     ma_uint64 frameCountIn;
40710     ma_uint64 frameCountOut;
40711     ma_uint64 frameCount;
40712
40713     MA_ASSERT(pConverter != NULL);
40714
40715     frameCountIn = 0;
40716     if (pFrameCountIn != NULL) {
40717         frameCountIn = *pFrameCountIn;
40718     }
40719
40720     frameCountOut = 0;
40721     if (pFrameCountOut != NULL) {
40722         frameCountOut = *pFrameCountOut;
40723     }
40724
40725     frameCount = ma_min(frameCountIn, frameCountOut);
40726
40727     if (pConverter->hasPreFormatConversion == MA_FALSE && pConverter->hasPostFormatConversion == MA_FALSE) {
40728         /* No format conversion required. */
40729         result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOut, pFramesIn, frameCount);
40730         if (result != MA_SUCCESS) {
40731             return result;
40732         }
40733     } else {
40734         /* Format conversion required. */
40735         ma_uint64 framesProcessed = 0;
40736
40737         while (framesProcessed < frameCount) {
40738             ma_uint8 pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
40739             const ma_uint32 tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
40740             const void* pFramesInThisIteration;
40741             /* */ void* pFramesOutThisIteration;
40742             ma_uint64 frameCountThisIteration;
40743
40744             if (pFramesIn != NULL) {
40745                 pFramesInThisIteration = ma_offset_ptr(pFramesIn, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
40746             } else {
40747                 pFramesInThisIteration = NULL;
40748             }
40749
40750             if (pFramesOut != NULL) {
40751                 pFramesOutThisIteration = ma_offset_ptr(pFramesOut, framesProcessed * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
40752             } else {
40753                 pFramesOutThisIteration = NULL;
40754             }
40755
40756             /* Do a pre format conversion if necessary. */
40757             if (pConverter->hasPreFormatConversion) {
40758                 ma_uint8 pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
40759                 const ma_uint32 tempBufferInCap = sizeof(pTempBufferIn) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn);
40760
40761                 frameCountThisIteration = (frameCount - framesProcessed);
40762                 if (frameCountThisIteration > tempBufferInCap) {
40763                     frameCountThisIteration = tempBufferInCap;
40764                 }
40765
40766                 if (pConverter->hasPostFormatConversion) {
40767                     if (frameCountThisIteration > tempBufferOutCap) {
40768                         frameCountThisIteration = tempBufferOutCap;
40769                     }
40770                 }
40771
40772                 if (pFramesInThisIteration != NULL) {
40773                     ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pFramesInThisIteration, pConverter->config.formatIn, frameCountThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
40774                 } else {
40775                     MA_ZERO_MEMORY(pTempBufferIn, sizeof(pTempBufferIn));
40776                 }
40777
40778                 if (pConverter->hasPostFormatConversion) {
40779                     /* Both input and output conversion required. Output to the temp buffer. */
40780                     result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pTempBufferIn, frameCountThisIteration);
40781                 } else {
40782                     /* Only pre-format required. Output straight to the output buffer. */
40783                     result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pFramesOutThisIteration, pTempBufferIn, frameCountThisIteration);
40784                 }
40785
40786                 if (result != MA_SUCCESS) {
40787                     break;
40788                 }
40789             } else {
40790                 /* No pre-format required. Just read straight from the input buffer. */
40791                 MA_ASSERT(pConverter->hasPostFormatConversion == MA_TRUE);
40792
40793                 frameCountThisIteration = (frameCount - framesProcessed);
40794                 if (frameCountThisIteration > tempBufferOutCap) {
40795                     frameCountThisIteration = tempBufferOutCap;
40796                 }
40797
40798                 result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferOut, pFramesInThisIteration, frameCountThisIteration);
40799                 if (result != MA_SUCCESS) {
40800                     break;
40801                 }
40802             }
40803
40804             /* If we are doing a post format conversion we need to do that now. */
40805             if (pConverter->hasPostFormatConversion) {
40806                 if (pFramesOutThisIteration != NULL) {
40807                     ma_convert_pcm_frames_format(pFramesOutThisIteration, pConverter->config.formatOut, pTempBufferOut, pConverter->channelConverter.format, frameCountThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode);
40808                 }
40809             }
40810
40811             framesProcessed += frameCountThisIteration;
40812         }
40813     }
40814
40815     if (pFrameCountIn != NULL) {
40816         *pFrameCountIn = frameCount;
40817     }
40818     if (pFrameCountOut != NULL) {
40819         *pFrameCountOut = frameCount;
40820     }
40821
40822     return MA_SUCCESS;
40823 }
40824
40825 static ma_result ma_data_converter_process_pcm_frames__resampling_first(ma_data_converter* pConverter, const void* pFramesIn, ma_uint64* pFrameCountIn, void* pFramesOut, ma_uint64* pFrameCountOut)
40826 {
40827     ma_result result;
40828     ma_uint64 frameCountIn;
40829     ma_uint64 frameCountOut;
40830     ma_uint64 framesProcessedIn;
40831     ma_uint64 framesProcessedOut;
40832     ma_uint8  pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];   /* In resampler format. */
40833     ma_uint64 tempBufferInCap;
40834     ma_uint8  pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In resampler format, channel converter input format. */
40835     ma_uint64 tempBufferMidCap;
40836     ma_uint8  pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In channel converter output format. */
40837     ma_uint64 tempBufferOutCap;
40838
40839     MA_ASSERT(pConverter != NULL);
40840     MA_ASSERT(pConverter->resampler.config.format   == pConverter->channelConverter.format);
40841     MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsIn);
40842     MA_ASSERT(pConverter->resampler.config.channels <  pConverter->channelConverter.channelsOut);
40843
40844     frameCountIn = 0;
40845     if (pFrameCountIn != NULL) {
40846         frameCountIn = *pFrameCountIn;
40847     }
40848
40849     frameCountOut = 0;
40850     if (pFrameCountOut != NULL) {
40851         frameCountOut = *pFrameCountOut;
40852     }
40853
40854     framesProcessedIn  = 0;
40855     framesProcessedOut = 0;
40856
40857     tempBufferInCap  = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
40858     tempBufferMidCap = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
40859     tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
40860
40861     while (framesProcessedOut < frameCountOut) {
40862         ma_uint64 frameCountInThisIteration;
40863         ma_uint64 frameCountOutThisIteration;
40864         const void* pRunningFramesIn = NULL;
40865         void* pRunningFramesOut = NULL;
40866         const void* pResampleBufferIn;
40867         void* pChannelsBufferOut;
40868
40869         if (pFramesIn != NULL) {
40870             pRunningFramesIn  = ma_offset_ptr(pFramesIn,  framesProcessedIn  * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
40871         }
40872         if (pFramesOut != NULL) {
40873             pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
40874         }
40875
40876         /* Run input data through the resampler and output it to the temporary buffer. */
40877         frameCountInThisIteration = (frameCountIn - framesProcessedIn);
40878
40879         if (pConverter->hasPreFormatConversion) {
40880             if (frameCountInThisIteration > tempBufferInCap) {
40881                 frameCountInThisIteration = tempBufferInCap;
40882             }
40883         }
40884
40885         frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
40886         if (frameCountOutThisIteration > tempBufferMidCap) {
40887             frameCountOutThisIteration = tempBufferMidCap;
40888         }
40889
40890         /* We can't read more frames than can fit in the output buffer. */
40891         if (pConverter->hasPostFormatConversion) {
40892             if (frameCountOutThisIteration > tempBufferOutCap) {
40893                 frameCountOutThisIteration = tempBufferOutCap;
40894             }
40895         }
40896
40897         /* 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. */
40898         {
40899             ma_uint64 requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration);
40900             if (frameCountInThisIteration > requiredInputFrameCount) {
40901                 frameCountInThisIteration = requiredInputFrameCount;
40902             }
40903         }
40904
40905         if (pConverter->hasPreFormatConversion) {
40906             if (pFramesIn != NULL) {
40907                 ma_convert_pcm_frames_format(pTempBufferIn, pConverter->resampler.config.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
40908                 pResampleBufferIn = pTempBufferIn;
40909             } else {
40910                 pResampleBufferIn = NULL;
40911             }
40912         } else {
40913             pResampleBufferIn = pRunningFramesIn;
40914         }
40915
40916         result = ma_resampler_process_pcm_frames(&pConverter->resampler, pResampleBufferIn, &frameCountInThisIteration, pTempBufferMid, &frameCountOutThisIteration);
40917         if (result != MA_SUCCESS) {
40918             return result;
40919         }
40920
40921
40922         /*
40923         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
40924         this part if we have an output buffer.
40925         */
40926         if (pFramesOut != NULL) {
40927             if (pConverter->hasPostFormatConversion) {
40928                 pChannelsBufferOut = pTempBufferOut;
40929             } else {
40930                 pChannelsBufferOut = pRunningFramesOut;
40931             }
40932
40933             result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pChannelsBufferOut, pTempBufferMid, frameCountOutThisIteration);
40934             if (result != MA_SUCCESS) {
40935                 return result;
40936             }
40937
40938             /* Finally we do post format conversion. */
40939             if (pConverter->hasPostFormatConversion) {
40940                 ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pChannelsBufferOut, pConverter->channelConverter.format, frameCountOutThisIteration, pConverter->channelConverter.channelsOut, pConverter->config.ditherMode);
40941             }
40942         }
40943
40944
40945         framesProcessedIn  += frameCountInThisIteration;
40946         framesProcessedOut += frameCountOutThisIteration;
40947
40948         MA_ASSERT(framesProcessedIn  <= frameCountIn);
40949         MA_ASSERT(framesProcessedOut <= frameCountOut);
40950
40951         if (frameCountOutThisIteration == 0) {
40952             break;  /* Consumed all of our input data. */
40953         }
40954     }
40955
40956     if (pFrameCountIn != NULL) {
40957         *pFrameCountIn = framesProcessedIn;
40958     }
40959     if (pFrameCountOut != NULL) {
40960         *pFrameCountOut = framesProcessedOut;
40961     }
40962
40963     return MA_SUCCESS;
40964 }
40965
40966 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)
40967 {
40968     ma_result result;
40969     ma_uint64 frameCountIn;
40970     ma_uint64 frameCountOut;
40971     ma_uint64 framesProcessedIn;
40972     ma_uint64 framesProcessedOut;
40973     ma_uint8  pTempBufferIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];   /* In resampler format. */
40974     ma_uint64 tempBufferInCap;
40975     ma_uint8  pTempBufferMid[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In resampler format, channel converter input format. */
40976     ma_uint64 tempBufferMidCap;
40977     ma_uint8  pTempBufferOut[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In channel converter output format. */
40978     ma_uint64 tempBufferOutCap;
40979
40980     MA_ASSERT(pConverter != NULL);
40981     MA_ASSERT(pConverter->resampler.config.format   == pConverter->channelConverter.format);
40982     MA_ASSERT(pConverter->resampler.config.channels == pConverter->channelConverter.channelsOut);
40983     MA_ASSERT(pConverter->resampler.config.channels <  pConverter->channelConverter.channelsIn);
40984
40985     frameCountIn = 0;
40986     if (pFrameCountIn != NULL) {
40987         frameCountIn = *pFrameCountIn;
40988     }
40989
40990     frameCountOut = 0;
40991     if (pFrameCountOut != NULL) {
40992         frameCountOut = *pFrameCountOut;
40993     }
40994
40995     framesProcessedIn  = 0;
40996     framesProcessedOut = 0;
40997
40998     tempBufferInCap  = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsIn);
40999     tempBufferMidCap = sizeof(pTempBufferIn)  / ma_get_bytes_per_frame(pConverter->channelConverter.format, pConverter->channelConverter.channelsOut);
41000     tempBufferOutCap = sizeof(pTempBufferOut) / ma_get_bytes_per_frame(pConverter->resampler.config.format, pConverter->resampler.config.channels);
41001
41002     while (framesProcessedOut < frameCountOut) {
41003         ma_uint64 frameCountInThisIteration;
41004         ma_uint64 frameCountOutThisIteration;
41005         const void* pRunningFramesIn = NULL;
41006         void* pRunningFramesOut = NULL;
41007         const void* pChannelsBufferIn;
41008         void* pResampleBufferOut;
41009
41010         if (pFramesIn != NULL) {
41011             pRunningFramesIn  = ma_offset_ptr(pFramesIn,  framesProcessedIn  * ma_get_bytes_per_frame(pConverter->config.formatIn, pConverter->config.channelsIn));
41012         }
41013         if (pFramesOut != NULL) {
41014             pRunningFramesOut = ma_offset_ptr(pFramesOut, framesProcessedOut * ma_get_bytes_per_frame(pConverter->config.formatOut, pConverter->config.channelsOut));
41015         }
41016
41017         /* Run input data through the channel converter and output it to the temporary buffer. */
41018         frameCountInThisIteration = (frameCountIn - framesProcessedIn);
41019
41020         if (pConverter->hasPreFormatConversion) {
41021             if (frameCountInThisIteration > tempBufferInCap) {
41022                 frameCountInThisIteration = tempBufferInCap;
41023             }
41024
41025             if (pRunningFramesIn != NULL) {
41026                 ma_convert_pcm_frames_format(pTempBufferIn, pConverter->channelConverter.format, pRunningFramesIn, pConverter->config.formatIn, frameCountInThisIteration, pConverter->config.channelsIn, pConverter->config.ditherMode);
41027                 pChannelsBufferIn = pTempBufferIn;
41028             } else {
41029                 pChannelsBufferIn = NULL;
41030             }
41031         } else {
41032             pChannelsBufferIn = pRunningFramesIn;
41033         }
41034
41035         /*
41036         We can't convert more frames than will fit in the output buffer. We shouldn't actually need to do this check because the channel count is always reduced
41037         in this case which means we should always have capacity, but I'm leaving it here just for safety for future maintenance.
41038         */
41039         if (frameCountInThisIteration > tempBufferMidCap) {
41040             frameCountInThisIteration = tempBufferMidCap;
41041         }
41042
41043         /*
41044         Make sure we don't read any more input frames than we need to fill the output frame count. If we do this we will end up in a situation where we lose some
41045         input samples and will end up glitching.
41046         */
41047         frameCountOutThisIteration = (frameCountOut - framesProcessedOut);
41048         if (frameCountOutThisIteration > tempBufferMidCap) {
41049             frameCountOutThisIteration = tempBufferMidCap;
41050         }
41051
41052         if (pConverter->hasPostFormatConversion) {
41053             ma_uint64 requiredInputFrameCount;
41054
41055             if (frameCountOutThisIteration > tempBufferOutCap) {
41056                 frameCountOutThisIteration = tempBufferOutCap;
41057             }
41058
41059             requiredInputFrameCount = ma_resampler_get_required_input_frame_count(&pConverter->resampler, frameCountOutThisIteration);
41060             if (frameCountInThisIteration > requiredInputFrameCount) {
41061                 frameCountInThisIteration = requiredInputFrameCount;
41062             }
41063         }
41064
41065         result = ma_channel_converter_process_pcm_frames(&pConverter->channelConverter, pTempBufferMid, pChannelsBufferIn, frameCountInThisIteration);
41066         if (result != MA_SUCCESS) {
41067             return result;
41068         }
41069
41070
41071         /* At this point we have converted the channels to the output channel count which we now need to resample. */
41072         if (pConverter->hasPostFormatConversion) {
41073             pResampleBufferOut = pTempBufferOut;
41074         } else {
41075             pResampleBufferOut = pRunningFramesOut;
41076         }
41077
41078         result = ma_resampler_process_pcm_frames(&pConverter->resampler, pTempBufferMid, &frameCountInThisIteration, pResampleBufferOut, &frameCountOutThisIteration);
41079         if (result != MA_SUCCESS) {
41080             return result;
41081         }
41082
41083         /* Finally we can do the post format conversion. */
41084         if (pConverter->hasPostFormatConversion) {
41085             if (pRunningFramesOut != NULL) {
41086                 ma_convert_pcm_frames_format(pRunningFramesOut, pConverter->config.formatOut, pResampleBufferOut, pConverter->resampler.config.format, frameCountOutThisIteration, pConverter->config.channelsOut, pConverter->config.ditherMode);
41087             }
41088         }
41089
41090         framesProcessedIn  += frameCountInThisIteration;
41091         framesProcessedOut += frameCountOutThisIteration;
41092
41093         MA_ASSERT(framesProcessedIn  <= frameCountIn);
41094         MA_ASSERT(framesProcessedOut <= frameCountOut);
41095
41096         if (frameCountOutThisIteration == 0) {
41097             break;  /* Consumed all of our input data. */
41098         }
41099     }
41100
41101     if (pFrameCountIn != NULL) {
41102         *pFrameCountIn = framesProcessedIn;
41103     }
41104     if (pFrameCountOut != NULL) {
41105         *pFrameCountOut = framesProcessedOut;
41106     }
41107
41108     return MA_SUCCESS;
41109 }
41110
41111 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)
41112 {
41113     if (pConverter == NULL) {
41114         return MA_INVALID_ARGS;
41115     }
41116
41117     if (pConverter->isPassthrough) {
41118         return ma_data_converter_process_pcm_frames__passthrough(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
41119     }
41120
41121     /*
41122     Here is where the real work is done. Getting here means we're not using a passthrough and we need to move the data through each of the relevant stages. The order
41123     of our stages depends on the input and output channel count. If the input channels is less than the output channels we want to do sample rate conversion first so
41124     that it has less work (resampling is the most expensive part of format conversion).
41125     */
41126     if (pConverter->config.channelsIn < pConverter->config.channelsOut) {
41127         /* Do resampling first, if necessary. */
41128         MA_ASSERT(pConverter->hasChannelConverter == MA_TRUE);
41129
41130         if (pConverter->hasResampler) {
41131             /* Resampling first. */
41132             return ma_data_converter_process_pcm_frames__resampling_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
41133         } else {
41134             /* Resampling not required. */
41135             return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
41136         }
41137     } else {
41138         /* Do channel conversion first, if necessary. */
41139         if (pConverter->hasChannelConverter) {
41140             if (pConverter->hasResampler) {
41141                 /* Channel routing first. */
41142                 return ma_data_converter_process_pcm_frames__channels_first(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
41143             } else {
41144                 /* Resampling not required. */
41145                 return ma_data_converter_process_pcm_frames__channels_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
41146             }
41147         } else {
41148             /* Channel routing not required. */
41149             if (pConverter->hasResampler) {
41150                 /* Resampling only. */
41151                 return ma_data_converter_process_pcm_frames__resample_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
41152             } else {
41153                 /* No channel routing nor resampling required. Just format conversion. */
41154                 return ma_data_converter_process_pcm_frames__format_only(pConverter, pFramesIn, pFrameCountIn, pFramesOut, pFrameCountOut);
41155             }
41156         }
41157     }
41158 }
41159
41160 MA_API ma_result ma_data_converter_set_rate(ma_data_converter* pConverter, ma_uint32 sampleRateIn, ma_uint32 sampleRateOut)
41161 {
41162     if (pConverter == NULL) {
41163         return MA_INVALID_ARGS;
41164     }
41165
41166     if (pConverter->hasResampler == MA_FALSE) {
41167         return MA_INVALID_OPERATION;    /* Dynamic resampling not enabled. */
41168     }
41169
41170     return ma_resampler_set_rate(&pConverter->resampler, sampleRateIn, sampleRateOut);
41171 }
41172
41173 MA_API ma_result ma_data_converter_set_rate_ratio(ma_data_converter* pConverter, float ratioInOut)
41174 {
41175     if (pConverter == NULL) {
41176         return MA_INVALID_ARGS;
41177     }
41178
41179     if (pConverter->hasResampler == MA_FALSE) {
41180         return MA_INVALID_OPERATION;    /* Dynamic resampling not enabled. */
41181     }
41182
41183     return ma_resampler_set_rate_ratio(&pConverter->resampler, ratioInOut);
41184 }
41185
41186 MA_API ma_uint64 ma_data_converter_get_required_input_frame_count(const ma_data_converter* pConverter, ma_uint64 outputFrameCount)
41187 {
41188     if (pConverter == NULL) {
41189         return 0;
41190     }
41191
41192     if (pConverter->hasResampler) {
41193         return ma_resampler_get_required_input_frame_count(&pConverter->resampler, outputFrameCount);
41194     } else {
41195         return outputFrameCount;    /* 1:1 */
41196     }
41197 }
41198
41199 MA_API ma_uint64 ma_data_converter_get_expected_output_frame_count(const ma_data_converter* pConverter, ma_uint64 inputFrameCount)
41200 {
41201     if (pConverter == NULL) {
41202         return 0;
41203     }
41204
41205     if (pConverter->hasResampler) {
41206         return ma_resampler_get_expected_output_frame_count(&pConverter->resampler, inputFrameCount);
41207     } else {
41208         return inputFrameCount;     /* 1:1 */
41209     }
41210 }
41211
41212 MA_API ma_uint64 ma_data_converter_get_input_latency(const ma_data_converter* pConverter)
41213 {
41214     if (pConverter == NULL) {
41215         return 0;
41216     }
41217
41218     if (pConverter->hasResampler) {
41219         return ma_resampler_get_input_latency(&pConverter->resampler);
41220     }
41221
41222     return 0;   /* No latency without a resampler. */
41223 }
41224
41225 MA_API ma_uint64 ma_data_converter_get_output_latency(const ma_data_converter* pConverter)
41226 {
41227     if (pConverter == NULL) {
41228         return 0;
41229     }
41230
41231     if (pConverter->hasResampler) {
41232         return ma_resampler_get_output_latency(&pConverter->resampler);
41233     }
41234
41235     return 0;   /* No latency without a resampler. */
41236 }
41237
41238
41239
41240 /**************************************************************************************************************************************************************
41241
41242 Channel Maps
41243
41244 **************************************************************************************************************************************************************/
41245 MA_API void ma_channel_map_init_blank(ma_uint32 channels, ma_channel* pChannelMap)
41246 {
41247     if (pChannelMap == NULL) {
41248         return;
41249     }
41250
41251     MA_ZERO_MEMORY(pChannelMap, sizeof(*pChannelMap) * channels);
41252 }
41253
41254 static void ma_get_standard_channel_map_microsoft(ma_uint32 channels, ma_channel* pChannelMap)
41255 {
41256     /* Based off the speaker configurations mentioned here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-ksaudio_channel_config */
41257     switch (channels)
41258     {
41259         case 1:
41260         {
41261             pChannelMap[0] = MA_CHANNEL_MONO;
41262         } break;
41263
41264         case 2:
41265         {
41266             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41267             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41268         } break;
41269
41270         case 3: /* Not defined, but best guess. */
41271         {
41272             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41273             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41274             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41275         } break;
41276
41277         case 4:
41278         {
41279 #ifndef MA_USE_QUAD_MICROSOFT_CHANNEL_MAP
41280             /* Surround. Using the Surround profile has the advantage of the 3rd channel (MA_CHANNEL_FRONT_CENTER) mapping nicely with higher channel counts. */
41281             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41282             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41283             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41284             pChannelMap[3] = MA_CHANNEL_BACK_CENTER;
41285 #else
41286             /* Quad. */
41287             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41288             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41289             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41290             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41291 #endif
41292         } break;
41293
41294         case 5: /* Not defined, but best guess. */
41295         {
41296             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41297             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41298             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41299             pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
41300             pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
41301         } break;
41302
41303         case 6:
41304         {
41305             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41306             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41307             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41308             pChannelMap[3] = MA_CHANNEL_LFE;
41309             pChannelMap[4] = MA_CHANNEL_SIDE_LEFT;
41310             pChannelMap[5] = MA_CHANNEL_SIDE_RIGHT;
41311         } break;
41312
41313         case 7: /* Not defined, but best guess. */
41314         {
41315             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41316             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41317             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41318             pChannelMap[3] = MA_CHANNEL_LFE;
41319             pChannelMap[4] = MA_CHANNEL_BACK_CENTER;
41320             pChannelMap[5] = MA_CHANNEL_SIDE_LEFT;
41321             pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT;
41322         } break;
41323
41324         case 8:
41325         default:
41326         {
41327             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41328             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41329             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41330             pChannelMap[3] = MA_CHANNEL_LFE;
41331             pChannelMap[4] = MA_CHANNEL_BACK_LEFT;
41332             pChannelMap[5] = MA_CHANNEL_BACK_RIGHT;
41333             pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
41334             pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
41335         } break;
41336     }
41337
41338     /* Remainder. */
41339     if (channels > 8) {
41340         ma_uint32 iChannel;
41341         for (iChannel = 8; iChannel < channels; ++iChannel) {
41342             if (iChannel < MA_MAX_CHANNELS) {
41343                 pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
41344             } else {
41345                 pChannelMap[iChannel] = MA_CHANNEL_NONE;
41346             }
41347         }
41348     }
41349 }
41350
41351 static void ma_get_standard_channel_map_alsa(ma_uint32 channels, ma_channel* pChannelMap)
41352 {
41353     switch (channels)
41354     {
41355         case 1:
41356         {
41357             pChannelMap[0] = MA_CHANNEL_MONO;
41358         } break;
41359
41360         case 2:
41361         {
41362             pChannelMap[0] = MA_CHANNEL_LEFT;
41363             pChannelMap[1] = MA_CHANNEL_RIGHT;
41364         } break;
41365
41366         case 3:
41367         {
41368             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41369             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41370             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41371         } break;
41372
41373         case 4:
41374         {
41375             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41376             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41377             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41378             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41379         } break;
41380
41381         case 5:
41382         {
41383             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41384             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41385             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41386             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41387             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41388         } break;
41389
41390         case 6:
41391         {
41392             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41393             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41394             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41395             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41396             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41397             pChannelMap[5] = MA_CHANNEL_LFE;
41398         } break;
41399
41400         case 7:
41401         {
41402             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41403             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41404             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41405             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41406             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41407             pChannelMap[5] = MA_CHANNEL_LFE;
41408             pChannelMap[6] = MA_CHANNEL_BACK_CENTER;
41409         } break;
41410
41411         case 8:
41412         default:
41413         {
41414             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41415             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41416             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41417             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41418             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41419             pChannelMap[5] = MA_CHANNEL_LFE;
41420             pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
41421             pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
41422         } break;
41423     }
41424
41425     /* Remainder. */
41426     if (channels > 8) {
41427         ma_uint32 iChannel;
41428         for (iChannel = 8; iChannel < channels; ++iChannel) {
41429             if (iChannel < MA_MAX_CHANNELS) {
41430                 pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
41431             } else {
41432                 pChannelMap[iChannel] = MA_CHANNEL_NONE;
41433             }
41434         }
41435     }
41436 }
41437
41438 static void ma_get_standard_channel_map_rfc3551(ma_uint32 channels, ma_channel* pChannelMap)
41439 {
41440     switch (channels)
41441     {
41442         case 1:
41443         {
41444             pChannelMap[0] = MA_CHANNEL_MONO;
41445         } break;
41446
41447         case 2:
41448         {
41449             pChannelMap[0] = MA_CHANNEL_LEFT;
41450             pChannelMap[1] = MA_CHANNEL_RIGHT;
41451         } break;
41452
41453         case 3:
41454         {
41455             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41456             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41457             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41458         } break;
41459
41460         case 4:
41461         {
41462             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41463             pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
41464             pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
41465             pChannelMap[3] = MA_CHANNEL_BACK_CENTER;
41466         } break;
41467
41468         case 5:
41469         {
41470             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41471             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41472             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41473             pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
41474             pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
41475         } break;
41476
41477         case 6:
41478         {
41479             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41480             pChannelMap[1] = MA_CHANNEL_SIDE_LEFT;
41481             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41482             pChannelMap[3] = MA_CHANNEL_FRONT_RIGHT;
41483             pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
41484             pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
41485         } break;
41486     }
41487
41488     /* Remainder. */
41489     if (channels > 8) {
41490         ma_uint32 iChannel;
41491         for (iChannel = 6; iChannel < channels; ++iChannel) {
41492             if (iChannel < MA_MAX_CHANNELS) {
41493                 pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6));
41494             } else {
41495                 pChannelMap[iChannel] = MA_CHANNEL_NONE;
41496             }
41497         }
41498     }
41499 }
41500
41501 static void ma_get_standard_channel_map_flac(ma_uint32 channels, ma_channel* pChannelMap)
41502 {
41503     switch (channels)
41504     {
41505         case 1:
41506         {
41507             pChannelMap[0] = MA_CHANNEL_MONO;
41508         } break;
41509
41510         case 2:
41511         {
41512             pChannelMap[0] = MA_CHANNEL_LEFT;
41513             pChannelMap[1] = MA_CHANNEL_RIGHT;
41514         } break;
41515
41516         case 3:
41517         {
41518             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41519             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41520             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41521         } break;
41522
41523         case 4:
41524         {
41525             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41526             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41527             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41528             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41529         } break;
41530
41531         case 5:
41532         {
41533             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41534             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41535             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41536             pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
41537             pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
41538         } break;
41539
41540         case 6:
41541         {
41542             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41543             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41544             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41545             pChannelMap[3] = MA_CHANNEL_LFE;
41546             pChannelMap[4] = MA_CHANNEL_BACK_LEFT;
41547             pChannelMap[5] = MA_CHANNEL_BACK_RIGHT;
41548         } break;
41549
41550         case 7:
41551         {
41552             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41553             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41554             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41555             pChannelMap[3] = MA_CHANNEL_LFE;
41556             pChannelMap[4] = MA_CHANNEL_BACK_CENTER;
41557             pChannelMap[5] = MA_CHANNEL_SIDE_LEFT;
41558             pChannelMap[6] = MA_CHANNEL_SIDE_RIGHT;
41559         } break;
41560
41561         case 8:
41562         default:
41563         {
41564             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41565             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41566             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41567             pChannelMap[3] = MA_CHANNEL_LFE;
41568             pChannelMap[4] = MA_CHANNEL_BACK_LEFT;
41569             pChannelMap[5] = MA_CHANNEL_BACK_RIGHT;
41570             pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
41571             pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
41572         } break;
41573     }
41574
41575     /* Remainder. */
41576     if (channels > 8) {
41577         ma_uint32 iChannel;
41578         for (iChannel = 8; iChannel < channels; ++iChannel) {
41579             if (iChannel < MA_MAX_CHANNELS) {
41580                 pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
41581             } else {
41582                 pChannelMap[iChannel] = MA_CHANNEL_NONE;
41583             }
41584         }
41585     }
41586 }
41587
41588 static void ma_get_standard_channel_map_vorbis(ma_uint32 channels, ma_channel* pChannelMap)
41589 {
41590     /* In Vorbis' type 0 channel mapping, the first two channels are not always the standard left/right - it will have the center speaker where the right usually goes. Why?! */
41591     switch (channels)
41592     {
41593         case 1:
41594         {
41595             pChannelMap[0] = MA_CHANNEL_MONO;
41596         } break;
41597
41598         case 2:
41599         {
41600             pChannelMap[0] = MA_CHANNEL_LEFT;
41601             pChannelMap[1] = MA_CHANNEL_RIGHT;
41602         } break;
41603
41604         case 3:
41605         {
41606             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41607             pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
41608             pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
41609         } break;
41610
41611         case 4:
41612         {
41613             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41614             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41615             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41616             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41617         } break;
41618
41619         case 5:
41620         {
41621             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41622             pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
41623             pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
41624             pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
41625             pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
41626         } break;
41627
41628         case 6:
41629         {
41630             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41631             pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
41632             pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
41633             pChannelMap[3] = MA_CHANNEL_BACK_LEFT;
41634             pChannelMap[4] = MA_CHANNEL_BACK_RIGHT;
41635             pChannelMap[5] = MA_CHANNEL_LFE;
41636         } break;
41637
41638         case 7:
41639         {
41640             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41641             pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
41642             pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
41643             pChannelMap[3] = MA_CHANNEL_SIDE_LEFT;
41644             pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
41645             pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
41646             pChannelMap[6] = MA_CHANNEL_LFE;
41647         } break;
41648
41649         case 8:
41650         default:
41651         {
41652             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41653             pChannelMap[1] = MA_CHANNEL_FRONT_CENTER;
41654             pChannelMap[2] = MA_CHANNEL_FRONT_RIGHT;
41655             pChannelMap[3] = MA_CHANNEL_SIDE_LEFT;
41656             pChannelMap[4] = MA_CHANNEL_SIDE_RIGHT;
41657             pChannelMap[5] = MA_CHANNEL_BACK_LEFT;
41658             pChannelMap[6] = MA_CHANNEL_BACK_RIGHT;
41659             pChannelMap[7] = MA_CHANNEL_LFE;
41660         } break;
41661     }
41662
41663     /* Remainder. */
41664     if (channels > 8) {
41665         ma_uint32 iChannel;
41666         for (iChannel = 8; iChannel < channels; ++iChannel) {
41667             if (iChannel < MA_MAX_CHANNELS) {
41668                 pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
41669             } else {
41670                 pChannelMap[iChannel] = MA_CHANNEL_NONE;
41671             }
41672         }
41673     }
41674 }
41675
41676 static void ma_get_standard_channel_map_sound4(ma_uint32 channels, ma_channel* pChannelMap)
41677 {
41678     switch (channels)
41679     {
41680         case 1:
41681         {
41682             pChannelMap[0] = MA_CHANNEL_MONO;
41683         } break;
41684
41685         case 2:
41686         {
41687             pChannelMap[0] = MA_CHANNEL_LEFT;
41688             pChannelMap[1] = MA_CHANNEL_RIGHT;
41689         } break;
41690
41691         case 3:
41692         {
41693             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41694             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41695             pChannelMap[2] = MA_CHANNEL_BACK_CENTER;
41696         } break;
41697
41698         case 4:
41699         {
41700             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41701             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41702             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41703             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41704         } break;
41705
41706         case 5:
41707         {
41708             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41709             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41710             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41711             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41712             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41713         } break;
41714
41715         case 6:
41716         {
41717             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41718             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41719             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41720             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41721             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41722             pChannelMap[5] = MA_CHANNEL_LFE;
41723         } break;
41724
41725         case 7:
41726         {
41727             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41728             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41729             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41730             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41731             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41732             pChannelMap[5] = MA_CHANNEL_BACK_CENTER;
41733             pChannelMap[6] = MA_CHANNEL_LFE;
41734         } break;
41735
41736         case 8:
41737         default:
41738         {
41739             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41740             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41741             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41742             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41743             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41744             pChannelMap[5] = MA_CHANNEL_LFE;
41745             pChannelMap[6] = MA_CHANNEL_SIDE_LEFT;
41746             pChannelMap[7] = MA_CHANNEL_SIDE_RIGHT;
41747         } break;
41748     }
41749
41750     /* Remainder. */
41751     if (channels > 8) {
41752         ma_uint32 iChannel;
41753         for (iChannel = 8; iChannel < MA_MAX_CHANNELS; ++iChannel) {
41754             if (iChannel < MA_MAX_CHANNELS) {
41755                 pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-8));
41756             } else {
41757                 pChannelMap[iChannel] = MA_CHANNEL_NONE;
41758             }
41759         }
41760     }
41761 }
41762
41763 static void ma_get_standard_channel_map_sndio(ma_uint32 channels, ma_channel* pChannelMap)
41764 {
41765     switch (channels)
41766     {
41767         case 1:
41768         {
41769             pChannelMap[0] = MA_CHANNEL_MONO;
41770         } break;
41771
41772         case 2:
41773         {
41774             pChannelMap[0] = MA_CHANNEL_LEFT;
41775             pChannelMap[1] = MA_CHANNEL_RIGHT;
41776         } break;
41777
41778         case 3:
41779         {
41780             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41781             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41782             pChannelMap[2] = MA_CHANNEL_FRONT_CENTER;
41783         } break;
41784
41785         case 4:
41786         {
41787             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41788             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41789             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41790             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41791         } break;
41792
41793         case 5:
41794         {
41795             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41796             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41797             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41798             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41799             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41800         } break;
41801
41802         case 6:
41803         default:
41804         {
41805             pChannelMap[0] = MA_CHANNEL_FRONT_LEFT;
41806             pChannelMap[1] = MA_CHANNEL_FRONT_RIGHT;
41807             pChannelMap[2] = MA_CHANNEL_BACK_LEFT;
41808             pChannelMap[3] = MA_CHANNEL_BACK_RIGHT;
41809             pChannelMap[4] = MA_CHANNEL_FRONT_CENTER;
41810             pChannelMap[5] = MA_CHANNEL_LFE;
41811         } break;
41812     }
41813
41814     /* Remainder. */
41815     if (channels > 6) {
41816         ma_uint32 iChannel;
41817         for (iChannel = 6; iChannel < channels && iChannel < MA_MAX_CHANNELS; ++iChannel) {
41818             if (iChannel < MA_MAX_CHANNELS) {
41819                 pChannelMap[iChannel] = (ma_channel)(MA_CHANNEL_AUX_0 + (iChannel-6));
41820             } else {
41821                 pChannelMap[iChannel] = MA_CHANNEL_NONE;
41822             }
41823         }
41824     }
41825 }
41826
41827 MA_API void ma_get_standard_channel_map(ma_standard_channel_map standardChannelMap, ma_uint32 channels, ma_channel* pChannelMap)
41828 {
41829     switch (standardChannelMap)
41830     {
41831         case ma_standard_channel_map_alsa:
41832         {
41833             ma_get_standard_channel_map_alsa(channels, pChannelMap);
41834         } break;
41835
41836         case ma_standard_channel_map_rfc3551:
41837         {
41838             ma_get_standard_channel_map_rfc3551(channels, pChannelMap);
41839         } break;
41840
41841         case ma_standard_channel_map_flac:
41842         {
41843             ma_get_standard_channel_map_flac(channels, pChannelMap);
41844         } break;
41845
41846         case ma_standard_channel_map_vorbis:
41847         {
41848             ma_get_standard_channel_map_vorbis(channels, pChannelMap);
41849         } break;
41850
41851         case ma_standard_channel_map_sound4:
41852         {
41853             ma_get_standard_channel_map_sound4(channels, pChannelMap);
41854         } break;
41855
41856         case ma_standard_channel_map_sndio:
41857         {
41858             ma_get_standard_channel_map_sndio(channels, pChannelMap);
41859         } break;
41860
41861         case ma_standard_channel_map_microsoft: /* Also default. */
41862         /*case ma_standard_channel_map_default;*/
41863         default:
41864         {
41865             ma_get_standard_channel_map_microsoft(channels, pChannelMap);
41866         } break;
41867     }
41868 }
41869
41870 MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels)
41871 {
41872     if (pOut != NULL && pIn != NULL && channels > 0) {
41873         MA_COPY_MEMORY(pOut, pIn, sizeof(*pOut) * channels);
41874     }
41875 }
41876
41877 MA_API void ma_channel_map_copy_or_default(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels)
41878 {
41879     if (pOut == NULL || channels == 0) {
41880         return;
41881     }
41882
41883     if (pIn != NULL) {
41884         ma_channel_map_copy(pOut, pIn, channels);
41885     } else {
41886         ma_get_standard_channel_map(ma_standard_channel_map_default, channels, pOut);
41887     }
41888 }
41889
41890 MA_API ma_bool32 ma_channel_map_valid(ma_uint32 channels, const ma_channel* pChannelMap)
41891 {
41892     if (pChannelMap == NULL) {
41893         return MA_FALSE;
41894     }
41895
41896     /* A channel count of 0 is invalid. */
41897     if (channels == 0) {
41898         return MA_FALSE;
41899     }
41900
41901     /* It does not make sense to have a mono channel when there is more than 1 channel. */
41902     if (channels > 1) {
41903         ma_uint32 iChannel;
41904         for (iChannel = 0; iChannel < channels; ++iChannel) {
41905             if (pChannelMap[iChannel] == MA_CHANNEL_MONO) {
41906                 return MA_FALSE;
41907             }
41908         }
41909     }
41910
41911     return MA_TRUE;
41912 }
41913
41914 MA_API ma_bool32 ma_channel_map_equal(ma_uint32 channels, const ma_channel* pChannelMapA, const ma_channel* pChannelMapB)
41915 {
41916     ma_uint32 iChannel;
41917
41918     if (pChannelMapA == pChannelMapB) {
41919         return MA_TRUE;
41920     }
41921
41922     for (iChannel = 0; iChannel < channels; ++iChannel) {
41923         if (pChannelMapA[iChannel] != pChannelMapB[iChannel]) {
41924             return MA_FALSE;
41925         }
41926     }
41927
41928     return MA_TRUE;
41929 }
41930
41931 MA_API ma_bool32 ma_channel_map_blank(ma_uint32 channels, const ma_channel* pChannelMap)
41932 {
41933     ma_uint32 iChannel;
41934
41935     for (iChannel = 0; iChannel < channels; ++iChannel) {
41936         if (pChannelMap[iChannel] != MA_CHANNEL_NONE) {
41937             return MA_FALSE;
41938         }
41939     }
41940
41941     return MA_TRUE;
41942 }
41943
41944 MA_API ma_bool32 ma_channel_map_contains_channel_position(ma_uint32 channels, const ma_channel* pChannelMap, ma_channel channelPosition)
41945 {
41946     ma_uint32 iChannel;
41947
41948     for (iChannel = 0; iChannel < channels; ++iChannel) {
41949         if (pChannelMap[iChannel] == channelPosition) {
41950             return MA_TRUE;
41951         }
41952     }
41953
41954     return MA_FALSE;
41955 }
41956
41957
41958
41959 /**************************************************************************************************************************************************************
41960
41961 Conversion Helpers
41962
41963 **************************************************************************************************************************************************************/
41964 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)
41965 {
41966     ma_data_converter_config config;
41967
41968     config = ma_data_converter_config_init(formatIn, formatOut, channelsIn, channelsOut, sampleRateIn, sampleRateOut);
41969     ma_get_standard_channel_map(ma_standard_channel_map_default, channelsOut, config.channelMapOut);
41970     ma_get_standard_channel_map(ma_standard_channel_map_default, channelsIn,  config.channelMapIn);
41971     config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
41972
41973     return ma_convert_frames_ex(pOut, frameCountOut, pIn, frameCountIn, &config);
41974 }
41975
41976 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)
41977 {
41978     ma_result result;
41979     ma_data_converter converter;
41980
41981     if (frameCountIn == 0 || pConfig == NULL) {
41982         return 0;
41983     }
41984
41985     result = ma_data_converter_init(pConfig, &converter);
41986     if (result != MA_SUCCESS) {
41987         return 0;   /* Failed to initialize the data converter. */
41988     }
41989
41990     if (pOut == NULL) {
41991         frameCountOut = ma_data_converter_get_expected_output_frame_count(&converter, frameCountIn);
41992     } else {
41993         result = ma_data_converter_process_pcm_frames(&converter, pIn, &frameCountIn, pOut, &frameCountOut);
41994         if (result != MA_SUCCESS) {
41995             frameCountOut = 0;
41996         }
41997     }
41998
41999     ma_data_converter_uninit(&converter);
42000     return frameCountOut;
42001 }
42002
42003
42004 /**************************************************************************************************************************************************************
42005
42006 Ring Buffer
42007
42008 **************************************************************************************************************************************************************/
42009 static MA_INLINE ma_uint32 ma_rb__extract_offset_in_bytes(ma_uint32 encodedOffset)
42010 {
42011     return encodedOffset & 0x7FFFFFFF;
42012 }
42013
42014 static MA_INLINE ma_uint32 ma_rb__extract_offset_loop_flag(ma_uint32 encodedOffset)
42015 {
42016     return encodedOffset & 0x80000000;
42017 }
42018
42019 static MA_INLINE void* ma_rb__get_read_ptr(ma_rb* pRB)
42020 {
42021     MA_ASSERT(pRB != NULL);
42022     return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedReadOffset)));
42023 }
42024
42025 static MA_INLINE void* ma_rb__get_write_ptr(ma_rb* pRB)
42026 {
42027     MA_ASSERT(pRB != NULL);
42028     return ma_offset_ptr(pRB->pBuffer, ma_rb__extract_offset_in_bytes(c89atomic_load_32(&pRB->encodedWriteOffset)));
42029 }
42030
42031 static MA_INLINE ma_uint32 ma_rb__construct_offset(ma_uint32 offsetInBytes, ma_uint32 offsetLoopFlag)
42032 {
42033     return offsetLoopFlag | offsetInBytes;
42034 }
42035
42036 static MA_INLINE void ma_rb__deconstruct_offset(ma_uint32 encodedOffset, ma_uint32* pOffsetInBytes, ma_uint32* pOffsetLoopFlag)
42037 {
42038     MA_ASSERT(pOffsetInBytes != NULL);
42039     MA_ASSERT(pOffsetLoopFlag != NULL);
42040
42041     *pOffsetInBytes  = ma_rb__extract_offset_in_bytes(encodedOffset);
42042     *pOffsetLoopFlag = ma_rb__extract_offset_loop_flag(encodedOffset);
42043 }
42044
42045
42046 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)
42047 {
42048     ma_result result;
42049     const ma_uint32 maxSubBufferSize = 0x7FFFFFFF - (MA_SIMD_ALIGNMENT-1);
42050
42051     if (pRB == NULL) {
42052         return MA_INVALID_ARGS;
42053     }
42054
42055     if (subbufferSizeInBytes == 0 || subbufferCount == 0) {
42056         return MA_INVALID_ARGS;
42057     }
42058
42059     if (subbufferSizeInBytes > maxSubBufferSize) {
42060         return MA_INVALID_ARGS;    /* Maximum buffer size is ~2GB. The most significant bit is a flag for use internally. */
42061     }
42062
42063
42064     MA_ZERO_OBJECT(pRB);
42065
42066     result = ma_allocation_callbacks_init_copy(&pRB->allocationCallbacks, pAllocationCallbacks);
42067     if (result != MA_SUCCESS) {
42068         return result;
42069     }
42070
42071     pRB->subbufferSizeInBytes = (ma_uint32)subbufferSizeInBytes;
42072     pRB->subbufferCount = (ma_uint32)subbufferCount;
42073
42074     if (pOptionalPreallocatedBuffer != NULL) {
42075         pRB->subbufferStrideInBytes = (ma_uint32)subbufferStrideInBytes;
42076         pRB->pBuffer = pOptionalPreallocatedBuffer;
42077     } else {
42078         size_t bufferSizeInBytes;
42079
42080         /*
42081         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
42082         we need to make sure the stride is a multiple of MA_SIMD_ALIGNMENT.
42083         */
42084         pRB->subbufferStrideInBytes = (pRB->subbufferSizeInBytes + (MA_SIMD_ALIGNMENT-1)) & ~MA_SIMD_ALIGNMENT;
42085
42086         bufferSizeInBytes = (size_t)pRB->subbufferCount*pRB->subbufferStrideInBytes;
42087         pRB->pBuffer = ma_aligned_malloc(bufferSizeInBytes, MA_SIMD_ALIGNMENT, &pRB->allocationCallbacks);
42088         if (pRB->pBuffer == NULL) {
42089             return MA_OUT_OF_MEMORY;
42090         }
42091
42092         MA_ZERO_MEMORY(pRB->pBuffer, bufferSizeInBytes);
42093         pRB->ownsBuffer = MA_TRUE;
42094     }
42095
42096     return MA_SUCCESS;
42097 }
42098
42099 MA_API ma_result ma_rb_init(size_t bufferSizeInBytes, void* pOptionalPreallocatedBuffer, const ma_allocation_callbacks* pAllocationCallbacks, ma_rb* pRB)
42100 {
42101     return ma_rb_init_ex(bufferSizeInBytes, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
42102 }
42103
42104 MA_API void ma_rb_uninit(ma_rb* pRB)
42105 {
42106     if (pRB == NULL) {
42107         return;
42108     }
42109
42110     if (pRB->ownsBuffer) {
42111         ma_aligned_free(pRB->pBuffer, &pRB->allocationCallbacks);
42112     }
42113 }
42114
42115 MA_API void ma_rb_reset(ma_rb* pRB)
42116 {
42117     if (pRB == NULL) {
42118         return;
42119     }
42120
42121     c89atomic_exchange_32(&pRB->encodedReadOffset, 0);
42122     c89atomic_exchange_32(&pRB->encodedWriteOffset, 0);
42123 }
42124
42125 MA_API ma_result ma_rb_acquire_read(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
42126 {
42127     ma_uint32 writeOffset;
42128     ma_uint32 writeOffsetInBytes;
42129     ma_uint32 writeOffsetLoopFlag;
42130     ma_uint32 readOffset;
42131     ma_uint32 readOffsetInBytes;
42132     ma_uint32 readOffsetLoopFlag;
42133     size_t bytesAvailable;
42134     size_t bytesRequested;
42135
42136     if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) {
42137         return MA_INVALID_ARGS;
42138     }
42139
42140     /* The returned buffer should never move ahead of the write pointer. */
42141     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
42142     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
42143
42144     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
42145     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
42146
42147     /*
42148     The number of bytes available depends on whether or not the read and write pointers are on the same loop iteration. If so, we
42149     can only read up to the write pointer. If not, we can only read up to the end of the buffer.
42150     */
42151     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
42152         bytesAvailable = writeOffsetInBytes - readOffsetInBytes;
42153     } else {
42154         bytesAvailable = pRB->subbufferSizeInBytes - readOffsetInBytes;
42155     }
42156
42157     bytesRequested = *pSizeInBytes;
42158     if (bytesRequested > bytesAvailable) {
42159         bytesRequested = bytesAvailable;
42160     }
42161
42162     *pSizeInBytes = bytesRequested;
42163     (*ppBufferOut) = ma_rb__get_read_ptr(pRB);
42164
42165     return MA_SUCCESS;
42166 }
42167
42168 MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut)
42169 {
42170     ma_uint32 readOffset;
42171     ma_uint32 readOffsetInBytes;
42172     ma_uint32 readOffsetLoopFlag;
42173     ma_uint32 newReadOffsetInBytes;
42174     ma_uint32 newReadOffsetLoopFlag;
42175
42176     if (pRB == NULL) {
42177         return MA_INVALID_ARGS;
42178     }
42179
42180     /* Validate the buffer. */
42181     if (pBufferOut != ma_rb__get_read_ptr(pRB)) {
42182         return MA_INVALID_ARGS;
42183     }
42184
42185     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
42186     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
42187
42188     /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
42189     newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + sizeInBytes);
42190     if (newReadOffsetInBytes > pRB->subbufferSizeInBytes) {
42191         return MA_INVALID_ARGS;    /* <-- sizeInBytes will cause the read offset to overflow. */
42192     }
42193
42194     /* Move the read pointer back to the start if necessary. */
42195     newReadOffsetLoopFlag = readOffsetLoopFlag;
42196     if (newReadOffsetInBytes == pRB->subbufferSizeInBytes) {
42197         newReadOffsetInBytes = 0;
42198         newReadOffsetLoopFlag ^= 0x80000000;
42199     }
42200
42201     c89atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetLoopFlag, newReadOffsetInBytes));
42202     return MA_SUCCESS;
42203 }
42204
42205 MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut)
42206 {
42207     ma_uint32 readOffset;
42208     ma_uint32 readOffsetInBytes;
42209     ma_uint32 readOffsetLoopFlag;
42210     ma_uint32 writeOffset;
42211     ma_uint32 writeOffsetInBytes;
42212     ma_uint32 writeOffsetLoopFlag;
42213     size_t bytesAvailable;
42214     size_t bytesRequested;
42215
42216     if (pRB == NULL || pSizeInBytes == NULL || ppBufferOut == NULL) {
42217         return MA_INVALID_ARGS;
42218     }
42219
42220     /* The returned buffer should never overtake the read buffer. */
42221     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
42222     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
42223
42224     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
42225     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
42226
42227     /*
42228     In the case of writing, if the write pointer and the read pointer are on the same loop iteration we can only
42229     write up to the end of the buffer. Otherwise we can only write up to the read pointer. The write pointer should
42230     never overtake the read pointer.
42231     */
42232     if (writeOffsetLoopFlag == readOffsetLoopFlag) {
42233         bytesAvailable = pRB->subbufferSizeInBytes - writeOffsetInBytes;
42234     } else {
42235         bytesAvailable = readOffsetInBytes - writeOffsetInBytes;
42236     }
42237
42238     bytesRequested = *pSizeInBytes;
42239     if (bytesRequested > bytesAvailable) {
42240         bytesRequested = bytesAvailable;
42241     }
42242
42243     *pSizeInBytes = bytesRequested;
42244     *ppBufferOut  = ma_rb__get_write_ptr(pRB);
42245
42246     /* Clear the buffer if desired. */
42247     if (pRB->clearOnWriteAcquire) {
42248         MA_ZERO_MEMORY(*ppBufferOut, *pSizeInBytes);
42249     }
42250
42251     return MA_SUCCESS;
42252 }
42253
42254 MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes, void* pBufferOut)
42255 {
42256     ma_uint32 writeOffset;
42257     ma_uint32 writeOffsetInBytes;
42258     ma_uint32 writeOffsetLoopFlag;
42259     ma_uint32 newWriteOffsetInBytes;
42260     ma_uint32 newWriteOffsetLoopFlag;
42261
42262     if (pRB == NULL) {
42263         return MA_INVALID_ARGS;
42264     }
42265
42266     /* Validate the buffer. */
42267     if (pBufferOut != ma_rb__get_write_ptr(pRB)) {
42268         return MA_INVALID_ARGS;
42269     }
42270
42271     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
42272     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
42273
42274     /* Check that sizeInBytes is correct. It should never go beyond the end of the buffer. */
42275     newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + sizeInBytes);
42276     if (newWriteOffsetInBytes > pRB->subbufferSizeInBytes) {
42277         return MA_INVALID_ARGS;    /* <-- sizeInBytes will cause the read offset to overflow. */
42278     }
42279
42280     /* Move the read pointer back to the start if necessary. */
42281     newWriteOffsetLoopFlag = writeOffsetLoopFlag;
42282     if (newWriteOffsetInBytes == pRB->subbufferSizeInBytes) {
42283         newWriteOffsetInBytes = 0;
42284         newWriteOffsetLoopFlag ^= 0x80000000;
42285     }
42286
42287     c89atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetLoopFlag, newWriteOffsetInBytes));
42288     return MA_SUCCESS;
42289 }
42290
42291 MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes)
42292 {
42293     ma_uint32 readOffset;
42294     ma_uint32 readOffsetInBytes;
42295     ma_uint32 readOffsetLoopFlag;
42296     ma_uint32 writeOffset;
42297     ma_uint32 writeOffsetInBytes;
42298     ma_uint32 writeOffsetLoopFlag;
42299     ma_uint32 newReadOffsetInBytes;
42300     ma_uint32 newReadOffsetLoopFlag;
42301
42302     if (pRB == NULL || offsetInBytes > pRB->subbufferSizeInBytes) {
42303         return MA_INVALID_ARGS;
42304     }
42305
42306     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
42307     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
42308
42309     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
42310     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
42311
42312     newReadOffsetLoopFlag = readOffsetLoopFlag;
42313
42314     /* We cannot go past the write buffer. */
42315     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
42316         if ((readOffsetInBytes + offsetInBytes) > writeOffsetInBytes) {
42317             newReadOffsetInBytes = writeOffsetInBytes;
42318         } else {
42319             newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes);
42320         }
42321     } else {
42322         /* May end up looping. */
42323         if ((readOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) {
42324             newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes;
42325             newReadOffsetLoopFlag ^= 0x80000000;    /* <-- Looped. */
42326         } else {
42327             newReadOffsetInBytes = (ma_uint32)(readOffsetInBytes + offsetInBytes);
42328         }
42329     }
42330
42331     c89atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag));
42332     return MA_SUCCESS;
42333 }
42334
42335 MA_API ma_result ma_rb_seek_write(ma_rb* pRB, size_t offsetInBytes)
42336 {
42337     ma_uint32 readOffset;
42338     ma_uint32 readOffsetInBytes;
42339     ma_uint32 readOffsetLoopFlag;
42340     ma_uint32 writeOffset;
42341     ma_uint32 writeOffsetInBytes;
42342     ma_uint32 writeOffsetLoopFlag;
42343     ma_uint32 newWriteOffsetInBytes;
42344     ma_uint32 newWriteOffsetLoopFlag;
42345
42346     if (pRB == NULL) {
42347         return MA_INVALID_ARGS;
42348     }
42349
42350     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
42351     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
42352
42353     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
42354     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
42355
42356     newWriteOffsetLoopFlag = writeOffsetLoopFlag;
42357
42358     /* We cannot go past the write buffer. */
42359     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
42360         /* May end up looping. */
42361         if ((writeOffsetInBytes + offsetInBytes) >= pRB->subbufferSizeInBytes) {
42362             newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes) - pRB->subbufferSizeInBytes;
42363             newWriteOffsetLoopFlag ^= 0x80000000;    /* <-- Looped. */
42364         } else {
42365             newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes);
42366         }
42367     } else {
42368         if ((writeOffsetInBytes + offsetInBytes) > readOffsetInBytes) {
42369             newWriteOffsetInBytes = readOffsetInBytes;
42370         } else {
42371             newWriteOffsetInBytes = (ma_uint32)(writeOffsetInBytes + offsetInBytes);
42372         }
42373     }
42374
42375     c89atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag));
42376     return MA_SUCCESS;
42377 }
42378
42379 MA_API ma_int32 ma_rb_pointer_distance(ma_rb* pRB)
42380 {
42381     ma_uint32 readOffset;
42382     ma_uint32 readOffsetInBytes;
42383     ma_uint32 readOffsetLoopFlag;
42384     ma_uint32 writeOffset;
42385     ma_uint32 writeOffsetInBytes;
42386     ma_uint32 writeOffsetLoopFlag;
42387
42388     if (pRB == NULL) {
42389         return 0;
42390     }
42391
42392     readOffset = c89atomic_load_32(&pRB->encodedReadOffset);
42393     ma_rb__deconstruct_offset(readOffset, &readOffsetInBytes, &readOffsetLoopFlag);
42394
42395     writeOffset = c89atomic_load_32(&pRB->encodedWriteOffset);
42396     ma_rb__deconstruct_offset(writeOffset, &writeOffsetInBytes, &writeOffsetLoopFlag);
42397
42398     if (readOffsetLoopFlag == writeOffsetLoopFlag) {
42399         return writeOffsetInBytes - readOffsetInBytes;
42400     } else {
42401         return writeOffsetInBytes + (pRB->subbufferSizeInBytes - readOffsetInBytes);
42402     }
42403 }
42404
42405 MA_API ma_uint32 ma_rb_available_read(ma_rb* pRB)
42406 {
42407     ma_int32 dist;
42408
42409     if (pRB == NULL) {
42410         return 0;
42411     }
42412
42413     dist = ma_rb_pointer_distance(pRB);
42414     if (dist < 0) {
42415         return 0;
42416     }
42417
42418     return dist;
42419 }
42420
42421 MA_API ma_uint32 ma_rb_available_write(ma_rb* pRB)
42422 {
42423     if (pRB == NULL) {
42424         return 0;
42425     }
42426
42427     return (ma_uint32)(ma_rb_get_subbuffer_size(pRB) - ma_rb_pointer_distance(pRB));
42428 }
42429
42430 MA_API size_t ma_rb_get_subbuffer_size(ma_rb* pRB)
42431 {
42432     if (pRB == NULL) {
42433         return 0;
42434     }
42435
42436     return pRB->subbufferSizeInBytes;
42437 }
42438
42439 MA_API size_t ma_rb_get_subbuffer_stride(ma_rb* pRB)
42440 {
42441     if (pRB == NULL) {
42442         return 0;
42443     }
42444
42445     if (pRB->subbufferStrideInBytes == 0) {
42446         return (size_t)pRB->subbufferSizeInBytes;
42447     }
42448
42449     return (size_t)pRB->subbufferStrideInBytes;
42450 }
42451
42452 MA_API size_t ma_rb_get_subbuffer_offset(ma_rb* pRB, size_t subbufferIndex)
42453 {
42454     if (pRB == NULL) {
42455         return 0;
42456     }
42457
42458     return subbufferIndex * ma_rb_get_subbuffer_stride(pRB);
42459 }
42460
42461 MA_API void* ma_rb_get_subbuffer_ptr(ma_rb* pRB, size_t subbufferIndex, void* pBuffer)
42462 {
42463     if (pRB == NULL) {
42464         return NULL;
42465     }
42466
42467     return ma_offset_ptr(pBuffer, ma_rb_get_subbuffer_offset(pRB, subbufferIndex));
42468 }
42469
42470
42471
42472 static MA_INLINE ma_uint32 ma_pcm_rb_get_bpf(ma_pcm_rb* pRB)
42473 {
42474     MA_ASSERT(pRB != NULL);
42475
42476     return ma_get_bytes_per_frame(pRB->format, pRB->channels);
42477 }
42478
42479 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)
42480 {
42481     ma_uint32 bpf;
42482     ma_result result;
42483
42484     if (pRB == NULL) {
42485         return MA_INVALID_ARGS;
42486     }
42487
42488     MA_ZERO_OBJECT(pRB);
42489
42490     bpf = ma_get_bytes_per_frame(format, channels);
42491     if (bpf == 0) {
42492         return MA_INVALID_ARGS;
42493     }
42494
42495     result = ma_rb_init_ex(subbufferSizeInFrames*bpf, subbufferCount, subbufferStrideInFrames*bpf, pOptionalPreallocatedBuffer, pAllocationCallbacks, &pRB->rb);
42496     if (result != MA_SUCCESS) {
42497         return result;
42498     }
42499
42500     pRB->format   = format;
42501     pRB->channels = channels;
42502
42503     return MA_SUCCESS;
42504 }
42505
42506 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)
42507 {
42508     return ma_pcm_rb_init_ex(format, channels, bufferSizeInFrames, 1, 0, pOptionalPreallocatedBuffer, pAllocationCallbacks, pRB);
42509 }
42510
42511 MA_API void ma_pcm_rb_uninit(ma_pcm_rb* pRB)
42512 {
42513     if (pRB == NULL) {
42514         return;
42515     }
42516
42517     ma_rb_uninit(&pRB->rb);
42518 }
42519
42520 MA_API void ma_pcm_rb_reset(ma_pcm_rb* pRB)
42521 {
42522     if (pRB == NULL) {
42523         return;
42524     }
42525
42526     ma_rb_reset(&pRB->rb);
42527 }
42528
42529 MA_API ma_result ma_pcm_rb_acquire_read(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
42530 {
42531     size_t sizeInBytes;
42532     ma_result result;
42533
42534     if (pRB == NULL || pSizeInFrames == NULL) {
42535         return MA_INVALID_ARGS;
42536     }
42537
42538     sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB);
42539
42540     result = ma_rb_acquire_read(&pRB->rb, &sizeInBytes, ppBufferOut);
42541     if (result != MA_SUCCESS) {
42542         return result;
42543     }
42544
42545     *pSizeInFrames = (ma_uint32)(sizeInBytes / (size_t)ma_pcm_rb_get_bpf(pRB));
42546     return MA_SUCCESS;
42547 }
42548
42549 MA_API ma_result ma_pcm_rb_commit_read(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut)
42550 {
42551     if (pRB == NULL) {
42552         return MA_INVALID_ARGS;
42553     }
42554
42555     return ma_rb_commit_read(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut);
42556 }
42557
42558 MA_API ma_result ma_pcm_rb_acquire_write(ma_pcm_rb* pRB, ma_uint32* pSizeInFrames, void** ppBufferOut)
42559 {
42560     size_t sizeInBytes;
42561     ma_result result;
42562
42563     if (pRB == NULL) {
42564         return MA_INVALID_ARGS;
42565     }
42566
42567     sizeInBytes = *pSizeInFrames * ma_pcm_rb_get_bpf(pRB);
42568
42569     result = ma_rb_acquire_write(&pRB->rb, &sizeInBytes, ppBufferOut);
42570     if (result != MA_SUCCESS) {
42571         return result;
42572     }
42573
42574     *pSizeInFrames = (ma_uint32)(sizeInBytes / ma_pcm_rb_get_bpf(pRB));
42575     return MA_SUCCESS;
42576 }
42577
42578 MA_API ma_result ma_pcm_rb_commit_write(ma_pcm_rb* pRB, ma_uint32 sizeInFrames, void* pBufferOut)
42579 {
42580     if (pRB == NULL) {
42581         return MA_INVALID_ARGS;
42582     }
42583
42584     return ma_rb_commit_write(&pRB->rb, sizeInFrames * ma_pcm_rb_get_bpf(pRB), pBufferOut);
42585 }
42586
42587 MA_API ma_result ma_pcm_rb_seek_read(ma_pcm_rb* pRB, ma_uint32 offsetInFrames)
42588 {
42589     if (pRB == NULL) {
42590         return MA_INVALID_ARGS;
42591     }
42592
42593     return ma_rb_seek_read(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB));
42594 }
42595
42596 MA_API ma_result ma_pcm_rb_seek_write(ma_pcm_rb* pRB, ma_uint32 offsetInFrames)
42597 {
42598     if (pRB == NULL) {
42599         return MA_INVALID_ARGS;
42600     }
42601
42602     return ma_rb_seek_write(&pRB->rb, offsetInFrames * ma_pcm_rb_get_bpf(pRB));
42603 }
42604
42605 MA_API ma_int32 ma_pcm_rb_pointer_distance(ma_pcm_rb* pRB)
42606 {
42607     if (pRB == NULL) {
42608         return 0;
42609     }
42610
42611     return ma_rb_pointer_distance(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
42612 }
42613
42614 MA_API ma_uint32 ma_pcm_rb_available_read(ma_pcm_rb* pRB)
42615 {
42616     if (pRB == NULL) {
42617         return 0;
42618     }
42619
42620     return ma_rb_available_read(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
42621 }
42622
42623 MA_API ma_uint32 ma_pcm_rb_available_write(ma_pcm_rb* pRB)
42624 {
42625     if (pRB == NULL) {
42626         return 0;
42627     }
42628
42629     return ma_rb_available_write(&pRB->rb) / ma_pcm_rb_get_bpf(pRB);
42630 }
42631
42632 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_size(ma_pcm_rb* pRB)
42633 {
42634     if (pRB == NULL) {
42635         return 0;
42636     }
42637
42638     return (ma_uint32)(ma_rb_get_subbuffer_size(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
42639 }
42640
42641 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_stride(ma_pcm_rb* pRB)
42642 {
42643     if (pRB == NULL) {
42644         return 0;
42645     }
42646
42647     return (ma_uint32)(ma_rb_get_subbuffer_stride(&pRB->rb) / ma_pcm_rb_get_bpf(pRB));
42648 }
42649
42650 MA_API ma_uint32 ma_pcm_rb_get_subbuffer_offset(ma_pcm_rb* pRB, ma_uint32 subbufferIndex)
42651 {
42652     if (pRB == NULL) {
42653         return 0;
42654     }
42655
42656     return (ma_uint32)(ma_rb_get_subbuffer_offset(&pRB->rb, subbufferIndex) / ma_pcm_rb_get_bpf(pRB));
42657 }
42658
42659 MA_API void* ma_pcm_rb_get_subbuffer_ptr(ma_pcm_rb* pRB, ma_uint32 subbufferIndex, void* pBuffer)
42660 {
42661     if (pRB == NULL) {
42662         return NULL;
42663     }
42664
42665     return ma_rb_get_subbuffer_ptr(&pRB->rb, subbufferIndex, pBuffer);
42666 }
42667
42668
42669
42670 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)
42671 {
42672     ma_result result;
42673     ma_uint32 sizeInFrames;
42674
42675     sizeInFrames = (ma_uint32)ma_calculate_frame_count_after_resampling(sampleRate, captureInternalSampleRate, captureInternalPeriodSizeInFrames * 5);
42676     if (sizeInFrames == 0) {
42677         return MA_INVALID_ARGS;
42678     }
42679
42680     result = ma_pcm_rb_init(captureFormat, captureChannels, sizeInFrames, NULL, pAllocationCallbacks, &pRB->rb);
42681     if (result != MA_SUCCESS) {
42682         return result;
42683     }
42684
42685     /* Seek forward a bit so we have a bit of a buffer in case of desyncs. */
42686     ma_pcm_rb_seek_write((ma_pcm_rb*)pRB, captureInternalPeriodSizeInFrames * 2);
42687
42688     return MA_SUCCESS;
42689 }
42690
42691 MA_API ma_result ma_duplex_rb_uninit(ma_duplex_rb* pRB)
42692 {
42693     ma_pcm_rb_uninit((ma_pcm_rb*)pRB);
42694     return MA_SUCCESS;
42695 }
42696
42697
42698
42699 /**************************************************************************************************************************************************************
42700
42701 Miscellaneous Helpers
42702
42703 **************************************************************************************************************************************************************/
42704 MA_API const char* ma_result_description(ma_result result)
42705 {
42706     switch (result)
42707     {
42708         case MA_SUCCESS:                       return "No error";
42709         case MA_ERROR:                         return "Unknown error";
42710         case MA_INVALID_ARGS:                  return "Invalid argument";
42711         case MA_INVALID_OPERATION:             return "Invalid operation";
42712         case MA_OUT_OF_MEMORY:                 return "Out of memory";
42713         case MA_OUT_OF_RANGE:                  return "Out of range";
42714         case MA_ACCESS_DENIED:                 return "Permission denied";
42715         case MA_DOES_NOT_EXIST:                return "Resource does not exist";
42716         case MA_ALREADY_EXISTS:                return "Resource already exists";
42717         case MA_TOO_MANY_OPEN_FILES:           return "Too many open files";
42718         case MA_INVALID_FILE:                  return "Invalid file";
42719         case MA_TOO_BIG:                       return "Too large";
42720         case MA_PATH_TOO_LONG:                 return "Path too long";
42721         case MA_NAME_TOO_LONG:                 return "Name too long";
42722         case MA_NOT_DIRECTORY:                 return "Not a directory";
42723         case MA_IS_DIRECTORY:                  return "Is a directory";
42724         case MA_DIRECTORY_NOT_EMPTY:           return "Directory not empty";
42725         case MA_END_OF_FILE:                   return "End of file";
42726         case MA_NO_SPACE:                      return "No space available";
42727         case MA_BUSY:                          return "Device or resource busy";
42728         case MA_IO_ERROR:                      return "Input/output error";
42729         case MA_INTERRUPT:                     return "Interrupted";
42730         case MA_UNAVAILABLE:                   return "Resource unavailable";
42731         case MA_ALREADY_IN_USE:                return "Resource already in use";
42732         case MA_BAD_ADDRESS:                   return "Bad address";
42733         case MA_BAD_SEEK:                      return "Illegal seek";
42734         case MA_BAD_PIPE:                      return "Broken pipe";
42735         case MA_DEADLOCK:                      return "Deadlock";
42736         case MA_TOO_MANY_LINKS:                return "Too many links";
42737         case MA_NOT_IMPLEMENTED:               return "Not implemented";
42738         case MA_NO_MESSAGE:                    return "No message of desired type";
42739         case MA_BAD_MESSAGE:                   return "Invalid message";
42740         case MA_NO_DATA_AVAILABLE:             return "No data available";
42741         case MA_INVALID_DATA:                  return "Invalid data";
42742         case MA_TIMEOUT:                       return "Timeout";
42743         case MA_NO_NETWORK:                    return "Network unavailable";
42744         case MA_NOT_UNIQUE:                    return "Not unique";
42745         case MA_NOT_SOCKET:                    return "Socket operation on non-socket";
42746         case MA_NO_ADDRESS:                    return "Destination address required";
42747         case MA_BAD_PROTOCOL:                  return "Protocol wrong type for socket";
42748         case MA_PROTOCOL_UNAVAILABLE:          return "Protocol not available";
42749         case MA_PROTOCOL_NOT_SUPPORTED:        return "Protocol not supported";
42750         case MA_PROTOCOL_FAMILY_NOT_SUPPORTED: return "Protocol family not supported";
42751         case MA_ADDRESS_FAMILY_NOT_SUPPORTED:  return "Address family not supported";
42752         case MA_SOCKET_NOT_SUPPORTED:          return "Socket type not supported";
42753         case MA_CONNECTION_RESET:              return "Connection reset";
42754         case MA_ALREADY_CONNECTED:             return "Already connected";
42755         case MA_NOT_CONNECTED:                 return "Not connected";
42756         case MA_CONNECTION_REFUSED:            return "Connection refused";
42757         case MA_NO_HOST:                       return "No host";
42758         case MA_IN_PROGRESS:                   return "Operation in progress";
42759         case MA_CANCELLED:                     return "Operation cancelled";
42760         case MA_MEMORY_ALREADY_MAPPED:         return "Memory already mapped";
42761         case MA_AT_END:                        return "Reached end of collection";
42762
42763         case MA_FORMAT_NOT_SUPPORTED:          return "Format not supported";
42764         case MA_DEVICE_TYPE_NOT_SUPPORTED:     return "Device type not supported";
42765         case MA_SHARE_MODE_NOT_SUPPORTED:      return "Share mode not supported";
42766         case MA_NO_BACKEND:                    return "No backend";
42767         case MA_NO_DEVICE:                     return "No device";
42768         case MA_API_NOT_FOUND:                 return "API not found";
42769         case MA_INVALID_DEVICE_CONFIG:         return "Invalid device config";
42770
42771         case MA_DEVICE_NOT_INITIALIZED:        return "Device not initialized";
42772         case MA_DEVICE_NOT_STARTED:            return "Device not started";
42773
42774         case MA_FAILED_TO_INIT_BACKEND:        return "Failed to initialize backend";
42775         case MA_FAILED_TO_OPEN_BACKEND_DEVICE: return "Failed to open backend device";
42776         case MA_FAILED_TO_START_BACKEND_DEVICE: return "Failed to start backend device";
42777         case MA_FAILED_TO_STOP_BACKEND_DEVICE: return "Failed to stop backend device";
42778
42779         default:                               return "Unknown error";
42780     }
42781 }
42782
42783 MA_API void* ma_malloc(size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
42784 {
42785     if (pAllocationCallbacks != NULL) {
42786         return ma__malloc_from_callbacks(sz, pAllocationCallbacks);
42787     } else {
42788         return ma__malloc_default(sz, NULL);
42789     }
42790 }
42791
42792 MA_API void* ma_realloc(void* p, size_t sz, const ma_allocation_callbacks* pAllocationCallbacks)
42793 {
42794     if (pAllocationCallbacks != NULL) {
42795         if (pAllocationCallbacks->onRealloc != NULL) {
42796             return pAllocationCallbacks->onRealloc(p, sz, pAllocationCallbacks->pUserData);
42797         } else {
42798             return NULL;    /* This requires a native implementation of realloc(). */
42799         }
42800     } else {
42801         return ma__realloc_default(p, sz, NULL);
42802     }
42803 }
42804
42805 MA_API void ma_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
42806 {
42807     if (pAllocationCallbacks != NULL) {
42808         ma__free_from_callbacks(p, pAllocationCallbacks);
42809     } else {
42810         ma__free_default(p, NULL);
42811     }
42812 }
42813
42814 MA_API void* ma_aligned_malloc(size_t sz, size_t alignment, const ma_allocation_callbacks* pAllocationCallbacks)
42815 {
42816     size_t extraBytes;
42817     void* pUnaligned;
42818     void* pAligned;
42819
42820     if (alignment == 0) {
42821         return 0;
42822     }
42823
42824     extraBytes = alignment-1 + sizeof(void*);
42825
42826     pUnaligned = ma_malloc(sz + extraBytes, pAllocationCallbacks);
42827     if (pUnaligned == NULL) {
42828         return NULL;
42829     }
42830
42831     pAligned = (void*)(((ma_uintptr)pUnaligned + extraBytes) & ~((ma_uintptr)(alignment-1)));
42832     ((void**)pAligned)[-1] = pUnaligned;
42833
42834     return pAligned;
42835 }
42836
42837 MA_API void ma_aligned_free(void* p, const ma_allocation_callbacks* pAllocationCallbacks)
42838 {
42839     ma_free(((void**)p)[-1], pAllocationCallbacks);
42840 }
42841
42842 MA_API const char* ma_get_format_name(ma_format format)
42843 {
42844     switch (format)
42845     {
42846         case ma_format_unknown: return "Unknown";
42847         case ma_format_u8:      return "8-bit Unsigned Integer";
42848         case ma_format_s16:     return "16-bit Signed Integer";
42849         case ma_format_s24:     return "24-bit Signed Integer (Tightly Packed)";
42850         case ma_format_s32:     return "32-bit Signed Integer";
42851         case ma_format_f32:     return "32-bit IEEE Floating Point";
42852         default:                return "Invalid";
42853     }
42854 }
42855
42856 MA_API void ma_blend_f32(float* pOut, float* pInA, float* pInB, float factor, ma_uint32 channels)
42857 {
42858     ma_uint32 i;
42859     for (i = 0; i < channels; ++i) {
42860         pOut[i] = ma_mix_f32(pInA[i], pInB[i], factor);
42861     }
42862 }
42863
42864
42865 MA_API ma_uint32 ma_get_bytes_per_sample(ma_format format)
42866 {
42867     ma_uint32 sizes[] = {
42868         0,  /* unknown */
42869         1,  /* u8 */
42870         2,  /* s16 */
42871         3,  /* s24 */
42872         4,  /* s32 */
42873         4,  /* f32 */
42874     };
42875     return sizes[format];
42876 }
42877
42878
42879
42880 MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead, ma_bool32 loop)
42881 {
42882     ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
42883
42884     /* Safety. */
42885     if (pFramesRead != NULL) {
42886         *pFramesRead = 0;
42887     }
42888
42889     if (pCallbacks == NULL) {
42890         return MA_INVALID_ARGS;
42891     }
42892
42893     if (pCallbacks->onRead == NULL) {
42894         return MA_NOT_IMPLEMENTED;
42895     }
42896
42897     /* A very small optimization for the non looping case. */
42898     if (loop == MA_FALSE) {
42899         return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead);
42900     } else {
42901         ma_format format;
42902         ma_uint32 channels;
42903         ma_uint32 sampleRate;
42904         if (ma_data_source_get_data_format(pDataSource, &format, &channels, &sampleRate) != MA_SUCCESS) {
42905             return pCallbacks->onRead(pDataSource, pFramesOut, frameCount, pFramesRead); /* We don't have a way to retrieve the data format which means we don't know how to offset the output buffer. Just read as much as we can. */
42906         } else {
42907             ma_result result = MA_SUCCESS;
42908             ma_uint64 totalFramesProcessed;
42909             void* pRunningFramesOut = pFramesOut;
42910
42911             totalFramesProcessed = 0;
42912             while (totalFramesProcessed < frameCount) {
42913                 ma_uint64 framesProcessed;
42914                 ma_uint64 framesRemaining = frameCount - totalFramesProcessed;
42915
42916                 result = pCallbacks->onRead(pDataSource, pRunningFramesOut, framesRemaining, &framesProcessed);
42917                 totalFramesProcessed += framesProcessed;
42918
42919                 /*
42920                 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
42921                 not necessarily considered an error.
42922                 */
42923                 if (result != MA_SUCCESS && result != MA_AT_END) {
42924                     break;
42925                 }
42926
42927                 /*
42928                 We can determine if we've reached the end by checking the return value of the onRead() callback. If it's less than what we requested it means
42929                 we've reached the end. To loop back to the start, all we need to do is seek back to the first frame.
42930                 */
42931                 if (framesProcessed < framesRemaining || result == MA_AT_END) {
42932                     if (ma_data_source_seek_to_pcm_frame(pDataSource, 0) != MA_SUCCESS) {
42933                         break;
42934                     }
42935                 }
42936
42937                 if (pRunningFramesOut != NULL) {
42938                     pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesProcessed * ma_get_bytes_per_frame(format, channels));
42939                 }
42940             }
42941
42942             if (pFramesRead != NULL) {
42943                 *pFramesRead = totalFramesProcessed;
42944             }
42945
42946             return result;
42947         }
42948     }
42949 }
42950
42951 MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked, ma_bool32 loop)
42952 {
42953     return ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, pFramesSeeked, loop);
42954 }
42955
42956 MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex)
42957 {
42958     ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
42959     if (pCallbacks == NULL || pCallbacks->onSeek == NULL) {
42960         return MA_INVALID_ARGS;
42961     }
42962
42963     return pCallbacks->onSeek(pDataSource, frameIndex);
42964 }
42965
42966 MA_API ma_result ma_data_source_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount)
42967 {
42968     ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
42969     if (pCallbacks == NULL || pCallbacks->onMap == NULL) {
42970         return MA_INVALID_ARGS;
42971     }
42972
42973     return pCallbacks->onMap(pDataSource, ppFramesOut, pFrameCount);
42974 }
42975
42976 MA_API ma_result ma_data_source_unmap(ma_data_source* pDataSource, ma_uint64 frameCount)
42977 {
42978     ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
42979     if (pCallbacks == NULL || pCallbacks->onUnmap == NULL) {
42980         return MA_INVALID_ARGS;
42981     }
42982
42983     return pCallbacks->onUnmap(pDataSource, frameCount);
42984 }
42985
42986 MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
42987 {
42988     ma_result result;
42989     ma_format format;
42990     ma_uint32 channels;
42991     ma_uint32 sampleRate;
42992     ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
42993
42994     if (pFormat != NULL) {
42995         *pFormat = ma_format_unknown;
42996     }
42997
42998     if (pChannels != NULL) {
42999         *pChannels = 0;
43000     }
43001
43002     if (pSampleRate != NULL) {
43003         *pSampleRate = 0;
43004     }
43005
43006     if (pCallbacks == NULL || pCallbacks->onGetDataFormat == NULL) {
43007         return MA_INVALID_ARGS;
43008     }
43009
43010     result = pCallbacks->onGetDataFormat(pDataSource, &format, &channels, &sampleRate);
43011     if (result != MA_SUCCESS) {
43012         return result;
43013     }
43014
43015     if (pFormat != NULL) {
43016         *pFormat = format;
43017     }
43018     if (pChannels != NULL) {
43019         *pChannels = channels;
43020     }
43021     if (pSampleRate != NULL) {
43022         *pSampleRate = sampleRate;
43023     }
43024
43025     return MA_SUCCESS;
43026 }
43027
43028 MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor)
43029 {
43030     ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
43031
43032     if (pCursor == NULL) {
43033         return MA_INVALID_ARGS;
43034     }
43035
43036     *pCursor = 0;
43037
43038     if (pCallbacks == NULL) {
43039         return MA_INVALID_ARGS;
43040     }
43041
43042     if (pCallbacks->onGetCursor == NULL) {
43043         return MA_NOT_IMPLEMENTED;
43044     }
43045
43046     return pCallbacks->onGetCursor(pDataSource, pCursor);
43047 }
43048
43049 MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength)
43050 {
43051     ma_data_source_callbacks* pCallbacks = (ma_data_source_callbacks*)pDataSource;
43052
43053     if (pLength == NULL) {
43054         return MA_INVALID_ARGS;
43055     }
43056
43057     *pLength = 0;
43058
43059     if (pCallbacks == NULL) {
43060         return MA_INVALID_ARGS;
43061     }
43062
43063     if (pCallbacks->onGetLength == NULL) {
43064         return MA_NOT_IMPLEMENTED;
43065     }
43066
43067     return pCallbacks->onGetLength(pDataSource, pLength);
43068 }
43069
43070
43071
43072
43073 static ma_result ma_audio_buffer_ref__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
43074 {
43075     ma_uint64 framesRead = ma_audio_buffer_ref_read_pcm_frames((ma_audio_buffer_ref*)pDataSource, pFramesOut, frameCount, MA_FALSE);
43076
43077     if (pFramesRead != NULL) {
43078         *pFramesRead = framesRead;
43079     }
43080
43081     if (framesRead < frameCount) {
43082         return MA_AT_END;
43083     }
43084
43085     return MA_SUCCESS;
43086 }
43087
43088 static ma_result ma_audio_buffer_ref__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
43089 {
43090     return ma_audio_buffer_ref_seek_to_pcm_frame((ma_audio_buffer_ref*)pDataSource, frameIndex);
43091 }
43092
43093 static ma_result ma_audio_buffer_ref__data_source_on_map(ma_data_source* pDataSource, void** ppFramesOut, ma_uint64* pFrameCount)
43094 {
43095     return ma_audio_buffer_ref_map((ma_audio_buffer_ref*)pDataSource, ppFramesOut, pFrameCount);
43096 }
43097
43098 static ma_result ma_audio_buffer_ref__data_source_on_unmap(ma_data_source* pDataSource, ma_uint64 frameCount)
43099 {
43100     return ma_audio_buffer_ref_unmap((ma_audio_buffer_ref*)pDataSource, frameCount);
43101 }
43102
43103 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)
43104 {
43105     ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource;
43106
43107     *pFormat     = pAudioBufferRef->format;
43108     *pChannels   = pAudioBufferRef->channels;
43109     *pSampleRate = 0;   /* There is no notion of a sample rate with audio buffers. */
43110
43111     return MA_SUCCESS;
43112 }
43113
43114 static ma_result ma_audio_buffer_ref__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
43115 {
43116     ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource;
43117
43118     *pCursor = pAudioBufferRef->cursor;
43119
43120     return MA_SUCCESS;
43121 }
43122
43123 static ma_result ma_audio_buffer_ref__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
43124 {
43125     ma_audio_buffer_ref* pAudioBufferRef = (ma_audio_buffer_ref*)pDataSource;
43126
43127     *pLength = pAudioBufferRef->sizeInFrames;
43128
43129     return MA_SUCCESS;
43130 }
43131
43132 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)
43133 {
43134     if (pAudioBufferRef == NULL) {
43135         return MA_INVALID_ARGS;
43136     }
43137
43138     MA_ZERO_OBJECT(pAudioBufferRef);
43139
43140     pAudioBufferRef->ds.onRead          = ma_audio_buffer_ref__data_source_on_read;
43141     pAudioBufferRef->ds.onSeek          = ma_audio_buffer_ref__data_source_on_seek;
43142     pAudioBufferRef->ds.onMap           = ma_audio_buffer_ref__data_source_on_map;
43143     pAudioBufferRef->ds.onUnmap         = ma_audio_buffer_ref__data_source_on_unmap;
43144     pAudioBufferRef->ds.onGetDataFormat = ma_audio_buffer_ref__data_source_on_get_data_format;
43145     pAudioBufferRef->ds.onGetCursor     = ma_audio_buffer_ref__data_source_on_get_cursor;
43146     pAudioBufferRef->ds.onGetLength     = ma_audio_buffer_ref__data_source_on_get_length;
43147     pAudioBufferRef->format             = format;
43148     pAudioBufferRef->channels           = channels;
43149     pAudioBufferRef->cursor             = 0;
43150     pAudioBufferRef->sizeInFrames       = sizeInFrames;
43151     pAudioBufferRef->pData              = pData;
43152
43153     return MA_SUCCESS;
43154 }
43155
43156 MA_API ma_result ma_audio_buffer_ref_set_data(ma_audio_buffer_ref* pAudioBufferRef, const void* pData, ma_uint64 sizeInFrames)
43157 {
43158     if (pAudioBufferRef == NULL) {
43159         return MA_INVALID_ARGS;
43160     }
43161
43162     pAudioBufferRef->cursor       = 0;
43163     pAudioBufferRef->sizeInFrames = sizeInFrames;
43164     pAudioBufferRef->pData        = pData;
43165
43166     return MA_SUCCESS;
43167 }
43168
43169 MA_API ma_uint64 ma_audio_buffer_ref_read_pcm_frames(ma_audio_buffer_ref* pAudioBufferRef, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop)
43170 {
43171     ma_uint64 totalFramesRead = 0;
43172
43173     if (pAudioBufferRef == NULL) {
43174         return 0;
43175     }
43176
43177     if (frameCount == 0) {
43178         return 0;
43179     }
43180
43181     while (totalFramesRead < frameCount) {
43182         ma_uint64 framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
43183         ma_uint64 framesRemaining = frameCount - totalFramesRead;
43184         ma_uint64 framesToRead;
43185
43186         framesToRead = framesRemaining;
43187         if (framesToRead > framesAvailable) {
43188             framesToRead = framesAvailable;
43189         }
43190
43191         if (pFramesOut != NULL) {
43192             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);
43193         }
43194
43195         totalFramesRead += framesToRead;
43196
43197         pAudioBufferRef->cursor += framesToRead;
43198         if (pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames) {
43199             if (loop) {
43200                 pAudioBufferRef->cursor = 0;
43201             } else {
43202                 break;  /* We've reached the end and we're not looping. Done. */
43203             }
43204         }
43205
43206         MA_ASSERT(pAudioBufferRef->cursor < pAudioBufferRef->sizeInFrames);
43207     }
43208
43209     return totalFramesRead;
43210 }
43211
43212 MA_API ma_result ma_audio_buffer_ref_seek_to_pcm_frame(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameIndex)
43213 {
43214     if (pAudioBufferRef == NULL) {
43215         return MA_INVALID_ARGS;
43216     }
43217
43218     if (frameIndex > pAudioBufferRef->sizeInFrames) {
43219         return MA_INVALID_ARGS;
43220     }
43221
43222     pAudioBufferRef->cursor = (size_t)frameIndex;
43223
43224     return MA_SUCCESS;
43225 }
43226
43227 MA_API ma_result ma_audio_buffer_ref_map(ma_audio_buffer_ref* pAudioBufferRef, void** ppFramesOut, ma_uint64* pFrameCount)
43228 {
43229     ma_uint64 framesAvailable;
43230     ma_uint64 frameCount = 0;
43231
43232     if (ppFramesOut != NULL) {
43233         *ppFramesOut = NULL;    /* Safety. */
43234     }
43235
43236     if (pFrameCount != NULL) {
43237         frameCount = *pFrameCount;
43238         *pFrameCount = 0;       /* Safety. */
43239     }
43240
43241     if (pAudioBufferRef == NULL || ppFramesOut == NULL || pFrameCount == NULL) {
43242         return MA_INVALID_ARGS;
43243     }
43244
43245     framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
43246     if (frameCount > framesAvailable) {
43247         frameCount = framesAvailable;
43248     }
43249
43250     *ppFramesOut = ma_offset_ptr(pAudioBufferRef->pData, pAudioBufferRef->cursor * ma_get_bytes_per_frame(pAudioBufferRef->format, pAudioBufferRef->channels));
43251     *pFrameCount = frameCount;
43252
43253     return MA_SUCCESS;
43254 }
43255
43256 MA_API ma_result ma_audio_buffer_ref_unmap(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64 frameCount)
43257 {
43258     ma_uint64 framesAvailable;
43259
43260     if (pAudioBufferRef == NULL) {
43261         return MA_INVALID_ARGS;
43262     }
43263
43264     framesAvailable = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
43265     if (frameCount > framesAvailable) {
43266         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. */
43267     }
43268
43269     pAudioBufferRef->cursor += frameCount;
43270
43271     if (pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames) {
43272         return MA_AT_END;   /* Successful. Need to tell the caller that the end has been reached so that it can loop if desired. */
43273     } else {
43274         return MA_SUCCESS;
43275     }
43276 }
43277
43278 MA_API ma_result ma_audio_buffer_ref_at_end(ma_audio_buffer_ref* pAudioBufferRef)
43279 {
43280     if (pAudioBufferRef == NULL) {
43281         return MA_FALSE;
43282     }
43283
43284     return pAudioBufferRef->cursor == pAudioBufferRef->sizeInFrames;
43285 }
43286
43287 MA_API ma_result ma_audio_buffer_ref_get_available_frames(ma_audio_buffer_ref* pAudioBufferRef, ma_uint64* pAvailableFrames)
43288 {
43289     if (pAvailableFrames == NULL) {
43290         return MA_INVALID_ARGS;
43291     }
43292
43293     *pAvailableFrames = 0;
43294
43295     if (pAudioBufferRef == NULL) {
43296         return MA_INVALID_ARGS;
43297     }
43298
43299     if (pAudioBufferRef->sizeInFrames <= pAudioBufferRef->cursor) {
43300         *pAvailableFrames = 0;
43301     } else {
43302         *pAvailableFrames = pAudioBufferRef->sizeInFrames - pAudioBufferRef->cursor;
43303     }
43304
43305     return MA_SUCCESS;
43306 }
43307
43308
43309
43310
43311 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)
43312 {
43313     ma_audio_buffer_config config;
43314
43315     MA_ZERO_OBJECT(&config);
43316     config.format = format;
43317     config.channels = channels;
43318     config.sizeInFrames = sizeInFrames;
43319     config.pData = pData;
43320     ma_allocation_callbacks_init_copy(&config.allocationCallbacks, pAllocationCallbacks);
43321
43322     return config;
43323 }
43324
43325 static ma_result ma_audio_buffer_init_ex(const ma_audio_buffer_config* pConfig, ma_bool32 doCopy, ma_audio_buffer* pAudioBuffer)
43326 {
43327     ma_result result;
43328
43329     if (pAudioBuffer == NULL) {
43330         return MA_INVALID_ARGS;
43331     }
43332
43333     MA_ZERO_MEMORY(pAudioBuffer, sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData));   /* Safety. Don't overwrite the extra data. */
43334
43335     if (pConfig == NULL) {
43336         return MA_INVALID_ARGS;
43337     }
43338
43339     if (pConfig->sizeInFrames == 0) {
43340         return MA_INVALID_ARGS; /* Not allowing buffer sizes of 0 frames. */
43341     }
43342
43343     result = ma_audio_buffer_ref_init(pConfig->format, pConfig->channels, NULL, 0, &pAudioBuffer->ref);
43344     if (result != MA_SUCCESS) {
43345         return result;
43346     }
43347     
43348     ma_allocation_callbacks_init_copy(&pAudioBuffer->allocationCallbacks, &pConfig->allocationCallbacks);
43349
43350     if (doCopy) {
43351         ma_uint64 allocationSizeInBytes;
43352         void* pData;
43353
43354         allocationSizeInBytes = pConfig->sizeInFrames * ma_get_bytes_per_frame(pConfig->format, pConfig->channels);
43355         if (allocationSizeInBytes > MA_SIZE_MAX) {
43356             return MA_OUT_OF_MEMORY;    /* Too big. */
43357         }
43358
43359         pData = ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &pAudioBuffer->allocationCallbacks);   /* Safe cast to size_t. */
43360         if (pData == NULL) {
43361             return MA_OUT_OF_MEMORY;
43362         }
43363
43364         if (pConfig->pData != NULL) {
43365             ma_copy_pcm_frames(pData, pConfig->pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels);
43366         } else {
43367             ma_silence_pcm_frames(pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels);
43368         }
43369
43370         ma_audio_buffer_ref_set_data(&pAudioBuffer->ref, pData, pConfig->sizeInFrames);
43371         pAudioBuffer->ownsData = MA_TRUE;
43372     } else {
43373         ma_audio_buffer_ref_set_data(&pAudioBuffer->ref, pConfig->pData, pConfig->sizeInFrames);
43374         pAudioBuffer->ownsData = MA_FALSE;
43375     }
43376
43377     return MA_SUCCESS;
43378 }
43379
43380 static void ma_audio_buffer_uninit_ex(ma_audio_buffer* pAudioBuffer, ma_bool32 doFree)
43381 {
43382     if (pAudioBuffer == NULL) {
43383         return;
43384     }
43385
43386     if (pAudioBuffer->ownsData && pAudioBuffer->ref.pData != &pAudioBuffer->_pExtraData[0]) {
43387         ma__free_from_callbacks((void*)pAudioBuffer->ref.pData, &pAudioBuffer->allocationCallbacks);    /* Naugty const cast, but OK in this case since we've guarded it with the ownsData check. */
43388     }
43389
43390     if (doFree) {
43391         ma__free_from_callbacks(pAudioBuffer, &pAudioBuffer->allocationCallbacks);
43392     }
43393 }
43394
43395 MA_API ma_result ma_audio_buffer_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer)
43396 {
43397     return ma_audio_buffer_init_ex(pConfig, MA_FALSE, pAudioBuffer);
43398 }
43399
43400 MA_API ma_result ma_audio_buffer_init_copy(const ma_audio_buffer_config* pConfig, ma_audio_buffer* pAudioBuffer)
43401 {
43402     return ma_audio_buffer_init_ex(pConfig, MA_TRUE, pAudioBuffer);
43403 }
43404
43405 MA_API ma_result ma_audio_buffer_alloc_and_init(const ma_audio_buffer_config* pConfig, ma_audio_buffer** ppAudioBuffer)
43406 {
43407     ma_result result;
43408     ma_audio_buffer* pAudioBuffer;
43409     ma_audio_buffer_config innerConfig; /* We'll be making some changes to the config, so need to make a copy. */
43410     ma_uint64 allocationSizeInBytes;
43411
43412     if (ppAudioBuffer == NULL) {
43413         return MA_INVALID_ARGS;
43414     }
43415
43416     *ppAudioBuffer = NULL;  /* Safety. */
43417
43418     if (pConfig == NULL) {
43419         return MA_INVALID_ARGS;
43420     }
43421
43422     innerConfig = *pConfig;
43423     ma_allocation_callbacks_init_copy(&innerConfig.allocationCallbacks, &pConfig->allocationCallbacks);
43424
43425     allocationSizeInBytes = sizeof(*pAudioBuffer) - sizeof(pAudioBuffer->_pExtraData) + (pConfig->sizeInFrames * ma_get_bytes_per_frame(pConfig->format, pConfig->channels));
43426     if (allocationSizeInBytes > MA_SIZE_MAX) {
43427         return MA_OUT_OF_MEMORY;    /* Too big. */
43428     }
43429
43430     pAudioBuffer = (ma_audio_buffer*)ma__malloc_from_callbacks((size_t)allocationSizeInBytes, &innerConfig.allocationCallbacks);  /* Safe cast to size_t. */
43431     if (pAudioBuffer == NULL) {
43432         return MA_OUT_OF_MEMORY;
43433     }
43434
43435     if (pConfig->pData != NULL) {
43436         ma_copy_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->pData, pConfig->sizeInFrames, pConfig->format, pConfig->channels);
43437     } else {
43438         ma_silence_pcm_frames(&pAudioBuffer->_pExtraData[0], pConfig->sizeInFrames, pConfig->format, pConfig->channels);
43439     }
43440
43441     innerConfig.pData = &pAudioBuffer->_pExtraData[0];
43442
43443     result = ma_audio_buffer_init_ex(&innerConfig, MA_FALSE, pAudioBuffer);
43444     if (result != MA_SUCCESS) {
43445         ma__free_from_callbacks(pAudioBuffer, &innerConfig.allocationCallbacks);
43446         return result;
43447     }
43448
43449     *ppAudioBuffer = pAudioBuffer;
43450
43451     return MA_SUCCESS;
43452 }
43453
43454 MA_API void ma_audio_buffer_uninit(ma_audio_buffer* pAudioBuffer)
43455 {
43456     ma_audio_buffer_uninit_ex(pAudioBuffer, MA_FALSE);
43457 }
43458
43459 MA_API void ma_audio_buffer_uninit_and_free(ma_audio_buffer* pAudioBuffer)
43460 {
43461     ma_audio_buffer_uninit_ex(pAudioBuffer, MA_TRUE);
43462 }
43463
43464 MA_API ma_uint64 ma_audio_buffer_read_pcm_frames(ma_audio_buffer* pAudioBuffer, void* pFramesOut, ma_uint64 frameCount, ma_bool32 loop)
43465 {
43466     if (pAudioBuffer == NULL) {
43467         return 0;
43468     }
43469
43470     return ma_audio_buffer_ref_read_pcm_frames(&pAudioBuffer->ref, pFramesOut, frameCount, loop);
43471 }
43472
43473 MA_API ma_result ma_audio_buffer_seek_to_pcm_frame(ma_audio_buffer* pAudioBuffer, ma_uint64 frameIndex)
43474 {
43475     if (pAudioBuffer == NULL) {
43476         return MA_INVALID_ARGS;
43477     }
43478
43479     return ma_audio_buffer_ref_seek_to_pcm_frame(&pAudioBuffer->ref, frameIndex);
43480 }
43481
43482 MA_API ma_result ma_audio_buffer_map(ma_audio_buffer* pAudioBuffer, void** ppFramesOut, ma_uint64* pFrameCount)
43483 {
43484     if (ppFramesOut != NULL) {
43485         *ppFramesOut = NULL;    /* Safety. */
43486     }
43487
43488     if (pAudioBuffer == NULL) {
43489         if (pFrameCount != NULL) {
43490             *pFrameCount = 0;
43491         }
43492
43493         return MA_INVALID_ARGS;
43494     }
43495
43496     return ma_audio_buffer_ref_map(&pAudioBuffer->ref, ppFramesOut, pFrameCount);
43497 }
43498
43499 MA_API ma_result ma_audio_buffer_unmap(ma_audio_buffer* pAudioBuffer, ma_uint64 frameCount)
43500 {
43501     if (pAudioBuffer == NULL) {
43502         return MA_INVALID_ARGS;
43503     }
43504
43505     return ma_audio_buffer_ref_unmap(&pAudioBuffer->ref, frameCount);
43506 }
43507
43508 MA_API ma_result ma_audio_buffer_at_end(ma_audio_buffer* pAudioBuffer)
43509 {
43510     if (pAudioBuffer == NULL) {
43511         return MA_FALSE;
43512     }
43513
43514     return ma_audio_buffer_ref_at_end(&pAudioBuffer->ref);
43515 }
43516
43517 MA_API ma_result ma_audio_buffer_get_available_frames(ma_audio_buffer* pAudioBuffer, ma_uint64* pAvailableFrames)
43518 {
43519     if (pAvailableFrames == NULL) {
43520         return MA_INVALID_ARGS;
43521     }
43522
43523     *pAvailableFrames = 0;
43524
43525     if (pAudioBuffer == NULL) {
43526         return MA_INVALID_ARGS;
43527     }
43528
43529     return ma_audio_buffer_ref_get_available_frames(&pAudioBuffer->ref, pAvailableFrames);
43530 }
43531
43532
43533
43534 /**************************************************************************************************************************************************************
43535
43536 VFS
43537
43538 **************************************************************************************************************************************************************/
43539 MA_API ma_result ma_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
43540 {
43541     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43542
43543     if (pFile == NULL) {
43544         return MA_INVALID_ARGS;
43545     }
43546
43547     *pFile = NULL;
43548
43549     if (pVFS == NULL || pFilePath == NULL || openMode == 0) {
43550         return MA_INVALID_ARGS;
43551     }
43552
43553     if (pCallbacks->onOpen == NULL) {
43554         return MA_NOT_IMPLEMENTED;
43555     }
43556
43557     return pCallbacks->onOpen(pVFS, pFilePath, openMode, pFile);
43558 }
43559
43560 MA_API ma_result ma_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
43561 {
43562     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43563
43564     if (pFile == NULL) {
43565         return MA_INVALID_ARGS;
43566     }
43567
43568     *pFile = NULL;
43569
43570     if (pVFS == NULL || pFilePath == NULL || openMode == 0) {
43571         return MA_INVALID_ARGS;
43572     }
43573
43574     if (pCallbacks->onOpenW == NULL) {
43575         return MA_NOT_IMPLEMENTED;
43576     }
43577
43578     return pCallbacks->onOpenW(pVFS, pFilePath, openMode, pFile);
43579 }
43580
43581 MA_API ma_result ma_vfs_close(ma_vfs* pVFS, ma_vfs_file file)
43582 {
43583     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43584
43585     if (pVFS == NULL || file == NULL) {
43586         return MA_INVALID_ARGS;
43587     }
43588
43589     if (pCallbacks->onClose == NULL) {
43590         return MA_NOT_IMPLEMENTED;
43591     }
43592
43593     return pCallbacks->onClose(pVFS, file);
43594 }
43595
43596 MA_API ma_result ma_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
43597 {
43598     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43599
43600     if (pBytesRead != NULL) {
43601         *pBytesRead = 0;
43602     }
43603
43604     if (pVFS == NULL || file == NULL || pDst == NULL) {
43605         return MA_INVALID_ARGS;
43606     }
43607
43608     if (pCallbacks->onRead == NULL) {
43609         return MA_NOT_IMPLEMENTED;
43610     }
43611
43612     return pCallbacks->onRead(pVFS, file, pDst, sizeInBytes, pBytesRead);
43613 }
43614
43615 MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
43616 {
43617     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43618
43619     if (pBytesWritten != NULL) {
43620         *pBytesWritten = 0;
43621     }
43622
43623     if (pVFS == NULL || file == NULL || pSrc == NULL) {
43624         return MA_INVALID_ARGS;
43625     }
43626
43627     if (pCallbacks->onWrite == NULL) {
43628         return MA_NOT_IMPLEMENTED;
43629     }
43630
43631     return pCallbacks->onWrite(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
43632 }
43633
43634 MA_API ma_result ma_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
43635 {
43636     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43637
43638     if (pVFS == NULL || file == NULL) {
43639         return MA_INVALID_ARGS;
43640     }
43641
43642     if (pCallbacks->onSeek == NULL) {
43643         return MA_NOT_IMPLEMENTED;
43644     }
43645
43646     return pCallbacks->onSeek(pVFS, file, offset, origin);
43647 }
43648
43649 MA_API ma_result ma_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
43650 {
43651     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43652
43653     if (pCursor == NULL) {
43654         return MA_INVALID_ARGS;
43655     }
43656
43657     *pCursor = 0;
43658
43659     if (pVFS == NULL || file == NULL) {
43660         return MA_INVALID_ARGS;
43661     }
43662
43663     if (pCallbacks->onTell == NULL) {
43664         return MA_NOT_IMPLEMENTED;
43665     }
43666
43667     return pCallbacks->onTell(pVFS, file, pCursor);
43668 }
43669
43670 MA_API ma_result ma_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
43671 {
43672     ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
43673
43674     if (pInfo == NULL) {
43675         return MA_INVALID_ARGS;
43676     }
43677
43678     MA_ZERO_OBJECT(pInfo);
43679
43680     if (pVFS == NULL || file == NULL) {
43681         return MA_INVALID_ARGS;
43682     }
43683
43684     if (pCallbacks->onInfo == NULL) {
43685         return MA_NOT_IMPLEMENTED;
43686     }
43687
43688     return pCallbacks->onInfo(pVFS, file, pInfo);
43689 }
43690
43691
43692 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, ma_uint32 allocationType)
43693 {
43694     ma_result result;
43695     ma_vfs_file file;
43696     ma_file_info info;
43697     void* pData;
43698     size_t bytesRead;
43699
43700     (void)allocationType;
43701
43702     if (ppData != NULL) {
43703         *ppData = NULL;
43704     }
43705     if (pSize != NULL) {
43706         *pSize = 0;
43707     }
43708
43709     if (ppData == NULL) {
43710         return MA_INVALID_ARGS;
43711     }
43712
43713     if (pFilePath != NULL) {
43714         result = ma_vfs_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file);
43715     } else {
43716         result = ma_vfs_open_w(pVFS, pFilePathW, MA_OPEN_MODE_READ, &file);
43717     }
43718     if (result != MA_SUCCESS) {
43719         return result;
43720     }
43721
43722     result = ma_vfs_info(pVFS, file, &info);
43723     if (result != MA_SUCCESS) {
43724         ma_vfs_close(pVFS, file);
43725         return result;
43726     }
43727
43728     if (info.sizeInBytes > MA_SIZE_MAX) {
43729         ma_vfs_close(pVFS, file);
43730         return MA_TOO_BIG;
43731     }
43732
43733     pData = ma__malloc_from_callbacks((size_t)info.sizeInBytes, pAllocationCallbacks);  /* Safe cast. */
43734     if (pData == NULL) {
43735         ma_vfs_close(pVFS, file);
43736         return result;
43737     }
43738
43739     result = ma_vfs_read(pVFS, file, pData, (size_t)info.sizeInBytes, &bytesRead);  /* Safe cast. */
43740     ma_vfs_close(pVFS, file);
43741
43742     if (result != MA_SUCCESS) {
43743         ma__free_from_callbacks(pData, pAllocationCallbacks);
43744         return result;
43745     }
43746
43747     if (pSize != NULL) {
43748         *pSize = bytesRead;
43749     }
43750
43751     MA_ASSERT(ppData != NULL);
43752     *ppData = pData;
43753
43754     return MA_SUCCESS;
43755 }
43756
43757 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)
43758 {
43759     return ma_vfs_open_and_read_file_ex(pVFS, pFilePath, NULL, ppData, pSize, pAllocationCallbacks, 0 /*MA_ALLOCATION_TYPE_GENERAL*/);
43760 }
43761
43762 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)
43763 {
43764     return ma_vfs_open_and_read_file_ex(pVFS, NULL, pFilePath, ppData, pSize, pAllocationCallbacks, 0 /*MA_ALLOCATION_TYPE_GENERAL*/);
43765 }
43766
43767
43768 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
43769 static void ma_default_vfs__get_open_settings_win32(ma_uint32 openMode, DWORD* pDesiredAccess, DWORD* pShareMode, DWORD* pCreationDisposition)
43770 {
43771     *pDesiredAccess = 0;
43772     if ((openMode & MA_OPEN_MODE_READ) != 0) {
43773         *pDesiredAccess |= GENERIC_READ;
43774     }
43775     if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
43776         *pDesiredAccess |= GENERIC_WRITE;
43777     }
43778
43779     *pShareMode = 0;
43780     if ((openMode & MA_OPEN_MODE_READ) != 0) {
43781         *pShareMode |= FILE_SHARE_READ;
43782     }
43783
43784     if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
43785         *pCreationDisposition = CREATE_ALWAYS;  /* Opening in write mode. Truncate. */
43786     } else {
43787         *pCreationDisposition = OPEN_EXISTING;  /* Opening in read mode. File must exist. */
43788     }
43789 }
43790
43791 static ma_result ma_default_vfs_open__win32(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
43792 {
43793     HANDLE hFile;
43794     DWORD dwDesiredAccess;
43795     DWORD dwShareMode;
43796     DWORD dwCreationDisposition;
43797
43798     (void)pVFS;
43799
43800     ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition);
43801
43802     hFile = CreateFileA(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
43803     if (hFile == INVALID_HANDLE_VALUE) {
43804         return ma_result_from_GetLastError(GetLastError());
43805     }
43806
43807     *pFile = hFile;
43808     return MA_SUCCESS;
43809 }
43810
43811 static ma_result ma_default_vfs_open_w__win32(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
43812 {
43813     HANDLE hFile;
43814     DWORD dwDesiredAccess;
43815     DWORD dwShareMode;
43816     DWORD dwCreationDisposition;
43817
43818     (void)pVFS;
43819
43820     ma_default_vfs__get_open_settings_win32(openMode, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition);
43821
43822     hFile = CreateFileW(pFilePath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
43823     if (hFile == INVALID_HANDLE_VALUE) {
43824         return ma_result_from_GetLastError(GetLastError());
43825     }
43826
43827     *pFile = hFile;
43828     return MA_SUCCESS;
43829 }
43830
43831 static ma_result ma_default_vfs_close__win32(ma_vfs* pVFS, ma_vfs_file file)
43832 {
43833     (void)pVFS;
43834
43835     if (CloseHandle((HANDLE)file) == 0) {
43836         return ma_result_from_GetLastError(GetLastError());
43837     }
43838
43839     return MA_SUCCESS;
43840 }
43841
43842
43843 static ma_result ma_default_vfs_read__win32(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
43844 {
43845     ma_result result = MA_SUCCESS;
43846     size_t totalBytesRead;
43847
43848     (void)pVFS;
43849
43850     totalBytesRead = 0;
43851     while (totalBytesRead < sizeInBytes) {
43852         size_t bytesRemaining;
43853         DWORD bytesToRead;
43854         DWORD bytesRead;
43855         BOOL readResult;
43856
43857         bytesRemaining = sizeInBytes - totalBytesRead;
43858         if (bytesRemaining >= 0xFFFFFFFF) {
43859             bytesToRead = 0xFFFFFFFF;
43860         } else {
43861             bytesToRead = (DWORD)bytesRemaining;
43862         }
43863
43864         readResult = ReadFile((HANDLE)file, ma_offset_ptr(pDst, totalBytesRead), bytesToRead, &bytesRead, NULL);
43865         if (readResult == 1 && bytesRead == 0) {
43866             break;  /* EOF */
43867         }
43868
43869         totalBytesRead += bytesRead;
43870
43871         if (bytesRead < bytesToRead) {
43872             break;  /* EOF */
43873         }
43874
43875         if (readResult == 0) {
43876             result = ma_result_from_GetLastError(GetLastError());
43877             break;
43878         }
43879     }
43880
43881     if (pBytesRead != NULL) {
43882         *pBytesRead = totalBytesRead;
43883     }
43884
43885     return result;
43886 }
43887
43888 static ma_result ma_default_vfs_write__win32(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
43889 {
43890     ma_result result = MA_SUCCESS;
43891     size_t totalBytesWritten;
43892
43893     (void)pVFS;
43894
43895     totalBytesWritten = 0;
43896     while (totalBytesWritten < sizeInBytes) {
43897         size_t bytesRemaining;
43898         DWORD bytesToWrite;
43899         DWORD bytesWritten;
43900         BOOL writeResult;
43901
43902         bytesRemaining = sizeInBytes - totalBytesWritten;
43903         if (bytesRemaining >= 0xFFFFFFFF) {
43904             bytesToWrite = 0xFFFFFFFF;
43905         } else {
43906             bytesToWrite = (DWORD)bytesRemaining;
43907         }
43908
43909         writeResult = WriteFile((HANDLE)file, ma_offset_ptr(pSrc, totalBytesWritten), bytesToWrite, &bytesWritten, NULL);
43910         totalBytesWritten += bytesWritten;
43911
43912         if (writeResult == 0) {
43913             result = ma_result_from_GetLastError(GetLastError());
43914             break;
43915         }
43916     }
43917
43918     if (pBytesWritten != NULL) {
43919         *pBytesWritten = totalBytesWritten;
43920     }
43921
43922     return result;
43923 }
43924
43925
43926 static ma_result ma_default_vfs_seek__win32(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
43927 {
43928     LARGE_INTEGER liDistanceToMove;
43929     DWORD dwMoveMethod;
43930     BOOL result;
43931
43932     (void)pVFS;
43933
43934     liDistanceToMove.QuadPart = offset;
43935
43936     /*  */ if (origin == ma_seek_origin_current) {
43937         dwMoveMethod = FILE_CURRENT;
43938     } else if (origin == ma_seek_origin_end) {
43939         dwMoveMethod = FILE_END;
43940     } else {
43941         dwMoveMethod = FILE_BEGIN;
43942     }
43943
43944 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__)
43945     /* No SetFilePointerEx() so restrict to 31 bits. */
43946     if (origin > 0x7FFFFFFF) {
43947         return MA_OUT_OF_RANGE;
43948     }
43949
43950     result = SetFilePointer((HANDLE)file, (LONG)liDistanceToMove.QuadPart, NULL, dwMoveMethod);
43951 #else
43952     result = SetFilePointerEx((HANDLE)file, liDistanceToMove, NULL, dwMoveMethod);
43953 #endif
43954     if (result == 0) {
43955         return ma_result_from_GetLastError(GetLastError());
43956     }
43957
43958     return MA_SUCCESS;
43959 }
43960
43961 static ma_result ma_default_vfs_tell__win32(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
43962 {
43963     LARGE_INTEGER liZero;
43964     LARGE_INTEGER liTell;
43965     BOOL result;
43966 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__)
43967     LONG tell;
43968 #endif
43969
43970     (void)pVFS;
43971
43972     liZero.QuadPart = 0;
43973
43974 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__DMC__)
43975     result = SetFilePointer((HANDLE)file, (LONG)liZero.QuadPart, &tell, FILE_CURRENT);
43976     liTell.QuadPart = tell;
43977 #else
43978     result = SetFilePointerEx((HANDLE)file, liZero, &liTell, FILE_CURRENT);
43979 #endif
43980     if (result == 0) {
43981         return ma_result_from_GetLastError(GetLastError());
43982     }
43983
43984     if (pCursor != NULL) {
43985         *pCursor = liTell.QuadPart;
43986     }
43987
43988     return MA_SUCCESS;
43989 }
43990
43991 static ma_result ma_default_vfs_info__win32(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
43992 {
43993     BY_HANDLE_FILE_INFORMATION fi;
43994     BOOL result;
43995
43996     (void)pVFS;
43997
43998     result = GetFileInformationByHandle((HANDLE)file, &fi);
43999     if (result == 0) {
44000         return ma_result_from_GetLastError(GetLastError());
44001     }
44002
44003     pInfo->sizeInBytes = ((ma_uint64)fi.nFileSizeHigh << 32) | ((ma_uint64)fi.nFileSizeLow);
44004
44005     return MA_SUCCESS;
44006 }
44007 #else
44008 static ma_result ma_default_vfs_open__stdio(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
44009 {
44010     ma_result result;
44011     FILE* pFileStd;
44012     const char* pOpenModeStr;
44013
44014     MA_ASSERT(pFilePath != NULL);
44015     MA_ASSERT(openMode  != 0);
44016     MA_ASSERT(pFile     != NULL);
44017
44018     (void)pVFS;
44019
44020     if ((openMode & MA_OPEN_MODE_READ) != 0) {
44021         if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
44022             pOpenModeStr = "r+";
44023         } else {
44024             pOpenModeStr = "rb";
44025         }
44026     } else {
44027         pOpenModeStr = "wb";
44028     }
44029
44030     result = ma_fopen(&pFileStd, pFilePath, pOpenModeStr);
44031     if (result != MA_SUCCESS) {
44032         return result;
44033     }
44034
44035     *pFile = pFileStd;
44036
44037     return MA_SUCCESS;
44038 }
44039
44040 static ma_result ma_default_vfs_open_w__stdio(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
44041 {
44042     ma_result result;
44043     FILE* pFileStd;
44044     const wchar_t* pOpenModeStr;
44045
44046     MA_ASSERT(pFilePath != NULL);
44047     MA_ASSERT(openMode  != 0);
44048     MA_ASSERT(pFile     != NULL);
44049
44050     (void)pVFS;
44051
44052     if ((openMode & MA_OPEN_MODE_READ) != 0) {
44053         if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
44054             pOpenModeStr = L"r+";
44055         } else {
44056             pOpenModeStr = L"rb";
44057         }
44058     } else {
44059         pOpenModeStr = L"wb";
44060     }
44061
44062     result = ma_wfopen(&pFileStd, pFilePath, pOpenModeStr, (pVFS != NULL) ? &((ma_default_vfs*)pVFS)->allocationCallbacks : NULL);
44063     if (result != MA_SUCCESS) {
44064         return result;
44065     }
44066
44067     *pFile = pFileStd;
44068
44069     return MA_SUCCESS;
44070 }
44071
44072 static ma_result ma_default_vfs_close__stdio(ma_vfs* pVFS, ma_vfs_file file)
44073 {
44074     MA_ASSERT(file != NULL);
44075
44076     (void)pVFS;
44077
44078     fclose((FILE*)file);
44079
44080     return MA_SUCCESS;
44081 }
44082
44083 static ma_result ma_default_vfs_read__stdio(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
44084 {
44085     size_t result;
44086
44087     MA_ASSERT(file != NULL);
44088     MA_ASSERT(pDst != NULL);
44089
44090     (void)pVFS;
44091
44092     result = fread(pDst, 1, sizeInBytes, (FILE*)file);
44093
44094     if (pBytesRead != NULL) {
44095         *pBytesRead = result;
44096     }
44097
44098     if (result != sizeInBytes) {
44099         if (feof((FILE*)file)) {
44100             return MA_END_OF_FILE;
44101         } else {
44102             return ma_result_from_errno(ferror((FILE*)file));
44103         }
44104     }
44105
44106     return MA_SUCCESS;
44107 }
44108
44109 static ma_result ma_default_vfs_write__stdio(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
44110 {
44111     size_t result;
44112
44113     MA_ASSERT(file != NULL);
44114     MA_ASSERT(pSrc != NULL);
44115
44116     (void)pVFS;
44117
44118     result = fwrite(pSrc, 1, sizeInBytes, (FILE*)file);
44119
44120     if (pBytesWritten != NULL) {
44121         *pBytesWritten = result;
44122     }
44123
44124     if (result != sizeInBytes) {
44125         return ma_result_from_errno(ferror((FILE*)file));
44126     }
44127
44128     return MA_SUCCESS;
44129 }
44130
44131 static ma_result ma_default_vfs_seek__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
44132 {
44133     int result;
44134
44135     MA_ASSERT(file != NULL);
44136
44137     (void)pVFS;
44138
44139 #if defined(_WIN32)
44140     #if defined(_MSC_VER) && _MSC_VER > 1200
44141         result = _fseeki64((FILE*)file, offset, origin);
44142     #else
44143         /* No _fseeki64() so restrict to 31 bits. */
44144         if (origin > 0x7FFFFFFF) {
44145             return MA_OUT_OF_RANGE;
44146         }
44147
44148         result = fseek((FILE*)file, (int)offset, origin);
44149     #endif
44150 #else
44151     result = fseek((FILE*)file, (long int)offset, origin);
44152 #endif
44153     if (result != 0) {
44154         return MA_ERROR;
44155     }
44156
44157     return MA_SUCCESS;
44158 }
44159
44160 static ma_result ma_default_vfs_tell__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
44161 {
44162     ma_int64 result;
44163
44164     MA_ASSERT(file    != NULL);
44165     MA_ASSERT(pCursor != NULL);
44166
44167     (void)pVFS;
44168
44169 #if defined(_WIN32)
44170     #if defined(_MSC_VER) && _MSC_VER > 1200
44171         result = _ftelli64((FILE*)file);
44172     #else
44173         result = ftell((FILE*)file);
44174     #endif
44175 #else
44176     result = ftell((FILE*)file);
44177 #endif
44178
44179     *pCursor = result;
44180
44181     return MA_SUCCESS;
44182 }
44183
44184 #if !defined(_MSC_VER) && !((defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)) && !defined(MA_BSD)
44185 int fileno(FILE *stream);
44186 #endif
44187
44188 static ma_result ma_default_vfs_info__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
44189 {
44190     int fd;
44191     struct stat info;
44192
44193     MA_ASSERT(file  != NULL);
44194     MA_ASSERT(pInfo != NULL);
44195
44196     (void)pVFS;
44197
44198 #if defined(_MSC_VER)
44199     fd = _fileno((FILE*)file);
44200 #else
44201     fd =  fileno((FILE*)file);
44202 #endif
44203
44204     if (fstat(fd, &info) != 0) {
44205         return ma_result_from_errno(errno);
44206     }
44207
44208     pInfo->sizeInBytes = info.st_size;
44209
44210     return MA_SUCCESS;
44211 }
44212 #endif
44213
44214
44215 static ma_result ma_default_vfs_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
44216 {
44217     if (pFile == NULL) {
44218         return MA_INVALID_ARGS;
44219     }
44220
44221     *pFile = NULL;
44222
44223     if (pFilePath == NULL || openMode == 0) {
44224         return MA_INVALID_ARGS;
44225     }
44226
44227 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44228     return ma_default_vfs_open__win32(pVFS, pFilePath, openMode, pFile);
44229 #else
44230     return ma_default_vfs_open__stdio(pVFS, pFilePath, openMode, pFile);
44231 #endif
44232 }
44233
44234 static ma_result ma_default_vfs_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
44235 {
44236     if (pFile == NULL) {
44237         return MA_INVALID_ARGS;
44238     }
44239
44240     *pFile = NULL;
44241
44242     if (pFilePath == NULL || openMode == 0) {
44243         return MA_INVALID_ARGS;
44244     }
44245
44246 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44247     return ma_default_vfs_open_w__win32(pVFS, pFilePath, openMode, pFile);
44248 #else
44249     return ma_default_vfs_open_w__stdio(pVFS, pFilePath, openMode, pFile);
44250 #endif
44251 }
44252
44253 static ma_result ma_default_vfs_close(ma_vfs* pVFS, ma_vfs_file file)
44254 {
44255     if (file == NULL) {
44256         return MA_INVALID_ARGS;
44257     }
44258
44259 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44260     return ma_default_vfs_close__win32(pVFS, file);
44261 #else
44262     return ma_default_vfs_close__stdio(pVFS, file);
44263 #endif
44264 }
44265
44266 static ma_result ma_default_vfs_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
44267 {
44268     if (pBytesRead != NULL) {
44269         *pBytesRead = 0;
44270     }
44271
44272     if (file == NULL || pDst == NULL) {
44273         return MA_INVALID_ARGS;
44274     }
44275
44276 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44277     return ma_default_vfs_read__win32(pVFS, file, pDst, sizeInBytes, pBytesRead);
44278 #else
44279     return ma_default_vfs_read__stdio(pVFS, file, pDst, sizeInBytes, pBytesRead);
44280 #endif
44281 }
44282
44283 static ma_result ma_default_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc, size_t sizeInBytes, size_t* pBytesWritten)
44284 {
44285     if (pBytesWritten != NULL) {
44286         *pBytesWritten = 0;
44287     }
44288
44289     if (file == NULL || pSrc == NULL) {
44290         return MA_INVALID_ARGS;
44291     }
44292
44293 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44294     return ma_default_vfs_write__win32(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
44295 #else
44296     return ma_default_vfs_write__stdio(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
44297 #endif
44298 }
44299
44300 static ma_result ma_default_vfs_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
44301 {
44302     if (file == NULL) {
44303         return MA_INVALID_ARGS;
44304     }
44305
44306 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44307     return ma_default_vfs_seek__win32(pVFS, file, offset, origin);
44308 #else
44309     return ma_default_vfs_seek__stdio(pVFS, file, offset, origin);
44310 #endif
44311 }
44312
44313 static ma_result ma_default_vfs_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
44314 {
44315     if (pCursor == NULL) {
44316         return MA_INVALID_ARGS;
44317     }
44318
44319     *pCursor = 0;
44320
44321     if (file == NULL) {
44322         return MA_INVALID_ARGS;
44323     }
44324
44325 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44326     return ma_default_vfs_tell__win32(pVFS, file, pCursor);
44327 #else
44328     return ma_default_vfs_tell__stdio(pVFS, file, pCursor);
44329 #endif
44330 }
44331
44332 static ma_result ma_default_vfs_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
44333 {
44334     if (pInfo == NULL) {
44335         return MA_INVALID_ARGS;
44336     }
44337
44338     MA_ZERO_OBJECT(pInfo);
44339
44340     if (file == NULL) {
44341         return MA_INVALID_ARGS;
44342     }
44343
44344 #if defined(MA_WIN32) && defined(MA_WIN32_DESKTOP)
44345     return ma_default_vfs_info__win32(pVFS, file, pInfo);
44346 #else
44347     return ma_default_vfs_info__stdio(pVFS, file, pInfo);
44348 #endif
44349 }
44350
44351
44352 MA_API ma_result ma_default_vfs_init(ma_default_vfs* pVFS, const ma_allocation_callbacks* pAllocationCallbacks)
44353 {
44354     if (pVFS == NULL) {
44355         return MA_INVALID_ARGS;
44356     }
44357
44358     pVFS->cb.onOpen  = ma_default_vfs_open;
44359     pVFS->cb.onOpenW = ma_default_vfs_open_w;
44360     pVFS->cb.onClose = ma_default_vfs_close;
44361     pVFS->cb.onRead  = ma_default_vfs_read;
44362     pVFS->cb.onWrite = ma_default_vfs_write;
44363     pVFS->cb.onSeek  = ma_default_vfs_seek;
44364     pVFS->cb.onTell  = ma_default_vfs_tell;
44365     pVFS->cb.onInfo  = ma_default_vfs_info;
44366     ma_allocation_callbacks_init_copy(&pVFS->allocationCallbacks, pAllocationCallbacks);
44367
44368     return MA_SUCCESS;
44369 }
44370
44371
44372 MA_API ma_result ma_vfs_or_default_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
44373 {
44374     if (pVFS != NULL) {
44375         return ma_vfs_open(pVFS, pFilePath, openMode, pFile);
44376     } else {
44377         return ma_default_vfs_open(pVFS, pFilePath, openMode, pFile);
44378     }
44379 }
44380
44381 MA_API ma_result ma_vfs_or_default_open_w(ma_vfs* pVFS, const wchar_t* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile)
44382 {
44383     if (pVFS != NULL) {
44384         return ma_vfs_open_w(pVFS, pFilePath, openMode, pFile);
44385     } else {
44386         return ma_default_vfs_open_w(pVFS, pFilePath, openMode, pFile);
44387     }
44388 }
44389
44390 MA_API ma_result ma_vfs_or_default_close(ma_vfs* pVFS, ma_vfs_file file)
44391 {
44392     if (pVFS != NULL) {
44393         return ma_vfs_close(pVFS, file);
44394     } else {
44395         return ma_default_vfs_close(pVFS, file);
44396     }
44397 }
44398
44399 MA_API ma_result ma_vfs_or_default_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead)
44400 {
44401     if (pVFS != NULL) {
44402         return ma_vfs_read(pVFS, file, pDst, sizeInBytes, pBytesRead);
44403     } else {
44404         return ma_default_vfs_read(pVFS, file, pDst, sizeInBytes, pBytesRead);
44405     }
44406 }
44407
44408 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)
44409 {
44410     if (pVFS != NULL) {
44411         return ma_vfs_write(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
44412     } else {
44413         return ma_default_vfs_write(pVFS, file, pSrc, sizeInBytes, pBytesWritten);
44414     }
44415 }
44416
44417 MA_API ma_result ma_vfs_or_default_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin)
44418 {
44419     if (pVFS != NULL) {
44420         return ma_vfs_seek(pVFS, file, offset, origin);
44421     } else {
44422         return ma_default_vfs_seek(pVFS, file, offset, origin);
44423     }
44424 }
44425
44426 MA_API ma_result ma_vfs_or_default_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor)
44427 {
44428     if (pVFS != NULL) {
44429         return ma_vfs_tell(pVFS, file, pCursor);
44430     } else {
44431         return ma_default_vfs_tell(pVFS, file, pCursor);
44432     }
44433 }
44434
44435 MA_API ma_result ma_vfs_or_default_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo)
44436 {
44437     if (pVFS != NULL) {
44438         return ma_vfs_info(pVFS, file, pInfo);
44439     } else {
44440         return ma_default_vfs_info(pVFS, file, pInfo);
44441     }
44442 }
44443
44444
44445
44446 /**************************************************************************************************************************************************************
44447
44448 Decoding and Encoding Headers. These are auto-generated from a tool.
44449
44450 **************************************************************************************************************************************************************/
44451 #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING))
44452 /* dr_wav_h begin */
44453 #ifndef dr_wav_h
44454 #define dr_wav_h
44455 #ifdef __cplusplus
44456 extern "C" {
44457 #endif
44458 #define DRWAV_STRINGIFY(x)      #x
44459 #define DRWAV_XSTRINGIFY(x)     DRWAV_STRINGIFY(x)
44460 #define DRWAV_VERSION_MAJOR     0
44461 #define DRWAV_VERSION_MINOR     12
44462 #define DRWAV_VERSION_REVISION  19
44463 #define DRWAV_VERSION_STRING    DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
44464 #include <stddef.h>
44465 typedef   signed char           drwav_int8;
44466 typedef unsigned char           drwav_uint8;
44467 typedef   signed short          drwav_int16;
44468 typedef unsigned short          drwav_uint16;
44469 typedef   signed int            drwav_int32;
44470 typedef unsigned int            drwav_uint32;
44471 #if defined(_MSC_VER)
44472     typedef   signed __int64    drwav_int64;
44473     typedef unsigned __int64    drwav_uint64;
44474 #else
44475     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
44476         #pragma GCC diagnostic push
44477         #pragma GCC diagnostic ignored "-Wlong-long"
44478         #if defined(__clang__)
44479             #pragma GCC diagnostic ignored "-Wc++11-long-long"
44480         #endif
44481     #endif
44482     typedef   signed long long  drwav_int64;
44483     typedef unsigned long long  drwav_uint64;
44484     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
44485         #pragma GCC diagnostic pop
44486     #endif
44487 #endif
44488 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
44489     typedef drwav_uint64        drwav_uintptr;
44490 #else
44491     typedef drwav_uint32        drwav_uintptr;
44492 #endif
44493 typedef drwav_uint8             drwav_bool8;
44494 typedef drwav_uint32            drwav_bool32;
44495 #define DRWAV_TRUE              1
44496 #define DRWAV_FALSE             0
44497 #if !defined(DRWAV_API)
44498     #if defined(DRWAV_DLL)
44499         #if defined(_WIN32)
44500             #define DRWAV_DLL_IMPORT  __declspec(dllimport)
44501             #define DRWAV_DLL_EXPORT  __declspec(dllexport)
44502             #define DRWAV_DLL_PRIVATE static
44503         #else
44504             #if defined(__GNUC__) && __GNUC__ >= 4
44505                 #define DRWAV_DLL_IMPORT  __attribute__((visibility("default")))
44506                 #define DRWAV_DLL_EXPORT  __attribute__((visibility("default")))
44507                 #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
44508             #else
44509                 #define DRWAV_DLL_IMPORT
44510                 #define DRWAV_DLL_EXPORT
44511                 #define DRWAV_DLL_PRIVATE static
44512             #endif
44513         #endif
44514         #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
44515             #define DRWAV_API  DRWAV_DLL_EXPORT
44516         #else
44517             #define DRWAV_API  DRWAV_DLL_IMPORT
44518         #endif
44519         #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
44520     #else
44521         #define DRWAV_API extern
44522         #define DRWAV_PRIVATE static
44523     #endif
44524 #endif
44525 typedef drwav_int32 drwav_result;
44526 #define DRWAV_SUCCESS                        0
44527 #define DRWAV_ERROR                         -1
44528 #define DRWAV_INVALID_ARGS                  -2
44529 #define DRWAV_INVALID_OPERATION             -3
44530 #define DRWAV_OUT_OF_MEMORY                 -4
44531 #define DRWAV_OUT_OF_RANGE                  -5
44532 #define DRWAV_ACCESS_DENIED                 -6
44533 #define DRWAV_DOES_NOT_EXIST                -7
44534 #define DRWAV_ALREADY_EXISTS                -8
44535 #define DRWAV_TOO_MANY_OPEN_FILES           -9
44536 #define DRWAV_INVALID_FILE                  -10
44537 #define DRWAV_TOO_BIG                       -11
44538 #define DRWAV_PATH_TOO_LONG                 -12
44539 #define DRWAV_NAME_TOO_LONG                 -13
44540 #define DRWAV_NOT_DIRECTORY                 -14
44541 #define DRWAV_IS_DIRECTORY                  -15
44542 #define DRWAV_DIRECTORY_NOT_EMPTY           -16
44543 #define DRWAV_END_OF_FILE                   -17
44544 #define DRWAV_NO_SPACE                      -18
44545 #define DRWAV_BUSY                          -19
44546 #define DRWAV_IO_ERROR                      -20
44547 #define DRWAV_INTERRUPT                     -21
44548 #define DRWAV_UNAVAILABLE                   -22
44549 #define DRWAV_ALREADY_IN_USE                -23
44550 #define DRWAV_BAD_ADDRESS                   -24
44551 #define DRWAV_BAD_SEEK                      -25
44552 #define DRWAV_BAD_PIPE                      -26
44553 #define DRWAV_DEADLOCK                      -27
44554 #define DRWAV_TOO_MANY_LINKS                -28
44555 #define DRWAV_NOT_IMPLEMENTED               -29
44556 #define DRWAV_NO_MESSAGE                    -30
44557 #define DRWAV_BAD_MESSAGE                   -31
44558 #define DRWAV_NO_DATA_AVAILABLE             -32
44559 #define DRWAV_INVALID_DATA                  -33
44560 #define DRWAV_TIMEOUT                       -34
44561 #define DRWAV_NO_NETWORK                    -35
44562 #define DRWAV_NOT_UNIQUE                    -36
44563 #define DRWAV_NOT_SOCKET                    -37
44564 #define DRWAV_NO_ADDRESS                    -38
44565 #define DRWAV_BAD_PROTOCOL                  -39
44566 #define DRWAV_PROTOCOL_UNAVAILABLE          -40
44567 #define DRWAV_PROTOCOL_NOT_SUPPORTED        -41
44568 #define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
44569 #define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED  -43
44570 #define DRWAV_SOCKET_NOT_SUPPORTED          -44
44571 #define DRWAV_CONNECTION_RESET              -45
44572 #define DRWAV_ALREADY_CONNECTED             -46
44573 #define DRWAV_NOT_CONNECTED                 -47
44574 #define DRWAV_CONNECTION_REFUSED            -48
44575 #define DRWAV_NO_HOST                       -49
44576 #define DRWAV_IN_PROGRESS                   -50
44577 #define DRWAV_CANCELLED                     -51
44578 #define DRWAV_MEMORY_ALREADY_MAPPED         -52
44579 #define DRWAV_AT_END                        -53
44580 #define DR_WAVE_FORMAT_PCM          0x1
44581 #define DR_WAVE_FORMAT_ADPCM        0x2
44582 #define DR_WAVE_FORMAT_IEEE_FLOAT   0x3
44583 #define DR_WAVE_FORMAT_ALAW         0x6
44584 #define DR_WAVE_FORMAT_MULAW        0x7
44585 #define DR_WAVE_FORMAT_DVI_ADPCM    0x11
44586 #define DR_WAVE_FORMAT_EXTENSIBLE   0xFFFE
44587 #ifndef DRWAV_MAX_SMPL_LOOPS
44588 #define DRWAV_MAX_SMPL_LOOPS        1
44589 #endif
44590 #define DRWAV_SEQUENTIAL            0x00000001
44591 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
44592 DRWAV_API const char* drwav_version_string(void);
44593 typedef enum
44594 {
44595     drwav_seek_origin_start,
44596     drwav_seek_origin_current
44597 } drwav_seek_origin;
44598 typedef enum
44599 {
44600     drwav_container_riff,
44601     drwav_container_w64,
44602     drwav_container_rf64
44603 } drwav_container;
44604 typedef struct
44605 {
44606     union
44607     {
44608         drwav_uint8 fourcc[4];
44609         drwav_uint8 guid[16];
44610     } id;
44611     drwav_uint64 sizeInBytes;
44612     unsigned int paddingSize;
44613 } drwav_chunk_header;
44614 typedef struct
44615 {
44616     drwav_uint16 formatTag;
44617     drwav_uint16 channels;
44618     drwav_uint32 sampleRate;
44619     drwav_uint32 avgBytesPerSec;
44620     drwav_uint16 blockAlign;
44621     drwav_uint16 bitsPerSample;
44622     drwav_uint16 extendedSize;
44623     drwav_uint16 validBitsPerSample;
44624     drwav_uint32 channelMask;
44625     drwav_uint8 subFormat[16];
44626 } drwav_fmt;
44627 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
44628 typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
44629 typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
44630 typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
44631 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);
44632 typedef struct
44633 {
44634     void* pUserData;
44635     void* (* onMalloc)(size_t sz, void* pUserData);
44636     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
44637     void  (* onFree)(void* p, void* pUserData);
44638 } drwav_allocation_callbacks;
44639 typedef struct
44640 {
44641     const drwav_uint8* data;
44642     size_t dataSize;
44643     size_t currentReadPos;
44644 } drwav__memory_stream;
44645 typedef struct
44646 {
44647     void** ppData;
44648     size_t* pDataSize;
44649     size_t dataSize;
44650     size_t dataCapacity;
44651     size_t currentWritePos;
44652 } drwav__memory_stream_write;
44653 typedef struct
44654 {
44655     drwav_container container;
44656     drwav_uint32 format;
44657     drwav_uint32 channels;
44658     drwav_uint32 sampleRate;
44659     drwav_uint32 bitsPerSample;
44660 } drwav_data_format;
44661 typedef struct
44662 {
44663     drwav_uint32 cuePointId;
44664     drwav_uint32 type;
44665     drwav_uint32 start;
44666     drwav_uint32 end;
44667     drwav_uint32 fraction;
44668     drwav_uint32 playCount;
44669 } drwav_smpl_loop;
44670  typedef struct
44671 {
44672     drwav_uint32 manufacturer;
44673     drwav_uint32 product;
44674     drwav_uint32 samplePeriod;
44675     drwav_uint32 midiUnityNotes;
44676     drwav_uint32 midiPitchFraction;
44677     drwav_uint32 smpteFormat;
44678     drwav_uint32 smpteOffset;
44679     drwav_uint32 numSampleLoops;
44680     drwav_uint32 samplerData;
44681     drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS];
44682 } drwav_smpl;
44683 typedef struct
44684 {
44685     drwav_read_proc onRead;
44686     drwav_write_proc onWrite;
44687     drwav_seek_proc onSeek;
44688     void* pUserData;
44689     drwav_allocation_callbacks allocationCallbacks;
44690     drwav_container container;
44691     drwav_fmt fmt;
44692     drwav_uint32 sampleRate;
44693     drwav_uint16 channels;
44694     drwav_uint16 bitsPerSample;
44695     drwav_uint16 translatedFormatTag;
44696     drwav_uint64 totalPCMFrameCount;
44697     drwav_uint64 dataChunkDataSize;
44698     drwav_uint64 dataChunkDataPos;
44699     drwav_uint64 bytesRemaining;
44700     drwav_uint64 dataChunkDataSizeTargetWrite;
44701     drwav_bool32 isSequentialWrite;
44702     drwav_smpl smpl;
44703     drwav__memory_stream memoryStream;
44704     drwav__memory_stream_write memoryStreamWrite;
44705     struct
44706     {
44707         drwav_uint64 iCurrentPCMFrame;
44708     } compressed;
44709     struct
44710     {
44711         drwav_uint32 bytesRemainingInBlock;
44712         drwav_uint16 predictor[2];
44713         drwav_int32  delta[2];
44714         drwav_int32  cachedFrames[4];
44715         drwav_uint32 cachedFrameCount;
44716         drwav_int32  prevFrames[2][2];
44717     } msadpcm;
44718     struct
44719     {
44720         drwav_uint32 bytesRemainingInBlock;
44721         drwav_int32  predictor[2];
44722         drwav_int32  stepIndex[2];
44723         drwav_int32  cachedFrames[16];
44724         drwav_uint32 cachedFrameCount;
44725     } ima;
44726 } drwav;
44727 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
44728 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);
44729 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);
44730 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);
44731 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);
44732 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
44733 DRWAV_API drwav_result drwav_uninit(drwav* pWav);
44734 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
44735 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
44736 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
44737 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
44738 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
44739 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
44740 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
44741 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
44742 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
44743 #ifndef DR_WAV_NO_CONVERSION_API
44744 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
44745 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
44746 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
44747 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
44748 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
44749 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
44750 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
44751 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
44752 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
44753 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
44754 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
44755 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
44756 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
44757 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
44758 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
44759 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
44760 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
44761 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
44762 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
44763 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
44764 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
44765 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
44766 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
44767 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
44768 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
44769 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
44770 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
44771 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
44772 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
44773 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
44774 #endif
44775 #ifndef DR_WAV_NO_STDIO
44776 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
44777 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);
44778 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
44779 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);
44780 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
44781 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);
44782 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);
44783 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);
44784 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);
44785 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);
44786 #endif
44787 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
44788 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);
44789 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);
44790 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);
44791 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);
44792 #ifndef DR_WAV_NO_CONVERSION_API
44793 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);
44794 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);
44795 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);
44796 #ifndef DR_WAV_NO_STDIO
44797 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);
44798 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);
44799 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);
44800 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);
44801 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);
44802 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);
44803 #endif
44804 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);
44805 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);
44806 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);
44807 #endif
44808 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
44809 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
44810 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
44811 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
44812 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
44813 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
44814 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
44815 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
44816 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
44817 #ifdef __cplusplus
44818 }
44819 #endif
44820 #endif
44821 /* dr_wav_h end */
44822 #endif  /* MA_NO_WAV */
44823
44824 #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING)
44825 /* dr_flac_h begin */
44826 #ifndef dr_flac_h
44827 #define dr_flac_h
44828 #ifdef __cplusplus
44829 extern "C" {
44830 #endif
44831 #define DRFLAC_STRINGIFY(x)      #x
44832 #define DRFLAC_XSTRINGIFY(x)     DRFLAC_STRINGIFY(x)
44833 #define DRFLAC_VERSION_MAJOR     0
44834 #define DRFLAC_VERSION_MINOR     12
44835 #define DRFLAC_VERSION_REVISION  29
44836 #define DRFLAC_VERSION_STRING    DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
44837 #include <stddef.h>
44838 typedef   signed char           drflac_int8;
44839 typedef unsigned char           drflac_uint8;
44840 typedef   signed short          drflac_int16;
44841 typedef unsigned short          drflac_uint16;
44842 typedef   signed int            drflac_int32;
44843 typedef unsigned int            drflac_uint32;
44844 #if defined(_MSC_VER)
44845     typedef   signed __int64    drflac_int64;
44846     typedef unsigned __int64    drflac_uint64;
44847 #else
44848     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
44849         #pragma GCC diagnostic push
44850         #pragma GCC diagnostic ignored "-Wlong-long"
44851         #if defined(__clang__)
44852             #pragma GCC diagnostic ignored "-Wc++11-long-long"
44853         #endif
44854     #endif
44855     typedef   signed long long  drflac_int64;
44856     typedef unsigned long long  drflac_uint64;
44857     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
44858         #pragma GCC diagnostic pop
44859     #endif
44860 #endif
44861 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
44862     typedef drflac_uint64       drflac_uintptr;
44863 #else
44864     typedef drflac_uint32       drflac_uintptr;
44865 #endif
44866 typedef drflac_uint8            drflac_bool8;
44867 typedef drflac_uint32           drflac_bool32;
44868 #define DRFLAC_TRUE             1
44869 #define DRFLAC_FALSE            0
44870 #if !defined(DRFLAC_API)
44871     #if defined(DRFLAC_DLL)
44872         #if defined(_WIN32)
44873             #define DRFLAC_DLL_IMPORT  __declspec(dllimport)
44874             #define DRFLAC_DLL_EXPORT  __declspec(dllexport)
44875             #define DRFLAC_DLL_PRIVATE static
44876         #else
44877             #if defined(__GNUC__) && __GNUC__ >= 4
44878                 #define DRFLAC_DLL_IMPORT  __attribute__((visibility("default")))
44879                 #define DRFLAC_DLL_EXPORT  __attribute__((visibility("default")))
44880                 #define DRFLAC_DLL_PRIVATE __attribute__((visibility("hidden")))
44881             #else
44882                 #define DRFLAC_DLL_IMPORT
44883                 #define DRFLAC_DLL_EXPORT
44884                 #define DRFLAC_DLL_PRIVATE static
44885             #endif
44886         #endif
44887         #if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION)
44888             #define DRFLAC_API  DRFLAC_DLL_EXPORT
44889         #else
44890             #define DRFLAC_API  DRFLAC_DLL_IMPORT
44891         #endif
44892         #define DRFLAC_PRIVATE DRFLAC_DLL_PRIVATE
44893     #else
44894         #define DRFLAC_API extern
44895         #define DRFLAC_PRIVATE static
44896     #endif
44897 #endif
44898 #if defined(_MSC_VER) && _MSC_VER >= 1700
44899     #define DRFLAC_DEPRECATED       __declspec(deprecated)
44900 #elif (defined(__GNUC__) && __GNUC__ >= 4)
44901     #define DRFLAC_DEPRECATED       __attribute__((deprecated))
44902 #elif defined(__has_feature)
44903     #if __has_feature(attribute_deprecated)
44904         #define DRFLAC_DEPRECATED   __attribute__((deprecated))
44905     #else
44906         #define DRFLAC_DEPRECATED
44907     #endif
44908 #else
44909     #define DRFLAC_DEPRECATED
44910 #endif
44911 DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision);
44912 DRFLAC_API const char* drflac_version_string(void);
44913 #ifndef DR_FLAC_BUFFER_SIZE
44914 #define DR_FLAC_BUFFER_SIZE   4096
44915 #endif
44916 #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
44917 #define DRFLAC_64BIT
44918 #endif
44919 #ifdef DRFLAC_64BIT
44920 typedef drflac_uint64 drflac_cache_t;
44921 #else
44922 typedef drflac_uint32 drflac_cache_t;
44923 #endif
44924 #define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO       0
44925 #define DRFLAC_METADATA_BLOCK_TYPE_PADDING          1
44926 #define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION      2
44927 #define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE        3
44928 #define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT   4
44929 #define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET         5
44930 #define DRFLAC_METADATA_BLOCK_TYPE_PICTURE          6
44931 #define DRFLAC_METADATA_BLOCK_TYPE_INVALID          127
44932 #define DRFLAC_PICTURE_TYPE_OTHER                   0
44933 #define DRFLAC_PICTURE_TYPE_FILE_ICON               1
44934 #define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON         2
44935 #define DRFLAC_PICTURE_TYPE_COVER_FRONT             3
44936 #define DRFLAC_PICTURE_TYPE_COVER_BACK              4
44937 #define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE            5
44938 #define DRFLAC_PICTURE_TYPE_MEDIA                   6
44939 #define DRFLAC_PICTURE_TYPE_LEAD_ARTIST             7
44940 #define DRFLAC_PICTURE_TYPE_ARTIST                  8
44941 #define DRFLAC_PICTURE_TYPE_CONDUCTOR               9
44942 #define DRFLAC_PICTURE_TYPE_BAND                    10
44943 #define DRFLAC_PICTURE_TYPE_COMPOSER                11
44944 #define DRFLAC_PICTURE_TYPE_LYRICIST                12
44945 #define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION      13
44946 #define DRFLAC_PICTURE_TYPE_DURING_RECORDING        14
44947 #define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE      15
44948 #define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE          16
44949 #define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH     17
44950 #define DRFLAC_PICTURE_TYPE_ILLUSTRATION            18
44951 #define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE           19
44952 #define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE      20
44953 typedef enum
44954 {
44955     drflac_container_native,
44956     drflac_container_ogg,
44957     drflac_container_unknown
44958 } drflac_container;
44959 typedef enum
44960 {
44961     drflac_seek_origin_start,
44962     drflac_seek_origin_current
44963 } drflac_seek_origin;
44964 #pragma pack(2)
44965 typedef struct
44966 {
44967     drflac_uint64 firstPCMFrame;
44968     drflac_uint64 flacFrameOffset;
44969     drflac_uint16 pcmFrameCount;
44970 } drflac_seekpoint;
44971 #pragma pack()
44972 typedef struct
44973 {
44974     drflac_uint16 minBlockSizeInPCMFrames;
44975     drflac_uint16 maxBlockSizeInPCMFrames;
44976     drflac_uint32 minFrameSizeInPCMFrames;
44977     drflac_uint32 maxFrameSizeInPCMFrames;
44978     drflac_uint32 sampleRate;
44979     drflac_uint8  channels;
44980     drflac_uint8  bitsPerSample;
44981     drflac_uint64 totalPCMFrameCount;
44982     drflac_uint8  md5[16];
44983 } drflac_streaminfo;
44984 typedef struct
44985 {
44986     drflac_uint32 type;
44987     const void* pRawData;
44988     drflac_uint32 rawDataSize;
44989     union
44990     {
44991         drflac_streaminfo streaminfo;
44992         struct
44993         {
44994             int unused;
44995         } padding;
44996         struct
44997         {
44998             drflac_uint32 id;
44999             const void* pData;
45000             drflac_uint32 dataSize;
45001         } application;
45002         struct
45003         {
45004             drflac_uint32 seekpointCount;
45005             const drflac_seekpoint* pSeekpoints;
45006         } seektable;
45007         struct
45008         {
45009             drflac_uint32 vendorLength;
45010             const char* vendor;
45011             drflac_uint32 commentCount;
45012             const void* pComments;
45013         } vorbis_comment;
45014         struct
45015         {
45016             char catalog[128];
45017             drflac_uint64 leadInSampleCount;
45018             drflac_bool32 isCD;
45019             drflac_uint8 trackCount;
45020             const void* pTrackData;
45021         } cuesheet;
45022         struct
45023         {
45024             drflac_uint32 type;
45025             drflac_uint32 mimeLength;
45026             const char* mime;
45027             drflac_uint32 descriptionLength;
45028             const char* description;
45029             drflac_uint32 width;
45030             drflac_uint32 height;
45031             drflac_uint32 colorDepth;
45032             drflac_uint32 indexColorCount;
45033             drflac_uint32 pictureDataSize;
45034             const drflac_uint8* pPictureData;
45035         } picture;
45036     } data;
45037 } drflac_metadata;
45038 typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
45039 typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
45040 typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
45041 typedef struct
45042 {
45043     void* pUserData;
45044     void* (* onMalloc)(size_t sz, void* pUserData);
45045     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
45046     void  (* onFree)(void* p, void* pUserData);
45047 } drflac_allocation_callbacks;
45048 typedef struct
45049 {
45050     const drflac_uint8* data;
45051     size_t dataSize;
45052     size_t currentReadPos;
45053 } drflac__memory_stream;
45054 typedef struct
45055 {
45056     drflac_read_proc onRead;
45057     drflac_seek_proc onSeek;
45058     void* pUserData;
45059     size_t unalignedByteCount;
45060     drflac_cache_t unalignedCache;
45061     drflac_uint32 nextL2Line;
45062     drflac_uint32 consumedBits;
45063     drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
45064     drflac_cache_t cache;
45065     drflac_uint16 crc16;
45066     drflac_cache_t crc16Cache;
45067     drflac_uint32 crc16CacheIgnoredBytes;
45068 } drflac_bs;
45069 typedef struct
45070 {
45071     drflac_uint8 subframeType;
45072     drflac_uint8 wastedBitsPerSample;
45073     drflac_uint8 lpcOrder;
45074     drflac_int32* pSamplesS32;
45075 } drflac_subframe;
45076 typedef struct
45077 {
45078     drflac_uint64 pcmFrameNumber;
45079     drflac_uint32 flacFrameNumber;
45080     drflac_uint32 sampleRate;
45081     drflac_uint16 blockSizeInPCMFrames;
45082     drflac_uint8 channelAssignment;
45083     drflac_uint8 bitsPerSample;
45084     drflac_uint8 crc8;
45085 } drflac_frame_header;
45086 typedef struct
45087 {
45088     drflac_frame_header header;
45089     drflac_uint32 pcmFramesRemaining;
45090     drflac_subframe subframes[8];
45091 } drflac_frame;
45092 typedef struct
45093 {
45094     drflac_meta_proc onMeta;
45095     void* pUserDataMD;
45096     drflac_allocation_callbacks allocationCallbacks;
45097     drflac_uint32 sampleRate;
45098     drflac_uint8 channels;
45099     drflac_uint8 bitsPerSample;
45100     drflac_uint16 maxBlockSizeInPCMFrames;
45101     drflac_uint64 totalPCMFrameCount;
45102     drflac_container container;
45103     drflac_uint32 seekpointCount;
45104     drflac_frame currentFLACFrame;
45105     drflac_uint64 currentPCMFrame;
45106     drflac_uint64 firstFLACFramePosInBytes;
45107     drflac__memory_stream memoryStream;
45108     drflac_int32* pDecodedSamples;
45109     drflac_seekpoint* pSeekpoints;
45110     void* _oggbs;
45111     drflac_bool32 _noSeekTableSeek    : 1;
45112     drflac_bool32 _noBinarySearchSeek : 1;
45113     drflac_bool32 _noBruteForceSeek   : 1;
45114     drflac_bs bs;
45115     drflac_uint8 pExtraData[1];
45116 } drflac;
45117 DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
45118 DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
45119 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);
45120 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);
45121 DRFLAC_API void drflac_close(drflac* pFlac);
45122 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut);
45123 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut);
45124 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut);
45125 DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex);
45126 #ifndef DR_FLAC_NO_STDIO
45127 DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
45128 DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
45129 DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
45130 DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
45131 #endif
45132 DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks);
45133 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);
45134 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);
45135 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);
45136 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);
45137 #ifndef DR_FLAC_NO_STDIO
45138 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);
45139 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);
45140 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);
45141 #endif
45142 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);
45143 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);
45144 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);
45145 DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks);
45146 typedef struct
45147 {
45148     drflac_uint32 countRemaining;
45149     const char* pRunningData;
45150 } drflac_vorbis_comment_iterator;
45151 DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments);
45152 DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut);
45153 typedef struct
45154 {
45155     drflac_uint32 countRemaining;
45156     const char* pRunningData;
45157 } drflac_cuesheet_track_iterator;
45158 #pragma pack(4)
45159 typedef struct
45160 {
45161     drflac_uint64 offset;
45162     drflac_uint8 index;
45163     drflac_uint8 reserved[3];
45164 } drflac_cuesheet_track_index;
45165 #pragma pack()
45166 typedef struct
45167 {
45168     drflac_uint64 offset;
45169     drflac_uint8 trackNumber;
45170     char ISRC[12];
45171     drflac_bool8 isAudio;
45172     drflac_bool8 preEmphasis;
45173     drflac_uint8 indexCount;
45174     const drflac_cuesheet_track_index* pIndexPoints;
45175 } drflac_cuesheet_track;
45176 DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData);
45177 DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack);
45178 #ifdef __cplusplus
45179 }
45180 #endif
45181 #endif
45182 /* dr_flac_h end */
45183 #endif  /* MA_NO_FLAC */
45184
45185 #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING)
45186 /* dr_mp3_h begin */
45187 #ifndef dr_mp3_h
45188 #define dr_mp3_h
45189 #ifdef __cplusplus
45190 extern "C" {
45191 #endif
45192 #define DRMP3_STRINGIFY(x)      #x
45193 #define DRMP3_XSTRINGIFY(x)     DRMP3_STRINGIFY(x)
45194 #define DRMP3_VERSION_MAJOR     0
45195 #define DRMP3_VERSION_MINOR     6
45196 #define DRMP3_VERSION_REVISION  27
45197 #define DRMP3_VERSION_STRING    DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
45198 #include <stddef.h>
45199 typedef   signed char           drmp3_int8;
45200 typedef unsigned char           drmp3_uint8;
45201 typedef   signed short          drmp3_int16;
45202 typedef unsigned short          drmp3_uint16;
45203 typedef   signed int            drmp3_int32;
45204 typedef unsigned int            drmp3_uint32;
45205 #if defined(_MSC_VER)
45206     typedef   signed __int64    drmp3_int64;
45207     typedef unsigned __int64    drmp3_uint64;
45208 #else
45209     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
45210         #pragma GCC diagnostic push
45211         #pragma GCC diagnostic ignored "-Wlong-long"
45212         #if defined(__clang__)
45213             #pragma GCC diagnostic ignored "-Wc++11-long-long"
45214         #endif
45215     #endif
45216     typedef   signed long long  drmp3_int64;
45217     typedef unsigned long long  drmp3_uint64;
45218     #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
45219         #pragma GCC diagnostic pop
45220     #endif
45221 #endif
45222 #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
45223     typedef drmp3_uint64        drmp3_uintptr;
45224 #else
45225     typedef drmp3_uint32        drmp3_uintptr;
45226 #endif
45227 typedef drmp3_uint8             drmp3_bool8;
45228 typedef drmp3_uint32            drmp3_bool32;
45229 #define DRMP3_TRUE              1
45230 #define DRMP3_FALSE             0
45231 #if !defined(DRMP3_API)
45232     #if defined(DRMP3_DLL)
45233         #if defined(_WIN32)
45234             #define DRMP3_DLL_IMPORT  __declspec(dllimport)
45235             #define DRMP3_DLL_EXPORT  __declspec(dllexport)
45236             #define DRMP3_DLL_PRIVATE static
45237         #else
45238             #if defined(__GNUC__) && __GNUC__ >= 4
45239                 #define DRMP3_DLL_IMPORT  __attribute__((visibility("default")))
45240                 #define DRMP3_DLL_EXPORT  __attribute__((visibility("default")))
45241                 #define DRMP3_DLL_PRIVATE __attribute__((visibility("hidden")))
45242             #else
45243                 #define DRMP3_DLL_IMPORT
45244                 #define DRMP3_DLL_EXPORT
45245                 #define DRMP3_DLL_PRIVATE static
45246             #endif
45247         #endif
45248         #if defined(DR_MP3_IMPLEMENTATION) || defined(DRMP3_IMPLEMENTATION)
45249             #define DRMP3_API  DRMP3_DLL_EXPORT
45250         #else
45251             #define DRMP3_API  DRMP3_DLL_IMPORT
45252         #endif
45253         #define DRMP3_PRIVATE DRMP3_DLL_PRIVATE
45254     #else
45255         #define DRMP3_API extern
45256         #define DRMP3_PRIVATE static
45257     #endif
45258 #endif
45259 typedef drmp3_int32 drmp3_result;
45260 #define DRMP3_SUCCESS                        0
45261 #define DRMP3_ERROR                         -1
45262 #define DRMP3_INVALID_ARGS                  -2
45263 #define DRMP3_INVALID_OPERATION             -3
45264 #define DRMP3_OUT_OF_MEMORY                 -4
45265 #define DRMP3_OUT_OF_RANGE                  -5
45266 #define DRMP3_ACCESS_DENIED                 -6
45267 #define DRMP3_DOES_NOT_EXIST                -7
45268 #define DRMP3_ALREADY_EXISTS                -8
45269 #define DRMP3_TOO_MANY_OPEN_FILES           -9
45270 #define DRMP3_INVALID_FILE                  -10
45271 #define DRMP3_TOO_BIG                       -11
45272 #define DRMP3_PATH_TOO_LONG                 -12
45273 #define DRMP3_NAME_TOO_LONG                 -13
45274 #define DRMP3_NOT_DIRECTORY                 -14
45275 #define DRMP3_IS_DIRECTORY                  -15
45276 #define DRMP3_DIRECTORY_NOT_EMPTY           -16
45277 #define DRMP3_END_OF_FILE                   -17
45278 #define DRMP3_NO_SPACE                      -18
45279 #define DRMP3_BUSY                          -19
45280 #define DRMP3_IO_ERROR                      -20
45281 #define DRMP3_INTERRUPT                     -21
45282 #define DRMP3_UNAVAILABLE                   -22
45283 #define DRMP3_ALREADY_IN_USE                -23
45284 #define DRMP3_BAD_ADDRESS                   -24
45285 #define DRMP3_BAD_SEEK                      -25
45286 #define DRMP3_BAD_PIPE                      -26
45287 #define DRMP3_DEADLOCK                      -27
45288 #define DRMP3_TOO_MANY_LINKS                -28
45289 #define DRMP3_NOT_IMPLEMENTED               -29
45290 #define DRMP3_NO_MESSAGE                    -30
45291 #define DRMP3_BAD_MESSAGE                   -31
45292 #define DRMP3_NO_DATA_AVAILABLE             -32
45293 #define DRMP3_INVALID_DATA                  -33
45294 #define DRMP3_TIMEOUT                       -34
45295 #define DRMP3_NO_NETWORK                    -35
45296 #define DRMP3_NOT_UNIQUE                    -36
45297 #define DRMP3_NOT_SOCKET                    -37
45298 #define DRMP3_NO_ADDRESS                    -38
45299 #define DRMP3_BAD_PROTOCOL                  -39
45300 #define DRMP3_PROTOCOL_UNAVAILABLE          -40
45301 #define DRMP3_PROTOCOL_NOT_SUPPORTED        -41
45302 #define DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED -42
45303 #define DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED  -43
45304 #define DRMP3_SOCKET_NOT_SUPPORTED          -44
45305 #define DRMP3_CONNECTION_RESET              -45
45306 #define DRMP3_ALREADY_CONNECTED             -46
45307 #define DRMP3_NOT_CONNECTED                 -47
45308 #define DRMP3_CONNECTION_REFUSED            -48
45309 #define DRMP3_NO_HOST                       -49
45310 #define DRMP3_IN_PROGRESS                   -50
45311 #define DRMP3_CANCELLED                     -51
45312 #define DRMP3_MEMORY_ALREADY_MAPPED         -52
45313 #define DRMP3_AT_END                        -53
45314 #define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME  1152
45315 #define DRMP3_MAX_SAMPLES_PER_FRAME         (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2)
45316 #ifdef _MSC_VER
45317     #define DRMP3_INLINE __forceinline
45318 #elif defined(__GNUC__)
45319     #if defined(__STRICT_ANSI__)
45320         #define DRMP3_INLINE __inline__ __attribute__((always_inline))
45321     #else
45322         #define DRMP3_INLINE inline __attribute__((always_inline))
45323     #endif
45324 #elif defined(__WATCOMC__)
45325     #define DRMP3_INLINE __inline
45326 #else
45327     #define DRMP3_INLINE
45328 #endif
45329 DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision);
45330 DRMP3_API const char* drmp3_version_string(void);
45331 typedef struct
45332 {
45333     int frame_bytes, channels, hz, layer, bitrate_kbps;
45334 } drmp3dec_frame_info;
45335 typedef struct
45336 {
45337     float mdct_overlap[2][9*32], qmf_state[15*2*32];
45338     int reserv, free_format_bytes;
45339     drmp3_uint8 header[4], reserv_buf[511];
45340 } drmp3dec;
45341 DRMP3_API void drmp3dec_init(drmp3dec *dec);
45342 DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info);
45343 DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples);
45344 typedef enum
45345 {
45346     drmp3_seek_origin_start,
45347     drmp3_seek_origin_current
45348 } drmp3_seek_origin;
45349 typedef struct
45350 {
45351     drmp3_uint64 seekPosInBytes;
45352     drmp3_uint64 pcmFrameIndex;
45353     drmp3_uint16 mp3FramesToDiscard;
45354     drmp3_uint16 pcmFramesToDiscard;
45355 } drmp3_seek_point;
45356 typedef size_t (* drmp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
45357 typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin);
45358 typedef struct
45359 {
45360     void* pUserData;
45361     void* (* onMalloc)(size_t sz, void* pUserData);
45362     void* (* onRealloc)(void* p, size_t sz, void* pUserData);
45363     void  (* onFree)(void* p, void* pUserData);
45364 } drmp3_allocation_callbacks;
45365 typedef struct
45366 {
45367     drmp3_uint32 channels;
45368     drmp3_uint32 sampleRate;
45369 } drmp3_config;
45370 typedef struct
45371 {
45372     drmp3dec decoder;
45373     drmp3dec_frame_info frameInfo;
45374     drmp3_uint32 channels;
45375     drmp3_uint32 sampleRate;
45376     drmp3_read_proc onRead;
45377     drmp3_seek_proc onSeek;
45378     void* pUserData;
45379     drmp3_allocation_callbacks allocationCallbacks;
45380     drmp3_uint32 mp3FrameChannels;
45381     drmp3_uint32 mp3FrameSampleRate;
45382     drmp3_uint32 pcmFramesConsumedInMP3Frame;
45383     drmp3_uint32 pcmFramesRemainingInMP3Frame;
45384     drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME];
45385     drmp3_uint64 currentPCMFrame;
45386     drmp3_uint64 streamCursor;
45387     drmp3_seek_point* pSeekPoints;
45388     drmp3_uint32 seekPointCount;
45389     size_t dataSize;
45390     size_t dataCapacity;
45391     size_t dataConsumed;
45392     drmp3_uint8* pData;
45393     drmp3_bool32 atEnd : 1;
45394     struct
45395     {
45396         const drmp3_uint8* pData;
45397         size_t dataSize;
45398         size_t currentReadPos;
45399     } memory;
45400 } drmp3;
45401 DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks);
45402 DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks);
45403 #ifndef DR_MP3_NO_STDIO
45404 DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
45405 DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
45406 #endif
45407 DRMP3_API void drmp3_uninit(drmp3* pMP3);
45408 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut);
45409 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut);
45410 DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex);
45411 DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3);
45412 DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3);
45413 DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount);
45414 DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints);
45415 DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints);
45416 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);
45417 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);
45418 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);
45419 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);
45420 #ifndef DR_MP3_NO_STDIO
45421 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);
45422 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);
45423 #endif
45424 DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks);
45425 DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks);
45426 #ifdef __cplusplus
45427 }
45428 #endif
45429 #endif
45430 /* dr_mp3_h end */
45431 #endif  /* MA_NO_MP3 */
45432
45433
45434 /**************************************************************************************************************************************************************
45435
45436 Decoding
45437
45438 **************************************************************************************************************************************************************/
45439 #ifndef MA_NO_DECODING
45440
45441 static size_t ma_decoder_read_bytes(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead)
45442 {
45443     size_t bytesRead;
45444
45445     MA_ASSERT(pDecoder != NULL);
45446     MA_ASSERT(pBufferOut != NULL);
45447
45448     bytesRead = pDecoder->onRead(pDecoder, pBufferOut, bytesToRead);
45449     pDecoder->readPointerInBytes += bytesRead;
45450
45451     return bytesRead;
45452 }
45453
45454 static ma_bool32 ma_decoder_seek_bytes(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin)
45455 {
45456     ma_bool32 wasSuccessful;
45457
45458     MA_ASSERT(pDecoder != NULL);
45459
45460     wasSuccessful = pDecoder->onSeek(pDecoder, byteOffset, origin);
45461     if (wasSuccessful) {
45462         if (origin == ma_seek_origin_start) {
45463             pDecoder->readPointerInBytes = (ma_uint64)byteOffset;
45464         } else {
45465             pDecoder->readPointerInBytes += byteOffset;
45466         }
45467     }
45468
45469     return wasSuccessful;
45470 }
45471
45472
45473 MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint32 outputChannels, ma_uint32 outputSampleRate)
45474 {
45475     ma_decoder_config config;
45476     MA_ZERO_OBJECT(&config);
45477     config.format     = outputFormat;
45478     config.channels   = ma_min(outputChannels, ma_countof(config.channelMap));
45479     config.sampleRate = outputSampleRate;
45480     config.resampling.algorithm = ma_resample_algorithm_linear;
45481     config.resampling.linear.lpfOrder = ma_min(MA_DEFAULT_RESAMPLER_LPF_ORDER, MA_MAX_FILTER_ORDER);
45482     config.resampling.speex.quality = 3;
45483
45484     /* Note that we are intentionally leaving the channel map empty here which will cause the default channel map to be used. */
45485
45486     return config;
45487 }
45488
45489 MA_API ma_decoder_config ma_decoder_config_init_copy(const ma_decoder_config* pConfig)
45490 {
45491     ma_decoder_config config;
45492     if (pConfig != NULL) {
45493         config = *pConfig;
45494     } else {
45495         MA_ZERO_OBJECT(&config);
45496     }
45497
45498     return config;
45499 }
45500
45501 static ma_result ma_decoder__init_data_converter(ma_decoder* pDecoder, const ma_decoder_config* pConfig)
45502 {
45503     ma_data_converter_config converterConfig;
45504
45505     MA_ASSERT(pDecoder != NULL);
45506     MA_ASSERT(pConfig  != NULL);
45507
45508     /* Make sure we're not asking for too many channels. */
45509     if (pConfig->channels > MA_MAX_CHANNELS) {
45510         return MA_INVALID_ARGS;
45511     }
45512
45513     /* The internal channels should have already been validated at a higher level, but we'll do it again explicitly here for safety. */
45514     if (pDecoder->internalChannels > MA_MAX_CHANNELS) {
45515         return MA_INVALID_ARGS;
45516     }
45517
45518
45519     /* Output format. */
45520     if (pConfig->format == ma_format_unknown) {
45521         pDecoder->outputFormat = pDecoder->internalFormat;
45522     } else {
45523         pDecoder->outputFormat = pConfig->format;
45524     }
45525
45526     if (pConfig->channels == 0) {
45527         pDecoder->outputChannels = pDecoder->internalChannels;
45528     } else {
45529         pDecoder->outputChannels = pConfig->channels;
45530     }
45531
45532     if (pConfig->sampleRate == 0) {
45533         pDecoder->outputSampleRate = pDecoder->internalSampleRate;
45534     } else {
45535         pDecoder->outputSampleRate = pConfig->sampleRate;
45536     }
45537
45538     if (ma_channel_map_blank(pDecoder->outputChannels, pConfig->channelMap)) {
45539         ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->outputChannels, pDecoder->outputChannelMap);
45540     } else {
45541         MA_COPY_MEMORY(pDecoder->outputChannelMap, pConfig->channelMap, sizeof(pConfig->channelMap));
45542     }
45543
45544
45545     converterConfig = ma_data_converter_config_init(
45546         pDecoder->internalFormat,     pDecoder->outputFormat,
45547         pDecoder->internalChannels,   pDecoder->outputChannels,
45548         pDecoder->internalSampleRate, pDecoder->outputSampleRate
45549     );
45550     ma_channel_map_copy(converterConfig.channelMapIn,  pDecoder->internalChannelMap, pDecoder->internalChannels);
45551     ma_channel_map_copy(converterConfig.channelMapOut, pDecoder->outputChannelMap,   pDecoder->outputChannels);
45552     converterConfig.channelMixMode             = pConfig->channelMixMode;
45553     converterConfig.ditherMode                 = pConfig->ditherMode;
45554     converterConfig.resampling.allowDynamicSampleRate = MA_FALSE;   /* Never allow dynamic sample rate conversion. Setting this to true will disable passthrough optimizations. */
45555     converterConfig.resampling.algorithm       = pConfig->resampling.algorithm;
45556     converterConfig.resampling.linear.lpfOrder = pConfig->resampling.linear.lpfOrder;
45557     converterConfig.resampling.speex.quality   = pConfig->resampling.speex.quality;
45558
45559     return ma_data_converter_init(&converterConfig, &pDecoder->converter);
45560 }
45561
45562 /* WAV */
45563 #ifdef dr_wav_h
45564 #define MA_HAS_WAV
45565
45566 static size_t ma_decoder_internal_on_read__wav(void* pUserData, void* pBufferOut, size_t bytesToRead)
45567 {
45568     ma_decoder* pDecoder = (ma_decoder*)pUserData;
45569     MA_ASSERT(pDecoder != NULL);
45570
45571     return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
45572 }
45573
45574 static drwav_bool32 ma_decoder_internal_on_seek__wav(void* pUserData, int offset, drwav_seek_origin origin)
45575 {
45576     ma_decoder* pDecoder = (ma_decoder*)pUserData;
45577     MA_ASSERT(pDecoder != NULL);
45578
45579     return ma_decoder_seek_bytes(pDecoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
45580 }
45581
45582 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__wav(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
45583 {
45584     drwav* pWav;
45585
45586     MA_ASSERT(pDecoder   != NULL);
45587     MA_ASSERT(pFramesOut != NULL);
45588
45589     pWav = (drwav*)pDecoder->pInternalDecoder;
45590     MA_ASSERT(pWav != NULL);
45591
45592     switch (pDecoder->internalFormat) {
45593         case ma_format_s16: return drwav_read_pcm_frames_s16(pWav, frameCount, (drwav_int16*)pFramesOut);
45594         case ma_format_s32: return drwav_read_pcm_frames_s32(pWav, frameCount, (drwav_int32*)pFramesOut);
45595         case ma_format_f32: return drwav_read_pcm_frames_f32(pWav, frameCount,       (float*)pFramesOut);
45596         default: break;
45597     }
45598
45599     /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */
45600     MA_ASSERT(MA_FALSE);
45601     return 0;
45602 }
45603
45604 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__wav(ma_decoder* pDecoder, ma_uint64 frameIndex)
45605 {
45606     drwav* pWav;
45607     drwav_bool32 result;
45608
45609     pWav = (drwav*)pDecoder->pInternalDecoder;
45610     MA_ASSERT(pWav != NULL);
45611
45612     result = drwav_seek_to_pcm_frame(pWav, frameIndex);
45613     if (result) {
45614         return MA_SUCCESS;
45615     } else {
45616         return MA_ERROR;
45617     }
45618 }
45619
45620 static ma_result ma_decoder_internal_on_uninit__wav(ma_decoder* pDecoder)
45621 {
45622     drwav_uninit((drwav*)pDecoder->pInternalDecoder);
45623     ma__free_from_callbacks(pDecoder->pInternalDecoder, &pDecoder->allocationCallbacks);
45624     return MA_SUCCESS;
45625 }
45626
45627 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__wav(ma_decoder* pDecoder)
45628 {
45629     return ((drwav*)pDecoder->pInternalDecoder)->totalPCMFrameCount;
45630 }
45631
45632 static ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
45633 {
45634     drwav* pWav;
45635     drwav_allocation_callbacks allocationCallbacks;
45636
45637     MA_ASSERT(pConfig != NULL);
45638     MA_ASSERT(pDecoder != NULL);
45639
45640     (void)pConfig;
45641
45642     pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pDecoder->allocationCallbacks);
45643     if (pWav == NULL) {
45644         return MA_OUT_OF_MEMORY;
45645     }
45646
45647     allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
45648     allocationCallbacks.onMalloc  = pDecoder->allocationCallbacks.onMalloc;
45649     allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
45650     allocationCallbacks.onFree    = pDecoder->allocationCallbacks.onFree;
45651
45652     /* Try opening the decoder first. */
45653     if (!drwav_init(pWav, ma_decoder_internal_on_read__wav, ma_decoder_internal_on_seek__wav, pDecoder, &allocationCallbacks)) {
45654         ma__free_from_callbacks(pWav, &pDecoder->allocationCallbacks);
45655         return MA_ERROR;
45656     }
45657
45658     /* If we get here it means we successfully initialized the WAV decoder. We can now initialize the rest of the ma_decoder. */
45659     pDecoder->onReadPCMFrames        = ma_decoder_internal_on_read_pcm_frames__wav;
45660     pDecoder->onSeekToPCMFrame       = ma_decoder_internal_on_seek_to_pcm_frame__wav;
45661     pDecoder->onUninit               = ma_decoder_internal_on_uninit__wav;
45662     pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__wav;
45663     pDecoder->pInternalDecoder       = pWav;
45664
45665     /* Try to be as optimal as possible for the internal format. If miniaudio does not support a format we will fall back to f32. */
45666     pDecoder->internalFormat = ma_format_unknown;
45667     switch (pWav->translatedFormatTag) {
45668         case DR_WAVE_FORMAT_PCM:
45669         {
45670             if (pWav->bitsPerSample == 8) {
45671                 pDecoder->internalFormat = ma_format_s16;
45672             } else if (pWav->bitsPerSample == 16) {
45673                 pDecoder->internalFormat = ma_format_s16;
45674             } else if (pWav->bitsPerSample == 32) {
45675                 pDecoder->internalFormat = ma_format_s32;
45676             }
45677         } break;
45678
45679         case DR_WAVE_FORMAT_IEEE_FLOAT:
45680         {
45681             if (pWav->bitsPerSample == 32) {
45682                 pDecoder->internalFormat = ma_format_f32;
45683             }
45684         } break;
45685
45686         case DR_WAVE_FORMAT_ALAW:
45687         case DR_WAVE_FORMAT_MULAW:
45688         case DR_WAVE_FORMAT_ADPCM:
45689         case DR_WAVE_FORMAT_DVI_ADPCM:
45690         {
45691             pDecoder->internalFormat = ma_format_s16;
45692         } break;
45693     }
45694
45695     if (pDecoder->internalFormat == ma_format_unknown) {
45696         pDecoder->internalFormat = ma_format_f32;
45697     }
45698
45699     pDecoder->internalChannels = pWav->channels;
45700     pDecoder->internalSampleRate = pWav->sampleRate;
45701     ma_get_standard_channel_map(ma_standard_channel_map_microsoft, pDecoder->internalChannels, pDecoder->internalChannelMap);
45702
45703     return MA_SUCCESS;
45704 }
45705 #endif  /* dr_wav_h */
45706
45707 /* FLAC */
45708 #ifdef dr_flac_h
45709 #define MA_HAS_FLAC
45710
45711 static size_t ma_decoder_internal_on_read__flac(void* pUserData, void* pBufferOut, size_t bytesToRead)
45712 {
45713     ma_decoder* pDecoder = (ma_decoder*)pUserData;
45714     MA_ASSERT(pDecoder != NULL);
45715
45716     return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
45717 }
45718
45719 static drflac_bool32 ma_decoder_internal_on_seek__flac(void* pUserData, int offset, drflac_seek_origin origin)
45720 {
45721     ma_decoder* pDecoder = (ma_decoder*)pUserData;
45722     MA_ASSERT(pDecoder != NULL);
45723
45724     return ma_decoder_seek_bytes(pDecoder, offset, (origin == drflac_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
45725 }
45726
45727 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__flac(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
45728 {
45729     drflac* pFlac;
45730
45731     MA_ASSERT(pDecoder   != NULL);
45732     MA_ASSERT(pFramesOut != NULL);
45733
45734     pFlac = (drflac*)pDecoder->pInternalDecoder;
45735     MA_ASSERT(pFlac != NULL);
45736
45737     switch (pDecoder->internalFormat) {
45738         case ma_format_s16: return drflac_read_pcm_frames_s16(pFlac, frameCount, (drflac_int16*)pFramesOut);
45739         case ma_format_s32: return drflac_read_pcm_frames_s32(pFlac, frameCount, (drflac_int32*)pFramesOut);
45740         case ma_format_f32: return drflac_read_pcm_frames_f32(pFlac, frameCount,        (float*)pFramesOut);
45741         default: break;
45742     }
45743
45744     /* Should never get here. If we do, it means the internal format was not set correctly at initialization time. */
45745     MA_ASSERT(MA_FALSE);
45746     return 0;
45747 }
45748
45749 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__flac(ma_decoder* pDecoder, ma_uint64 frameIndex)
45750 {
45751     drflac* pFlac;
45752     drflac_bool32 result;
45753
45754     pFlac = (drflac*)pDecoder->pInternalDecoder;
45755     MA_ASSERT(pFlac != NULL);
45756
45757     result = drflac_seek_to_pcm_frame(pFlac, frameIndex);
45758     if (result) {
45759         return MA_SUCCESS;
45760     } else {
45761         return MA_ERROR;
45762     }
45763 }
45764
45765 static ma_result ma_decoder_internal_on_uninit__flac(ma_decoder* pDecoder)
45766 {
45767     drflac_close((drflac*)pDecoder->pInternalDecoder);
45768     return MA_SUCCESS;
45769 }
45770
45771 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__flac(ma_decoder* pDecoder)
45772 {
45773     return ((drflac*)pDecoder->pInternalDecoder)->totalPCMFrameCount;
45774 }
45775
45776 static ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
45777 {
45778     drflac* pFlac;
45779     drflac_allocation_callbacks allocationCallbacks;
45780
45781     MA_ASSERT(pConfig  != NULL);
45782     MA_ASSERT(pDecoder != NULL);
45783
45784     allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
45785     allocationCallbacks.onMalloc  = pDecoder->allocationCallbacks.onMalloc;
45786     allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
45787     allocationCallbacks.onFree    = pDecoder->allocationCallbacks.onFree;
45788
45789     /* Try opening the decoder first. */
45790     pFlac = drflac_open(ma_decoder_internal_on_read__flac, ma_decoder_internal_on_seek__flac, pDecoder, &allocationCallbacks);
45791     if (pFlac == NULL) {
45792         return MA_ERROR;
45793     }
45794
45795     /* If we get here it means we successfully initialized the FLAC decoder. We can now initialize the rest of the ma_decoder. */
45796     pDecoder->onReadPCMFrames        = ma_decoder_internal_on_read_pcm_frames__flac;
45797     pDecoder->onSeekToPCMFrame       = ma_decoder_internal_on_seek_to_pcm_frame__flac;
45798     pDecoder->onUninit               = ma_decoder_internal_on_uninit__flac;
45799     pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__flac;
45800     pDecoder->pInternalDecoder       = pFlac;
45801
45802     /*
45803     dr_flac supports reading as s32, s16 and f32. Try to do a one-to-one mapping if possible, but fall back to s32 if not. s32 is the "native" FLAC format
45804     since it's the only one that's truly lossless. If the internal bits per sample is <= 16 we will decode to ma_format_s16 to keep it more efficient.
45805     */
45806     if (pConfig->format == ma_format_unknown) {
45807         if (pFlac->bitsPerSample <= 16) {
45808             pDecoder->internalFormat = ma_format_s16;
45809         } else {
45810             pDecoder->internalFormat = ma_format_s32;
45811         }
45812     } else {
45813         if (pConfig->format == ma_format_s16 || pConfig->format == ma_format_f32) {
45814             pDecoder->internalFormat = pConfig->format;
45815         } else {
45816             pDecoder->internalFormat = ma_format_s32;   /* s32 as the baseline to ensure no loss of precision for 24-bit encoded files. */
45817         }
45818     }
45819
45820     pDecoder->internalChannels = pFlac->channels;
45821     pDecoder->internalSampleRate = pFlac->sampleRate;
45822     ma_get_standard_channel_map(ma_standard_channel_map_flac, pDecoder->internalChannels, pDecoder->internalChannelMap);
45823
45824     return MA_SUCCESS;
45825 }
45826 #endif  /* dr_flac_h */
45827
45828 /* MP3 */
45829 #ifdef dr_mp3_h
45830 #define MA_HAS_MP3
45831
45832 static size_t ma_decoder_internal_on_read__mp3(void* pUserData, void* pBufferOut, size_t bytesToRead)
45833 {
45834     ma_decoder* pDecoder = (ma_decoder*)pUserData;
45835     MA_ASSERT(pDecoder != NULL);
45836
45837     return ma_decoder_read_bytes(pDecoder, pBufferOut, bytesToRead);
45838 }
45839
45840 static drmp3_bool32 ma_decoder_internal_on_seek__mp3(void* pUserData, int offset, drmp3_seek_origin origin)
45841 {
45842     ma_decoder* pDecoder = (ma_decoder*)pUserData;
45843     MA_ASSERT(pDecoder != NULL);
45844
45845     return ma_decoder_seek_bytes(pDecoder, offset, (origin == drmp3_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
45846 }
45847
45848 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__mp3(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
45849 {
45850     drmp3* pMP3;
45851
45852     MA_ASSERT(pDecoder   != NULL);
45853     MA_ASSERT(pFramesOut != NULL);
45854
45855     pMP3 = (drmp3*)pDecoder->pInternalDecoder;
45856     MA_ASSERT(pMP3 != NULL);
45857
45858 #if defined(DR_MP3_FLOAT_OUTPUT)
45859     MA_ASSERT(pDecoder->internalFormat == ma_format_f32);
45860     return drmp3_read_pcm_frames_f32(pMP3, frameCount, (float*)pFramesOut);
45861 #else
45862     MA_ASSERT(pDecoder->internalFormat == ma_format_s16);
45863     return drmp3_read_pcm_frames_s16(pMP3, frameCount, (drmp3_int16*)pFramesOut);
45864 #endif
45865 }
45866
45867 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__mp3(ma_decoder* pDecoder, ma_uint64 frameIndex)
45868 {
45869     drmp3* pMP3;
45870     drmp3_bool32 result;
45871
45872     pMP3 = (drmp3*)pDecoder->pInternalDecoder;
45873     MA_ASSERT(pMP3 != NULL);
45874
45875     result = drmp3_seek_to_pcm_frame(pMP3, frameIndex);
45876     if (result) {
45877         return MA_SUCCESS;
45878     } else {
45879         return MA_ERROR;
45880     }
45881 }
45882
45883 static ma_result ma_decoder_internal_on_uninit__mp3(ma_decoder* pDecoder)
45884 {
45885     drmp3_uninit((drmp3*)pDecoder->pInternalDecoder);
45886     ma__free_from_callbacks(pDecoder->pInternalDecoder, &pDecoder->allocationCallbacks);
45887     return MA_SUCCESS;
45888 }
45889
45890 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__mp3(ma_decoder* pDecoder)
45891 {
45892     return drmp3_get_pcm_frame_count((drmp3*)pDecoder->pInternalDecoder);
45893 }
45894
45895 static ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
45896 {
45897     drmp3* pMP3;
45898     drmp3_allocation_callbacks allocationCallbacks;
45899
45900     MA_ASSERT(pConfig != NULL);
45901     MA_ASSERT(pDecoder != NULL);
45902
45903     (void)pConfig;
45904
45905     pMP3 = (drmp3*)ma__malloc_from_callbacks(sizeof(*pMP3), &pDecoder->allocationCallbacks);
45906     if (pMP3 == NULL) {
45907         return MA_OUT_OF_MEMORY;
45908     }
45909
45910     allocationCallbacks.pUserData = pDecoder->allocationCallbacks.pUserData;
45911     allocationCallbacks.onMalloc  = pDecoder->allocationCallbacks.onMalloc;
45912     allocationCallbacks.onRealloc = pDecoder->allocationCallbacks.onRealloc;
45913     allocationCallbacks.onFree    = pDecoder->allocationCallbacks.onFree;
45914
45915     /*
45916     Try opening the decoder first. We always use whatever dr_mp3 reports for channel count and sample rate. The format is determined by
45917     the presence of DR_MP3_FLOAT_OUTPUT.
45918     */
45919     if (!drmp3_init(pMP3, ma_decoder_internal_on_read__mp3, ma_decoder_internal_on_seek__mp3, pDecoder, &allocationCallbacks)) {
45920         ma__free_from_callbacks(pMP3, &pDecoder->allocationCallbacks);
45921         return MA_ERROR;
45922     }
45923
45924     /* If we get here it means we successfully initialized the MP3 decoder. We can now initialize the rest of the ma_decoder. */
45925     pDecoder->onReadPCMFrames        = ma_decoder_internal_on_read_pcm_frames__mp3;
45926     pDecoder->onSeekToPCMFrame       = ma_decoder_internal_on_seek_to_pcm_frame__mp3;
45927     pDecoder->onUninit               = ma_decoder_internal_on_uninit__mp3;
45928     pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__mp3;
45929     pDecoder->pInternalDecoder       = pMP3;
45930
45931     /* Internal format. */
45932 #if defined(DR_MP3_FLOAT_OUTPUT)
45933     pDecoder->internalFormat     = ma_format_f32;
45934 #else
45935     pDecoder->internalFormat     = ma_format_s16;
45936 #endif
45937     pDecoder->internalChannels   = pMP3->channels;
45938     pDecoder->internalSampleRate = pMP3->sampleRate;
45939     ma_get_standard_channel_map(ma_standard_channel_map_default, pDecoder->internalChannels, pDecoder->internalChannelMap);
45940
45941     return MA_SUCCESS;
45942 }
45943 #endif  /* dr_mp3_h */
45944
45945 /* Vorbis */
45946 #ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H
45947 #define MA_HAS_VORBIS
45948
45949 /* The size in bytes of each chunk of data to read from the Vorbis stream. */
45950 #define MA_VORBIS_DATA_CHUNK_SIZE  4096
45951
45952 typedef struct
45953 {
45954     stb_vorbis* pInternalVorbis;
45955     ma_uint8* pData;
45956     size_t dataSize;
45957     size_t dataCapacity;
45958     ma_uint32 framesConsumed;  /* The number of frames consumed in ppPacketData. */
45959     ma_uint32 framesRemaining; /* The number of frames remaining in ppPacketData. */
45960     float** ppPacketData;
45961 } ma_vorbis_decoder;
45962
45963 static ma_uint64 ma_vorbis_decoder_read_pcm_frames(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
45964 {
45965     float* pFramesOutF;
45966     ma_uint64 totalFramesRead;
45967
45968     MA_ASSERT(pVorbis  != NULL);
45969     MA_ASSERT(pDecoder != NULL);
45970
45971     pFramesOutF = (float*)pFramesOut;
45972
45973     totalFramesRead = 0;
45974     while (frameCount > 0) {
45975         /* Read from the in-memory buffer first. */
45976         ma_uint32 framesToReadFromCache = (ma_uint32)ma_min(pVorbis->framesRemaining, frameCount);  /* Safe cast because pVorbis->framesRemaining is 32-bit. */
45977
45978         if (pFramesOut != NULL) {
45979             ma_uint64 iFrame;
45980             for (iFrame = 0; iFrame < framesToReadFromCache; iFrame += 1) {
45981                 ma_uint32 iChannel;
45982                 for (iChannel = 0; iChannel < pDecoder->internalChannels; ++iChannel) {
45983                     pFramesOutF[iChannel] = pVorbis->ppPacketData[iChannel][pVorbis->framesConsumed+iFrame];
45984                 }
45985                 pFramesOutF += pDecoder->internalChannels;
45986             }
45987         }
45988
45989         pVorbis->framesConsumed  += framesToReadFromCache;
45990         pVorbis->framesRemaining -= framesToReadFromCache;
45991         frameCount               -= framesToReadFromCache;
45992         totalFramesRead          += framesToReadFromCache;
45993
45994         if (frameCount == 0) {
45995             break;
45996         }
45997
45998         MA_ASSERT(pVorbis->framesRemaining == 0);
45999
46000         /* We've run out of cached frames, so decode the next packet and continue iteration. */
46001         do
46002         {
46003             int samplesRead;
46004             int consumedDataSize;
46005
46006             if (pVorbis->dataSize > INT_MAX) {
46007                 break;  /* Too big. */
46008             }
46009
46010             samplesRead = 0;
46011             consumedDataSize = stb_vorbis_decode_frame_pushdata(pVorbis->pInternalVorbis, pVorbis->pData, (int)pVorbis->dataSize, NULL, (float***)&pVorbis->ppPacketData, &samplesRead);
46012             if (consumedDataSize != 0) {
46013                 size_t leftoverDataSize = (pVorbis->dataSize - (size_t)consumedDataSize);
46014                 size_t i;
46015                 for (i = 0; i < leftoverDataSize; ++i) {
46016                     pVorbis->pData[i] = pVorbis->pData[i + consumedDataSize];
46017                 }
46018
46019                 pVorbis->dataSize = leftoverDataSize;
46020                 pVorbis->framesConsumed = 0;
46021                 pVorbis->framesRemaining = samplesRead;
46022                 break;
46023             } else {
46024                 /* Need more data. If there's any room in the existing buffer allocation fill that first. Otherwise expand. */
46025                 size_t bytesRead;
46026                 if (pVorbis->dataCapacity == pVorbis->dataSize) {
46027                     /* No room. Expand. */
46028                     size_t oldCap = pVorbis->dataCapacity;
46029                     size_t newCap = pVorbis->dataCapacity + MA_VORBIS_DATA_CHUNK_SIZE;
46030                     ma_uint8* pNewData;
46031
46032                     pNewData = (ma_uint8*)ma__realloc_from_callbacks(pVorbis->pData, newCap, oldCap, &pDecoder->allocationCallbacks);
46033                     if (pNewData == NULL) {
46034                         return totalFramesRead; /* Out of memory. */
46035                     }
46036
46037                     pVorbis->pData = pNewData;
46038                     pVorbis->dataCapacity = newCap;
46039                 }
46040
46041                 /* Fill in a chunk. */
46042                 bytesRead = ma_decoder_read_bytes(pDecoder, pVorbis->pData + pVorbis->dataSize, (pVorbis->dataCapacity - pVorbis->dataSize));
46043                 if (bytesRead == 0) {
46044                     return totalFramesRead; /* Error reading more data. */
46045                 }
46046
46047                 pVorbis->dataSize += bytesRead;
46048             }
46049         } while (MA_TRUE);
46050     }
46051
46052     return totalFramesRead;
46053 }
46054
46055 static ma_result ma_vorbis_decoder_seek_to_pcm_frame(ma_vorbis_decoder* pVorbis, ma_decoder* pDecoder, ma_uint64 frameIndex)
46056 {
46057     float buffer[4096];
46058
46059     MA_ASSERT(pVorbis != NULL);
46060     MA_ASSERT(pDecoder != NULL);
46061
46062     /*
46063     This is terribly inefficient because stb_vorbis does not have a good seeking solution with it's push API. Currently this just performs
46064     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
46065     find the one containing the sample we need. Then we know exactly where to seek for stb_vorbis.
46066
46067     TODO: Use seeking logic documented for stb_vorbis_flush_pushdata().
46068     */
46069     if (!ma_decoder_seek_bytes(pDecoder, 0, ma_seek_origin_start)) {
46070         return MA_ERROR;
46071     }
46072
46073     stb_vorbis_flush_pushdata(pVorbis->pInternalVorbis);
46074     pVorbis->framesConsumed  = 0;
46075     pVorbis->framesRemaining = 0;
46076     pVorbis->dataSize        = 0;
46077
46078     while (frameIndex > 0) {
46079         ma_uint32 framesRead;
46080         ma_uint32 framesToRead = ma_countof(buffer)/pDecoder->internalChannels;
46081         if (framesToRead > frameIndex) {
46082             framesToRead = (ma_uint32)frameIndex;
46083         }
46084
46085         framesRead = (ma_uint32)ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, buffer, framesToRead);
46086         if (framesRead == 0) {
46087             return MA_ERROR;
46088         }
46089
46090         frameIndex -= framesRead;
46091     }
46092
46093     return MA_SUCCESS;
46094 }
46095
46096
46097 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__vorbis(ma_decoder* pDecoder, ma_uint64 frameIndex)
46098 {
46099     ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
46100     MA_ASSERT(pVorbis != NULL);
46101
46102     return ma_vorbis_decoder_seek_to_pcm_frame(pVorbis, pDecoder, frameIndex);
46103 }
46104
46105 static ma_result ma_decoder_internal_on_uninit__vorbis(ma_decoder* pDecoder)
46106 {
46107     ma_vorbis_decoder* pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
46108     MA_ASSERT(pVorbis != NULL);
46109
46110     stb_vorbis_close(pVorbis->pInternalVorbis);
46111     ma__free_from_callbacks(pVorbis->pData, &pDecoder->allocationCallbacks);
46112     ma__free_from_callbacks(pVorbis,        &pDecoder->allocationCallbacks);
46113
46114     return MA_SUCCESS;
46115 }
46116
46117 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__vorbis(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
46118 {
46119     ma_vorbis_decoder* pVorbis;
46120
46121     MA_ASSERT(pDecoder   != NULL);
46122     MA_ASSERT(pFramesOut != NULL);
46123     MA_ASSERT(pDecoder->internalFormat == ma_format_f32);
46124
46125     pVorbis = (ma_vorbis_decoder*)pDecoder->pInternalDecoder;
46126     MA_ASSERT(pVorbis != NULL);
46127
46128     return ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, pFramesOut, frameCount);
46129 }
46130
46131 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__vorbis(ma_decoder* pDecoder)
46132 {
46133     /* No good way to do this with Vorbis. */
46134     (void)pDecoder;
46135     return 0;
46136 }
46137
46138 static ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46139 {
46140     stb_vorbis* pInternalVorbis = NULL;
46141     size_t dataSize = 0;
46142     size_t dataCapacity = 0;
46143     ma_uint8* pData = NULL;
46144     stb_vorbis_info vorbisInfo;
46145     size_t vorbisDataSize;
46146     ma_vorbis_decoder* pVorbis;
46147
46148     MA_ASSERT(pConfig != NULL);
46149     MA_ASSERT(pDecoder != NULL);
46150
46151     /* We grow the buffer in chunks. */
46152     do
46153     {
46154         /* Allocate memory for a new chunk. */
46155         ma_uint8* pNewData;
46156         size_t bytesRead;
46157         int vorbisError = 0;
46158         int consumedDataSize = 0;
46159         size_t oldCapacity = dataCapacity;
46160
46161         dataCapacity += MA_VORBIS_DATA_CHUNK_SIZE;
46162         pNewData = (ma_uint8*)ma__realloc_from_callbacks(pData, dataCapacity, oldCapacity, &pDecoder->allocationCallbacks);
46163         if (pNewData == NULL) {
46164             ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
46165             return MA_OUT_OF_MEMORY;
46166         }
46167
46168         pData = pNewData;
46169
46170         /* Fill in a chunk. */
46171         bytesRead = ma_decoder_read_bytes(pDecoder, pData + dataSize, (dataCapacity - dataSize));
46172         if (bytesRead == 0) {
46173             return MA_ERROR;
46174         }
46175
46176         dataSize += bytesRead;
46177         if (dataSize > INT_MAX) {
46178             return MA_ERROR;   /* Too big. */
46179         }
46180
46181         pInternalVorbis = stb_vorbis_open_pushdata(pData, (int)dataSize, &consumedDataSize, &vorbisError, NULL);
46182         if (pInternalVorbis != NULL) {
46183             /*
46184             If we get here it means we were able to open the stb_vorbis decoder. There may be some leftover bytes in our buffer, so
46185             we need to move those bytes down to the front of the buffer since they'll be needed for future decoding.
46186             */
46187             size_t leftoverDataSize = (dataSize - (size_t)consumedDataSize);
46188             size_t i;
46189             for (i = 0; i < leftoverDataSize; ++i) {
46190                 pData[i] = pData[i + consumedDataSize];
46191             }
46192
46193             dataSize = leftoverDataSize;
46194             break;  /* Success. */
46195         } else {
46196             if (vorbisError == VORBIS_need_more_data) {
46197                 continue;
46198             } else {
46199                 return MA_ERROR;   /* Failed to open the stb_vorbis decoder. */
46200             }
46201         }
46202     } while (MA_TRUE);
46203
46204
46205     /* If we get here it means we successfully opened the Vorbis decoder. */
46206     vorbisInfo = stb_vorbis_get_info(pInternalVorbis);
46207
46208     /* Don't allow more than MA_MAX_CHANNELS channels. */
46209     if (vorbisInfo.channels > MA_MAX_CHANNELS) {
46210         stb_vorbis_close(pInternalVorbis);
46211         ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
46212         return MA_ERROR;   /* Too many channels. */
46213     }
46214
46215     vorbisDataSize = sizeof(ma_vorbis_decoder) + sizeof(float)*vorbisInfo.max_frame_size;
46216     pVorbis = (ma_vorbis_decoder*)ma__malloc_from_callbacks(vorbisDataSize, &pDecoder->allocationCallbacks);
46217     if (pVorbis == NULL) {
46218         stb_vorbis_close(pInternalVorbis);
46219         ma__free_from_callbacks(pData, &pDecoder->allocationCallbacks);
46220         return MA_OUT_OF_MEMORY;
46221     }
46222
46223     MA_ZERO_MEMORY(pVorbis, vorbisDataSize);
46224     pVorbis->pInternalVorbis = pInternalVorbis;
46225     pVorbis->pData = pData;
46226     pVorbis->dataSize = dataSize;
46227     pVorbis->dataCapacity = dataCapacity;
46228
46229     pDecoder->onReadPCMFrames        = ma_decoder_internal_on_read_pcm_frames__vorbis;
46230     pDecoder->onSeekToPCMFrame       = ma_decoder_internal_on_seek_to_pcm_frame__vorbis;
46231     pDecoder->onUninit               = ma_decoder_internal_on_uninit__vorbis;
46232     pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__vorbis;
46233     pDecoder->pInternalDecoder       = pVorbis;
46234
46235     /* The internal format is always f32. */
46236     pDecoder->internalFormat     = ma_format_f32;
46237     pDecoder->internalChannels   = vorbisInfo.channels;
46238     pDecoder->internalSampleRate = vorbisInfo.sample_rate;
46239     ma_get_standard_channel_map(ma_standard_channel_map_vorbis, pDecoder->internalChannels, pDecoder->internalChannelMap);
46240
46241     return MA_SUCCESS;
46242 }
46243 #endif  /* STB_VORBIS_INCLUDE_STB_VORBIS_H */
46244
46245 /* Raw */
46246 static ma_uint64 ma_decoder_internal_on_read_pcm_frames__raw(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
46247 {
46248     ma_uint32 bpf;
46249     ma_uint64 totalFramesRead;
46250     void* pRunningFramesOut;
46251
46252     MA_ASSERT(pDecoder != NULL);
46253
46254     /* For raw decoding we just read directly from the decoder's callbacks. */
46255     bpf = ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
46256
46257     totalFramesRead   = 0;
46258     pRunningFramesOut = pFramesOut;
46259
46260     while (totalFramesRead < frameCount) {
46261         ma_uint64 framesReadThisIteration;
46262         ma_uint64 framesToReadThisIteration = (frameCount - totalFramesRead);
46263         if (framesToReadThisIteration > 0x7FFFFFFF/bpf) {
46264             framesToReadThisIteration = 0x7FFFFFFF/bpf;
46265         }
46266
46267         if (pFramesOut != NULL) {
46268             framesReadThisIteration = ma_decoder_read_bytes(pDecoder, pRunningFramesOut, (size_t)framesToReadThisIteration * bpf) / bpf;    /* Safe cast to size_t. */
46269             pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIteration * bpf);
46270         } else {
46271             /* We'll first try seeking. If this fails it means the end was reached and we'll to do a read-and-discard slow path to get the exact amount. */
46272             if (ma_decoder_seek_bytes(pDecoder, (int)framesToReadThisIteration, ma_seek_origin_current)) {
46273                 framesReadThisIteration = framesToReadThisIteration;
46274             } else {
46275                 /* Slow path. Need to fall back to a read-and-discard. This is required so we can get the exact number of remaining. */
46276                 ma_uint8 buffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
46277                 ma_uint32 bufferCap = sizeof(buffer) / bpf;
46278
46279                 framesReadThisIteration = 0;
46280                 while (framesReadThisIteration < framesToReadThisIteration) {
46281                     ma_uint64 framesReadNow;
46282                     ma_uint64 framesToReadNow = framesToReadThisIteration - framesReadThisIteration;
46283                     if (framesToReadNow > bufferCap) {
46284                         framesToReadNow = bufferCap;
46285                     }
46286
46287                     framesReadNow = ma_decoder_read_bytes(pDecoder, buffer, (size_t)(framesToReadNow * bpf)) / bpf; /* Safe cast. */
46288                     framesReadThisIteration += framesReadNow;
46289
46290                     if (framesReadNow < framesToReadNow) {
46291                         break;  /* The end has been reached. */
46292                     }
46293                 }
46294             }
46295         }
46296
46297         totalFramesRead += framesReadThisIteration;
46298
46299         if (framesReadThisIteration < framesToReadThisIteration) {
46300             break;  /* Done. */
46301         }
46302     }
46303
46304     return totalFramesRead;
46305 }
46306
46307 static ma_result ma_decoder_internal_on_seek_to_pcm_frame__raw(ma_decoder* pDecoder, ma_uint64 frameIndex)
46308 {
46309     ma_bool32 result = MA_FALSE;
46310     ma_uint64 totalBytesToSeek;
46311
46312     MA_ASSERT(pDecoder != NULL);
46313
46314     if (pDecoder->onSeek == NULL) {
46315         return MA_ERROR;
46316     }
46317
46318     /* The callback uses a 32 bit integer whereas we use a 64 bit unsigned integer. We just need to continuously seek until we're at the correct position. */
46319     totalBytesToSeek = frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
46320     if (totalBytesToSeek < 0x7FFFFFFF) {
46321         /* Simple case. */
46322         result = ma_decoder_seek_bytes(pDecoder, (int)(frameIndex * ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels)), ma_seek_origin_start);
46323     } else {
46324         /* Complex case. Start by doing a seek relative to the start. Then keep looping using offset seeking. */
46325         result = ma_decoder_seek_bytes(pDecoder, 0x7FFFFFFF, ma_seek_origin_start);
46326         if (result == MA_TRUE) {
46327             totalBytesToSeek -= 0x7FFFFFFF;
46328
46329             while (totalBytesToSeek > 0) {
46330                 ma_uint64 bytesToSeekThisIteration = totalBytesToSeek;
46331                 if (bytesToSeekThisIteration > 0x7FFFFFFF) {
46332                     bytesToSeekThisIteration = 0x7FFFFFFF;
46333                 }
46334
46335                 result = ma_decoder_seek_bytes(pDecoder, (int)bytesToSeekThisIteration, ma_seek_origin_current);
46336                 if (result != MA_TRUE) {
46337                     break;
46338                 }
46339
46340                 totalBytesToSeek -= bytesToSeekThisIteration;
46341             }
46342         }
46343     }
46344
46345     if (result) {
46346         return MA_SUCCESS;
46347     } else {
46348         return MA_ERROR;
46349     }
46350 }
46351
46352 static ma_result ma_decoder_internal_on_uninit__raw(ma_decoder* pDecoder)
46353 {
46354     (void)pDecoder;
46355     return MA_SUCCESS;
46356 }
46357
46358 static ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__raw(ma_decoder* pDecoder)
46359 {
46360     (void)pDecoder;
46361     return 0;
46362 }
46363
46364 static ma_result ma_decoder_init_raw__internal(const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder)
46365 {
46366     MA_ASSERT(pConfigIn != NULL);
46367     MA_ASSERT(pConfigOut != NULL);
46368     MA_ASSERT(pDecoder != NULL);
46369
46370     (void)pConfigOut;
46371
46372     pDecoder->onReadPCMFrames        = ma_decoder_internal_on_read_pcm_frames__raw;
46373     pDecoder->onSeekToPCMFrame       = ma_decoder_internal_on_seek_to_pcm_frame__raw;
46374     pDecoder->onUninit               = ma_decoder_internal_on_uninit__raw;
46375     pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__raw;
46376
46377     /* Internal format. */
46378     pDecoder->internalFormat     = pConfigIn->format;
46379     pDecoder->internalChannels   = pConfigIn->channels;
46380     pDecoder->internalSampleRate = pConfigIn->sampleRate;
46381     ma_channel_map_copy(pDecoder->internalChannelMap, pConfigIn->channelMap, pConfigIn->channels);
46382
46383     return MA_SUCCESS;
46384 }
46385
46386 static ma_result ma_decoder__init_allocation_callbacks(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46387 {
46388     MA_ASSERT(pDecoder != NULL);
46389
46390     if (pConfig != NULL) {
46391         return ma_allocation_callbacks_init_copy(&pDecoder->allocationCallbacks, &pConfig->allocationCallbacks);
46392     } else {
46393         pDecoder->allocationCallbacks = ma_allocation_callbacks_init_default();
46394         return MA_SUCCESS;
46395     }
46396 }
46397
46398 static ma_result ma_decoder__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
46399 {
46400     ma_uint64 framesRead = ma_decoder_read_pcm_frames((ma_decoder*)pDataSource, pFramesOut, frameCount);
46401
46402     if (pFramesRead != NULL) {
46403         *pFramesRead = framesRead;
46404     }
46405
46406     if (framesRead < frameCount) {
46407         return MA_AT_END;
46408     }
46409
46410     return MA_SUCCESS;
46411 }
46412
46413 static ma_result ma_decoder__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
46414 {
46415     return ma_decoder_seek_to_pcm_frame((ma_decoder*)pDataSource, frameIndex);
46416 }
46417
46418 static ma_result ma_decoder__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
46419 {
46420     ma_decoder* pDecoder = (ma_decoder*)pDataSource;
46421
46422     *pFormat     = pDecoder->outputFormat;
46423     *pChannels   = pDecoder->outputChannels;
46424     *pSampleRate = pDecoder->outputSampleRate;
46425
46426     return MA_SUCCESS;
46427 }
46428
46429 static ma_result ma_decoder__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pLength)
46430 {
46431     ma_decoder* pDecoder = (ma_decoder*)pDataSource;
46432
46433     return ma_decoder_get_cursor_in_pcm_frames(pDecoder, pLength);
46434 }
46435
46436 static ma_result ma_decoder__data_source_on_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
46437 {
46438     ma_decoder* pDecoder = (ma_decoder*)pDataSource;
46439
46440     *pLength = ma_decoder_get_length_in_pcm_frames(pDecoder);
46441     if (*pLength == 0) {
46442         return MA_NOT_IMPLEMENTED;
46443     }
46444
46445     return MA_SUCCESS;
46446 }
46447
46448 static ma_result ma_decoder__preinit(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46449 {
46450     ma_result result;
46451
46452     MA_ASSERT(pConfig != NULL);
46453
46454     if (pDecoder == NULL) {
46455         return MA_INVALID_ARGS;
46456     }
46457
46458     MA_ZERO_OBJECT(pDecoder);
46459
46460     if (onRead == NULL || onSeek == NULL) {
46461         return MA_INVALID_ARGS;
46462     }
46463
46464     pDecoder->ds.onRead          = ma_decoder__data_source_on_read;
46465     pDecoder->ds.onSeek          = ma_decoder__data_source_on_seek;
46466     pDecoder->ds.onGetDataFormat = ma_decoder__data_source_on_get_data_format;
46467     pDecoder->ds.onGetCursor     = ma_decoder__data_source_on_get_cursor;
46468     pDecoder->ds.onGetLength     = ma_decoder__data_source_on_get_length;
46469
46470     pDecoder->onRead    = onRead;
46471     pDecoder->onSeek    = onSeek;
46472     pDecoder->pUserData = pUserData;
46473
46474     result = ma_decoder__init_allocation_callbacks(pConfig, pDecoder);
46475     if (result != MA_SUCCESS) {
46476         return result;
46477     }
46478
46479     return MA_SUCCESS;
46480 }
46481
46482 static ma_result ma_decoder__postinit(const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46483 {
46484     ma_result result = MA_SUCCESS;
46485
46486     /* Basic validation in case the internal decoder supports different limits to miniaudio. */
46487     if (pDecoder->internalChannels < MA_MIN_CHANNELS || pDecoder->internalChannels > MA_MAX_CHANNELS) {
46488         result = MA_INVALID_DATA;
46489     }
46490
46491     if (result == MA_SUCCESS) {
46492         result = ma_decoder__init_data_converter(pDecoder, pConfig);
46493     }
46494
46495     /* If we failed post initialization we need to uninitialize the decoder before returning to prevent a memory leak. */
46496     if (result != MA_SUCCESS) {
46497         ma_decoder_uninit(pDecoder);
46498         return result;
46499     }
46500
46501     return result;
46502 }
46503
46504 MA_API ma_result ma_decoder_init_wav(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46505 {
46506 #ifdef MA_HAS_WAV
46507     ma_decoder_config config;
46508     ma_result result;
46509
46510     config = ma_decoder_config_init_copy(pConfig);
46511
46512     result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
46513     if (result != MA_SUCCESS) {
46514         return result;
46515     }
46516
46517     result = ma_decoder_init_wav__internal(&config, pDecoder);
46518     if (result != MA_SUCCESS) {
46519         return result;
46520     }
46521
46522     return ma_decoder__postinit(&config, pDecoder);
46523 #else
46524     (void)onRead;
46525     (void)onSeek;
46526     (void)pUserData;
46527     (void)pConfig;
46528     (void)pDecoder;
46529     return MA_NO_BACKEND;
46530 #endif
46531 }
46532
46533 MA_API ma_result ma_decoder_init_flac(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46534 {
46535 #ifdef MA_HAS_FLAC
46536     ma_decoder_config config;
46537     ma_result result;
46538
46539     config = ma_decoder_config_init_copy(pConfig);
46540
46541     result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
46542     if (result != MA_SUCCESS) {
46543         return result;
46544     }
46545
46546     result = ma_decoder_init_flac__internal(&config, pDecoder);
46547     if (result != MA_SUCCESS) {
46548         return result;
46549     }
46550
46551     return ma_decoder__postinit(&config, pDecoder);
46552 #else
46553     (void)onRead;
46554     (void)onSeek;
46555     (void)pUserData;
46556     (void)pConfig;
46557     (void)pDecoder;
46558     return MA_NO_BACKEND;
46559 #endif
46560 }
46561
46562 MA_API ma_result ma_decoder_init_mp3(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46563 {
46564 #ifdef MA_HAS_MP3
46565     ma_decoder_config config;
46566     ma_result result;
46567
46568     config = ma_decoder_config_init_copy(pConfig);
46569
46570     result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
46571     if (result != MA_SUCCESS) {
46572         return result;
46573     }
46574
46575     result = ma_decoder_init_mp3__internal(&config, pDecoder);
46576     if (result != MA_SUCCESS) {
46577         return result;
46578     }
46579
46580     return ma_decoder__postinit(&config, pDecoder);
46581 #else
46582     (void)onRead;
46583     (void)onSeek;
46584     (void)pUserData;
46585     (void)pConfig;
46586     (void)pDecoder;
46587     return MA_NO_BACKEND;
46588 #endif
46589 }
46590
46591 MA_API ma_result ma_decoder_init_vorbis(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46592 {
46593 #ifdef MA_HAS_VORBIS
46594     ma_decoder_config config;
46595     ma_result result;
46596
46597     config = ma_decoder_config_init_copy(pConfig);
46598
46599     result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
46600     if (result != MA_SUCCESS) {
46601         return result;
46602     }
46603
46604     result = ma_decoder_init_vorbis__internal(&config, pDecoder);
46605     if (result != MA_SUCCESS) {
46606         return result;
46607     }
46608
46609     return ma_decoder__postinit(&config, pDecoder);
46610 #else
46611     (void)onRead;
46612     (void)onSeek;
46613     (void)pUserData;
46614     (void)pConfig;
46615     (void)pDecoder;
46616     return MA_NO_BACKEND;
46617 #endif
46618 }
46619
46620 MA_API ma_result ma_decoder_init_raw(ma_decoder_read_proc onRead, ma_decoder_seek_proc onSeek, void* pUserData, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder)
46621 {
46622     ma_decoder_config config;
46623     ma_result result;
46624
46625     config = ma_decoder_config_init_copy(pConfigOut);
46626
46627     result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
46628     if (result != MA_SUCCESS) {
46629         return result;
46630     }
46631
46632     result = ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder);
46633     if (result != MA_SUCCESS) {
46634         return result;
46635     }
46636
46637     return ma_decoder__postinit(&config, pDecoder);
46638 }
46639
46640 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)
46641 {
46642     ma_result result = MA_NO_BACKEND;
46643
46644     MA_ASSERT(pConfig != NULL);
46645     MA_ASSERT(pDecoder != NULL);
46646
46647     /* Silence some warnings in the case that we don't have any decoder backends enabled. */
46648     (void)onRead;
46649     (void)onSeek;
46650     (void)pUserData;
46651     (void)pConfig;
46652     (void)pDecoder;
46653
46654     /* We use trial and error to open a decoder. */
46655
46656 #ifdef MA_HAS_WAV
46657     if (result != MA_SUCCESS) {
46658         result = ma_decoder_init_wav__internal(pConfig, pDecoder);
46659         if (result != MA_SUCCESS) {
46660             onSeek(pDecoder, 0, ma_seek_origin_start);
46661         }
46662     }
46663 #endif
46664 #ifdef MA_HAS_FLAC
46665     if (result != MA_SUCCESS) {
46666         result = ma_decoder_init_flac__internal(pConfig, pDecoder);
46667         if (result != MA_SUCCESS) {
46668             onSeek(pDecoder, 0, ma_seek_origin_start);
46669         }
46670     }
46671 #endif
46672 #ifdef MA_HAS_MP3
46673     if (result != MA_SUCCESS) {
46674         result = ma_decoder_init_mp3__internal(pConfig, pDecoder);
46675         if (result != MA_SUCCESS) {
46676             onSeek(pDecoder, 0, ma_seek_origin_start);
46677         }
46678     }
46679 #endif
46680 #ifdef MA_HAS_VORBIS
46681     if (result != MA_SUCCESS) {
46682         result = ma_decoder_init_vorbis__internal(pConfig, pDecoder);
46683         if (result != MA_SUCCESS) {
46684             onSeek(pDecoder, 0, ma_seek_origin_start);
46685         }
46686     }
46687 #endif
46688
46689     if (result != MA_SUCCESS) {
46690         return result;
46691     }
46692
46693     return ma_decoder__postinit(pConfig, pDecoder);
46694 }
46695
46696 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)
46697 {
46698     ma_decoder_config config;
46699     ma_result result;
46700
46701     config = ma_decoder_config_init_copy(pConfig);
46702
46703     result = ma_decoder__preinit(onRead, onSeek, pUserData, &config, pDecoder);
46704     if (result != MA_SUCCESS) {
46705         return result;
46706     }
46707
46708     return ma_decoder_init__internal(onRead, onSeek, pUserData, &config, pDecoder);
46709 }
46710
46711
46712 static size_t ma_decoder__on_read_memory(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead)
46713 {
46714     size_t bytesRemaining;
46715
46716     MA_ASSERT(pDecoder->backend.memory.dataSize >= pDecoder->backend.memory.currentReadPos);
46717
46718     bytesRemaining = pDecoder->backend.memory.dataSize - pDecoder->backend.memory.currentReadPos;
46719     if (bytesToRead > bytesRemaining) {
46720         bytesToRead = bytesRemaining;
46721     }
46722
46723     if (bytesToRead > 0) {
46724         MA_COPY_MEMORY(pBufferOut, pDecoder->backend.memory.pData + pDecoder->backend.memory.currentReadPos, bytesToRead);
46725         pDecoder->backend.memory.currentReadPos += bytesToRead;
46726     }
46727
46728     return bytesToRead;
46729 }
46730
46731 static ma_bool32 ma_decoder__on_seek_memory(ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin)
46732 {
46733     if (origin == ma_seek_origin_current) {
46734         if (byteOffset > 0) {
46735             if (pDecoder->backend.memory.currentReadPos + byteOffset > pDecoder->backend.memory.dataSize) {
46736                 byteOffset = (int)(pDecoder->backend.memory.dataSize - pDecoder->backend.memory.currentReadPos);  /* Trying to seek too far forward. */
46737             }
46738         } else {
46739             if (pDecoder->backend.memory.currentReadPos < (size_t)-byteOffset) {
46740                 byteOffset = -(int)pDecoder->backend.memory.currentReadPos;  /* Trying to seek too far backwards. */
46741             }
46742         }
46743
46744         /* This will never underflow thanks to the clamps above. */
46745         pDecoder->backend.memory.currentReadPos += byteOffset;
46746     } else {
46747         if ((ma_uint32)byteOffset <= pDecoder->backend.memory.dataSize) {
46748             pDecoder->backend.memory.currentReadPos = byteOffset;
46749         } else {
46750             pDecoder->backend.memory.currentReadPos = pDecoder->backend.memory.dataSize;  /* Trying to seek too far forward. */
46751         }
46752     }
46753
46754     return MA_TRUE;
46755 }
46756
46757 static ma_result ma_decoder__preinit_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46758 {
46759     ma_result result = ma_decoder__preinit(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, pConfig, pDecoder);
46760     if (result != MA_SUCCESS) {
46761         return result;
46762     }
46763
46764     if (pData == NULL || dataSize == 0) {
46765         return MA_INVALID_ARGS;
46766     }
46767
46768     pDecoder->backend.memory.pData = (const ma_uint8*)pData;
46769     pDecoder->backend.memory.dataSize = dataSize;
46770     pDecoder->backend.memory.currentReadPos = 0;
46771
46772     (void)pConfig;
46773     return MA_SUCCESS;
46774 }
46775
46776 MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46777 {
46778     ma_decoder_config config;
46779     ma_result result;
46780
46781     config = ma_decoder_config_init_copy(pConfig);  /* Make sure the config is not NULL. */
46782
46783     result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
46784     if (result != MA_SUCCESS) {
46785         return result;
46786     }
46787
46788     return ma_decoder_init__internal(ma_decoder__on_read_memory, ma_decoder__on_seek_memory, NULL, &config, pDecoder);
46789 }
46790
46791 MA_API ma_result ma_decoder_init_memory_wav(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46792 {
46793 #ifdef MA_HAS_WAV
46794     ma_decoder_config config;
46795     ma_result result;
46796
46797     config = ma_decoder_config_init_copy(pConfig);  /* Make sure the config is not NULL. */
46798
46799     result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
46800     if (result != MA_SUCCESS) {
46801         return result;
46802     }
46803
46804     result = ma_decoder_init_wav__internal(&config, pDecoder);
46805     if (result != MA_SUCCESS) {
46806         return result;
46807     }
46808
46809     return ma_decoder__postinit(&config, pDecoder);
46810 #else
46811     (void)pData;
46812     (void)dataSize;
46813     (void)pConfig;
46814     (void)pDecoder;
46815     return MA_NO_BACKEND;
46816 #endif
46817 }
46818
46819 MA_API ma_result ma_decoder_init_memory_flac(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46820 {
46821 #ifdef MA_HAS_FLAC
46822     ma_decoder_config config;
46823     ma_result result;
46824
46825     config = ma_decoder_config_init_copy(pConfig);  /* Make sure the config is not NULL. */
46826
46827     result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
46828     if (result != MA_SUCCESS) {
46829         return result;
46830     }
46831
46832     result = ma_decoder_init_flac__internal(&config, pDecoder);
46833     if (result != MA_SUCCESS) {
46834         return result;
46835     }
46836
46837     return ma_decoder__postinit(&config, pDecoder);
46838 #else
46839     (void)pData;
46840     (void)dataSize;
46841     (void)pConfig;
46842     (void)pDecoder;
46843     return MA_NO_BACKEND;
46844 #endif
46845 }
46846
46847 MA_API ma_result ma_decoder_init_memory_mp3(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46848 {
46849 #ifdef MA_HAS_MP3
46850     ma_decoder_config config;
46851     ma_result result;
46852
46853     config = ma_decoder_config_init_copy(pConfig);  /* Make sure the config is not NULL. */
46854
46855     result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
46856     if (result != MA_SUCCESS) {
46857         return result;
46858     }
46859
46860     result = ma_decoder_init_mp3__internal(&config, pDecoder);
46861     if (result != MA_SUCCESS) {
46862         return result;
46863     }
46864
46865     return ma_decoder__postinit(&config, pDecoder);
46866 #else
46867     (void)pData;
46868     (void)dataSize;
46869     (void)pConfig;
46870     (void)pDecoder;
46871     return MA_NO_BACKEND;
46872 #endif
46873 }
46874
46875 MA_API ma_result ma_decoder_init_memory_vorbis(const void* pData, size_t dataSize, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
46876 {
46877 #ifdef MA_HAS_VORBIS
46878     ma_decoder_config config;
46879     ma_result result;
46880
46881     config = ma_decoder_config_init_copy(pConfig);  /* Make sure the config is not NULL. */
46882
46883     result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
46884     if (result != MA_SUCCESS) {
46885         return result;
46886     }
46887
46888     result = ma_decoder_init_vorbis__internal(&config, pDecoder);
46889     if (result != MA_SUCCESS) {
46890         return result;
46891     }
46892
46893     return ma_decoder__postinit(&config, pDecoder);
46894 #else
46895     (void)pData;
46896     (void)dataSize;
46897     (void)pConfig;
46898     (void)pDecoder;
46899     return MA_NO_BACKEND;
46900 #endif
46901 }
46902
46903 MA_API ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder)
46904 {
46905     ma_decoder_config config;
46906     ma_result result;
46907
46908     config = ma_decoder_config_init_copy(pConfigOut);  /* Make sure the config is not NULL. */
46909
46910     result = ma_decoder__preinit_memory(pData, dataSize, &config, pDecoder);
46911     if (result != MA_SUCCESS) {
46912         return result;
46913     }
46914
46915     result = ma_decoder_init_raw__internal(pConfigIn, &config, pDecoder);
46916     if (result != MA_SUCCESS) {
46917         return result;
46918     }
46919
46920     return ma_decoder__postinit(&config, pDecoder);
46921 }
46922
46923
46924 #if defined(MA_HAS_WAV)    || \
46925     defined(MA_HAS_MP3)    || \
46926     defined(MA_HAS_FLAC)   || \
46927     defined(MA_HAS_VORBIS) || \
46928     defined(MA_HAS_OPUS)
46929 #define MA_HAS_PATH_API
46930 #endif
46931
46932 #if defined(MA_HAS_PATH_API)
46933 static const char* ma_path_file_name(const char* path)
46934 {
46935     const char* fileName;
46936
46937     if (path == NULL) {
46938         return NULL;
46939     }
46940
46941     fileName = path;
46942
46943     /* We just loop through the path until we find the last slash. */
46944     while (path[0] != '\0') {
46945         if (path[0] == '/' || path[0] == '\\') {
46946             fileName = path;
46947         }
46948
46949         path += 1;
46950     }
46951
46952     /* At this point the file name is sitting on a slash, so just move forward. */
46953     while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
46954         fileName += 1;
46955     }
46956
46957     return fileName;
46958 }
46959
46960 static const wchar_t* ma_path_file_name_w(const wchar_t* path)
46961 {
46962     const wchar_t* fileName;
46963
46964     if (path == NULL) {
46965         return NULL;
46966     }
46967
46968     fileName = path;
46969
46970     /* We just loop through the path until we find the last slash. */
46971     while (path[0] != '\0') {
46972         if (path[0] == '/' || path[0] == '\\') {
46973             fileName = path;
46974         }
46975
46976         path += 1;
46977     }
46978
46979     /* At this point the file name is sitting on a slash, so just move forward. */
46980     while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) {
46981         fileName += 1;
46982     }
46983
46984     return fileName;
46985 }
46986
46987
46988 static const char* ma_path_extension(const char* path)
46989 {
46990     const char* extension;
46991     const char* lastOccurance;
46992
46993     if (path == NULL) {
46994         path = "";
46995     }
46996
46997     extension = ma_path_file_name(path);
46998     lastOccurance = NULL;
46999
47000     /* Just find the last '.' and return. */
47001     while (extension[0] != '\0') {
47002         if (extension[0] == '.') {
47003             extension += 1;
47004             lastOccurance = extension;
47005         }
47006
47007         extension += 1;
47008     }
47009
47010     return (lastOccurance != NULL) ? lastOccurance : extension;
47011 }
47012
47013 static const wchar_t* ma_path_extension_w(const wchar_t* path)
47014 {
47015     const wchar_t* extension;
47016     const wchar_t* lastOccurance;
47017
47018     if (path == NULL) {
47019         path = L"";
47020     }
47021
47022     extension = ma_path_file_name_w(path);
47023     lastOccurance = NULL;
47024
47025     /* Just find the last '.' and return. */
47026     while (extension[0] != '\0') {
47027         if (extension[0] == '.') {
47028             extension += 1;
47029             lastOccurance = extension;
47030         }
47031
47032         extension += 1;
47033     }
47034
47035     return (lastOccurance != NULL) ? lastOccurance : extension;
47036 }
47037
47038
47039 static ma_bool32 ma_path_extension_equal(const char* path, const char* extension)
47040 {
47041     const char* ext1;
47042     const char* ext2;
47043
47044     if (path == NULL || extension == NULL) {
47045         return MA_FALSE;
47046     }
47047
47048     ext1 = extension;
47049     ext2 = ma_path_extension(path);
47050
47051 #if defined(_MSC_VER) || defined(__DMC__)
47052     return _stricmp(ext1, ext2) == 0;
47053 #else
47054     return strcasecmp(ext1, ext2) == 0;
47055 #endif
47056 }
47057
47058 static ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* extension)
47059 {
47060     const wchar_t* ext1;
47061     const wchar_t* ext2;
47062
47063     if (path == NULL || extension == NULL) {
47064         return MA_FALSE;
47065     }
47066
47067     ext1 = extension;
47068     ext2 = ma_path_extension_w(path);
47069
47070 #if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)
47071     return _wcsicmp(ext1, ext2) == 0;
47072 #else
47073     /*
47074     I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This
47075     isn't the most efficient way to do it, but it should work OK.
47076     */
47077     {
47078         char ext1MB[4096];
47079         char ext2MB[4096];
47080         const wchar_t* pext1 = ext1;
47081         const wchar_t* pext2 = ext2;
47082         mbstate_t mbs1;
47083         mbstate_t mbs2;
47084
47085         MA_ZERO_OBJECT(&mbs1);
47086         MA_ZERO_OBJECT(&mbs2);
47087
47088         if (wcsrtombs(ext1MB, &pext1, sizeof(ext1MB), &mbs1) == (size_t)-1) {
47089             return MA_FALSE;
47090         }
47091         if (wcsrtombs(ext2MB, &pext2, sizeof(ext2MB), &mbs2) == (size_t)-1) {
47092             return MA_FALSE;
47093         }
47094
47095         return strcasecmp(ext1MB, ext2MB) == 0;
47096     }
47097 #endif
47098 }
47099 #endif  /* MA_HAS_PATH_API */
47100
47101
47102
47103 static size_t ma_decoder__on_read_vfs(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead)
47104 {
47105     size_t bytesRead;
47106
47107     MA_ASSERT(pDecoder   != NULL);
47108     MA_ASSERT(pBufferOut != NULL);
47109
47110     ma_vfs_or_default_read(pDecoder->backend.vfs.pVFS, pDecoder->backend.vfs.file, pBufferOut, bytesToRead, &bytesRead);
47111
47112     return bytesRead;
47113 }
47114
47115 static ma_bool32 ma_decoder__on_seek_vfs(ma_decoder* pDecoder, int offset, ma_seek_origin origin)
47116 {
47117     ma_result result;
47118
47119     MA_ASSERT(pDecoder != NULL);
47120
47121     result = ma_vfs_or_default_seek(pDecoder->backend.vfs.pVFS, pDecoder->backend.vfs.file, offset, origin);
47122     if (result != MA_SUCCESS) {
47123         return MA_FALSE;
47124     }
47125
47126     return MA_TRUE;
47127 }
47128
47129 static ma_result ma_decoder__preinit_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47130 {
47131     ma_result result;
47132     ma_vfs_file file;
47133
47134     result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, pConfig, pDecoder);
47135     if (result != MA_SUCCESS) {
47136         return result;
47137     }
47138
47139     if (pFilePath == NULL || pFilePath[0] == '\0') {
47140         return MA_INVALID_ARGS;
47141     }
47142
47143     result = ma_vfs_or_default_open(pVFS, pFilePath, MA_OPEN_MODE_READ, &file);
47144     if (result != MA_SUCCESS) {
47145         return result;
47146     }
47147
47148     pDecoder->backend.vfs.pVFS = pVFS;
47149     pDecoder->backend.vfs.file = file;
47150
47151     return MA_SUCCESS;
47152 }
47153
47154 MA_API ma_result ma_decoder_init_vfs(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47155 {
47156     ma_result result;
47157     ma_decoder_config config;
47158
47159     config = ma_decoder_config_init_copy(pConfig);
47160     result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder);
47161     if (result != MA_SUCCESS) {
47162         return result;
47163     }
47164
47165     result = MA_NO_BACKEND;
47166
47167 #ifdef MA_HAS_WAV
47168     if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "wav")) {
47169         result = ma_decoder_init_wav__internal(&config, pDecoder);
47170         if (result != MA_SUCCESS) {
47171             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
47172         }
47173     }
47174 #endif
47175 #ifdef MA_HAS_FLAC
47176     if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "flac")) {
47177         result = ma_decoder_init_flac__internal(&config, pDecoder);
47178         if (result != MA_SUCCESS) {
47179             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
47180         }
47181     }
47182 #endif
47183 #ifdef MA_HAS_MP3
47184     if (result != MA_SUCCESS && ma_path_extension_equal(pFilePath, "mp3")) {
47185         result = ma_decoder_init_mp3__internal(&config, pDecoder);
47186         if (result != MA_SUCCESS) {
47187             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
47188         }
47189     }
47190 #endif
47191
47192     /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */
47193     if (result != MA_SUCCESS) {
47194         result = ma_decoder_init__internal(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, &config, pDecoder);
47195     } else {
47196         result = ma_decoder__postinit(&config, pDecoder);
47197     }
47198
47199     if (result != MA_SUCCESS) {
47200         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47201         return result;
47202     }
47203
47204     return MA_SUCCESS;
47205 }
47206
47207 MA_API ma_result ma_decoder_init_vfs_wav(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47208 {
47209 #ifdef MA_HAS_WAV
47210     ma_result result;
47211     ma_decoder_config config;
47212
47213     config = ma_decoder_config_init_copy(pConfig);
47214     result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder);
47215     if (result != MA_SUCCESS) {
47216         return result;
47217     }
47218
47219     result = ma_decoder_init_wav__internal(&config, pDecoder);
47220     if (result == MA_SUCCESS) {
47221         result = ma_decoder__postinit(&config, pDecoder);
47222     }
47223
47224     if (result != MA_SUCCESS) {
47225         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47226     }
47227
47228     return result;
47229 #else
47230     (void)pVFS;
47231     (void)pFilePath;
47232     (void)pConfig;
47233     (void)pDecoder;
47234     return MA_NO_BACKEND;
47235 #endif
47236 }
47237
47238 MA_API ma_result ma_decoder_init_vfs_flac(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47239 {
47240 #ifdef MA_HAS_FLAC
47241     ma_result result;
47242     ma_decoder_config config;
47243
47244     config = ma_decoder_config_init_copy(pConfig);
47245     result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder);
47246     if (result != MA_SUCCESS) {
47247         return result;
47248     }
47249
47250     result = ma_decoder_init_flac__internal(&config, pDecoder);
47251     if (result == MA_SUCCESS) {
47252         result = ma_decoder__postinit(&config, pDecoder);
47253     }
47254
47255     if (result != MA_SUCCESS) {
47256         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47257     }
47258
47259     return result;
47260 #else
47261     (void)pVFS;
47262     (void)pFilePath;
47263     (void)pConfig;
47264     (void)pDecoder;
47265     return MA_NO_BACKEND;
47266 #endif
47267 }
47268
47269 MA_API ma_result ma_decoder_init_vfs_mp3(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47270 {
47271 #ifdef MA_HAS_MP3
47272     ma_result result;
47273     ma_decoder_config config;
47274
47275     config = ma_decoder_config_init_copy(pConfig);
47276     result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder);
47277     if (result != MA_SUCCESS) {
47278         return result;
47279     }
47280
47281     result = ma_decoder_init_mp3__internal(&config, pDecoder);
47282     if (result == MA_SUCCESS) {
47283         result = ma_decoder__postinit(&config, pDecoder);
47284     }
47285
47286     if (result != MA_SUCCESS) {
47287         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47288     }
47289
47290     return result;
47291 #else
47292     (void)pVFS;
47293     (void)pFilePath;
47294     (void)pConfig;
47295     (void)pDecoder;
47296     return MA_NO_BACKEND;
47297 #endif
47298 }
47299
47300 MA_API ma_result ma_decoder_init_vfs_vorbis(ma_vfs* pVFS, const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47301 {
47302 #ifdef MA_HAS_VORBIS
47303     ma_result result;
47304     ma_decoder_config config;
47305
47306     config = ma_decoder_config_init_copy(pConfig);
47307     result = ma_decoder__preinit_vfs(pVFS, pFilePath, &config, pDecoder);
47308     if (result != MA_SUCCESS) {
47309         return result;
47310     }
47311
47312     result = ma_decoder_init_vorbis__internal(&config, pDecoder);
47313     if (result == MA_SUCCESS) {
47314         result = ma_decoder__postinit(&config, pDecoder);
47315     }
47316
47317     if (result != MA_SUCCESS) {
47318         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47319     }
47320
47321     return result;
47322 #else
47323     (void)pVFS;
47324     (void)pFilePath;
47325     (void)pConfig;
47326     (void)pDecoder;
47327     return MA_NO_BACKEND;
47328 #endif
47329 }
47330
47331
47332
47333 static ma_result ma_decoder__preinit_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47334 {
47335     ma_result result;
47336     ma_vfs_file file;
47337
47338     result = ma_decoder__preinit(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, pConfig, pDecoder);
47339     if (result != MA_SUCCESS) {
47340         return result;
47341     }
47342
47343     if (pFilePath == NULL || pFilePath[0] == '\0') {
47344         return MA_INVALID_ARGS;
47345     }
47346
47347     result = ma_vfs_or_default_open_w(pVFS, pFilePath, MA_OPEN_MODE_READ, &file);
47348     if (result != MA_SUCCESS) {
47349         return result;
47350     }
47351
47352     pDecoder->backend.vfs.pVFS = pVFS;
47353     pDecoder->backend.vfs.file = file;
47354
47355     return MA_SUCCESS;
47356 }
47357
47358 MA_API ma_result ma_decoder_init_vfs_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47359 {
47360     ma_result result;
47361     ma_decoder_config config;
47362
47363     config = ma_decoder_config_init_copy(pConfig);
47364     result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder);
47365     if (result != MA_SUCCESS) {
47366         return result;
47367     }
47368
47369     result = MA_NO_BACKEND;
47370
47371 #ifdef MA_HAS_WAV
47372     if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"wav")) {
47373         result = ma_decoder_init_wav__internal(&config, pDecoder);
47374         if (result != MA_SUCCESS) {
47375             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
47376         }
47377     }
47378 #endif
47379 #ifdef MA_HAS_FLAC
47380     if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"flac")) {
47381         result = ma_decoder_init_flac__internal(&config, pDecoder);
47382         if (result != MA_SUCCESS) {
47383             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
47384         }
47385     }
47386 #endif
47387 #ifdef MA_HAS_MP3
47388     if (result != MA_SUCCESS && ma_path_extension_equal_w(pFilePath, L"mp3")) {
47389         result = ma_decoder_init_mp3__internal(&config, pDecoder);
47390         if (result != MA_SUCCESS) {
47391             ma_decoder__on_seek_vfs(pDecoder, 0, ma_seek_origin_start);
47392         }
47393     }
47394 #endif
47395
47396     /* If we still haven't got a result just use trial and error. Otherwise we can finish up. */
47397     if (result != MA_SUCCESS) {
47398         result = ma_decoder_init__internal(ma_decoder__on_read_vfs, ma_decoder__on_seek_vfs, NULL, &config, pDecoder);
47399     } else {
47400         result = ma_decoder__postinit(&config, pDecoder);
47401     }
47402
47403     if (result != MA_SUCCESS) {
47404         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47405         return result;
47406     }
47407
47408     return MA_SUCCESS;
47409 }
47410
47411 MA_API ma_result ma_decoder_init_vfs_wav_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47412 {
47413 #ifdef MA_HAS_WAV
47414     ma_result result;
47415     ma_decoder_config config;
47416
47417     config = ma_decoder_config_init_copy(pConfig);
47418     result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder);
47419     if (result != MA_SUCCESS) {
47420         return result;
47421     }
47422
47423     result = ma_decoder_init_wav__internal(&config, pDecoder);
47424     if (result == MA_SUCCESS) {
47425         result = ma_decoder__postinit(&config, pDecoder);
47426     }
47427
47428     if (result != MA_SUCCESS) {
47429         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47430     }
47431
47432     return result;
47433 #else
47434     (void)pVFS;
47435     (void)pFilePath;
47436     (void)pConfig;
47437     (void)pDecoder;
47438     return MA_NO_BACKEND;
47439 #endif
47440 }
47441
47442 MA_API ma_result ma_decoder_init_vfs_flac_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47443 {
47444 #ifdef MA_HAS_FLAC
47445     ma_result result;
47446     ma_decoder_config config;
47447
47448     config = ma_decoder_config_init_copy(pConfig);
47449     result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder);
47450     if (result != MA_SUCCESS) {
47451         return result;
47452     }
47453
47454     result = ma_decoder_init_flac__internal(&config, pDecoder);
47455     if (result == MA_SUCCESS) {
47456         result = ma_decoder__postinit(&config, pDecoder);
47457     }
47458
47459     if (result != MA_SUCCESS) {
47460         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47461     }
47462
47463     return result;
47464 #else
47465     (void)pVFS;
47466     (void)pFilePath;
47467     (void)pConfig;
47468     (void)pDecoder;
47469     return MA_NO_BACKEND;
47470 #endif
47471 }
47472
47473 MA_API ma_result ma_decoder_init_vfs_mp3_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47474 {
47475 #ifdef MA_HAS_MP3
47476     ma_result result;
47477     ma_decoder_config config;
47478
47479     config = ma_decoder_config_init_copy(pConfig);
47480     result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder);
47481     if (result != MA_SUCCESS) {
47482         return result;
47483     }
47484
47485     result = ma_decoder_init_mp3__internal(&config, pDecoder);
47486     if (result == MA_SUCCESS) {
47487         result = ma_decoder__postinit(&config, pDecoder);
47488     }
47489
47490     if (result != MA_SUCCESS) {
47491         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47492     }
47493
47494     return result;
47495 #else
47496     (void)pVFS;
47497     (void)pFilePath;
47498     (void)pConfig;
47499     (void)pDecoder;
47500     return MA_NO_BACKEND;
47501 #endif
47502 }
47503
47504 MA_API ma_result ma_decoder_init_vfs_vorbis_w(ma_vfs* pVFS, const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47505 {
47506 #ifdef MA_HAS_VORBIS
47507     ma_result result;
47508     ma_decoder_config config;
47509
47510     config = ma_decoder_config_init_copy(pConfig);
47511     result = ma_decoder__preinit_vfs_w(pVFS, pFilePath, &config, pDecoder);
47512     if (result != MA_SUCCESS) {
47513         return result;
47514     }
47515
47516     result = ma_decoder_init_vorbis__internal(&config, pDecoder);
47517     if (result == MA_SUCCESS) {
47518         result = ma_decoder__postinit(&config, pDecoder);
47519     }
47520
47521     if (result != MA_SUCCESS) {
47522         ma_vfs_or_default_close(pVFS, pDecoder->backend.vfs.file);
47523     }
47524
47525     return result;
47526 #else
47527     (void)pVFS;
47528     (void)pFilePath;
47529     (void)pConfig;
47530     (void)pDecoder;
47531     return MA_NO_BACKEND;
47532 #endif
47533 }
47534
47535
47536
47537 MA_API ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47538 {
47539     return ma_decoder_init_vfs(NULL, pFilePath, pConfig, pDecoder);
47540 }
47541
47542 MA_API ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47543 {
47544     return ma_decoder_init_vfs_wav(NULL, pFilePath, pConfig, pDecoder);
47545 }
47546
47547 MA_API ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47548 {
47549     return ma_decoder_init_vfs_flac(NULL, pFilePath, pConfig, pDecoder);
47550 }
47551
47552 MA_API ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47553 {
47554     return ma_decoder_init_vfs_mp3(NULL, pFilePath, pConfig, pDecoder);
47555 }
47556
47557 MA_API ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47558 {
47559     return ma_decoder_init_vfs_vorbis(NULL, pFilePath, pConfig, pDecoder);
47560 }
47561
47562
47563
47564 MA_API ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47565 {
47566     return ma_decoder_init_vfs_w(NULL, pFilePath, pConfig, pDecoder);
47567 }
47568
47569 MA_API ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47570 {
47571     return ma_decoder_init_vfs_wav_w(NULL, pFilePath, pConfig, pDecoder);
47572 }
47573
47574 MA_API ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47575 {
47576     return ma_decoder_init_vfs_flac_w(NULL, pFilePath, pConfig, pDecoder);
47577 }
47578
47579 MA_API ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47580 {
47581     return ma_decoder_init_vfs_mp3_w(NULL, pFilePath, pConfig, pDecoder);
47582 }
47583
47584 MA_API ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder)
47585 {
47586     return ma_decoder_init_vfs_vorbis_w(NULL, pFilePath, pConfig, pDecoder);
47587 }
47588
47589 MA_API ma_result ma_decoder_uninit(ma_decoder* pDecoder)
47590 {
47591     if (pDecoder == NULL) {
47592         return MA_INVALID_ARGS;
47593     }
47594
47595     if (pDecoder->onUninit) {
47596         pDecoder->onUninit(pDecoder);
47597     }
47598
47599     if (pDecoder->onRead == ma_decoder__on_read_vfs) {
47600         ma_vfs_or_default_close(pDecoder->backend.vfs.pVFS, pDecoder->backend.vfs.file);
47601     }
47602
47603     ma_data_converter_uninit(&pDecoder->converter);
47604
47605     return MA_SUCCESS;
47606 }
47607
47608 MA_API ma_result ma_decoder_get_cursor_in_pcm_frames(ma_decoder* pDecoder, ma_uint64* pCursor)
47609 {
47610     if (pCursor == NULL) {
47611         return MA_INVALID_ARGS;
47612     }
47613
47614     *pCursor = 0;
47615
47616     if (pDecoder == NULL) {
47617         return MA_INVALID_ARGS;
47618     }
47619
47620     *pCursor = pDecoder->readPointerInPCMFrames;
47621
47622     return MA_SUCCESS;
47623 }
47624
47625 MA_API ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder)
47626 {
47627     if (pDecoder == NULL) {
47628         return 0;
47629     }
47630
47631     if (pDecoder->onGetLengthInPCMFrames) {
47632         ma_uint64 nativeLengthInPCMFrames = pDecoder->onGetLengthInPCMFrames(pDecoder);
47633         if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) {
47634             return nativeLengthInPCMFrames;
47635         } else {
47636             return ma_calculate_frame_count_after_resampling(pDecoder->outputSampleRate, pDecoder->internalSampleRate, nativeLengthInPCMFrames);
47637         }
47638     }
47639
47640     return 0;
47641 }
47642
47643 MA_API ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount)
47644 {
47645     ma_result result;
47646     ma_uint64 totalFramesReadOut;
47647     ma_uint64 totalFramesReadIn;
47648     void* pRunningFramesOut;
47649
47650     if (pDecoder == NULL) {
47651         return 0;
47652     }
47653
47654     if (pDecoder->onReadPCMFrames == NULL) {
47655         return 0;
47656     }
47657
47658     /* Fast path. */
47659     if (pDecoder->converter.isPassthrough) {
47660         totalFramesReadOut = pDecoder->onReadPCMFrames(pDecoder, pFramesOut, frameCount);
47661     } else {
47662         /*
47663         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
47664         need to run through each sample because we need to ensure it's internal cache is updated.
47665         */
47666         if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) {
47667             totalFramesReadOut = pDecoder->onReadPCMFrames(pDecoder, NULL, frameCount);   /* All decoder backends must support passing in NULL for the output buffer. */
47668         } else {
47669             /* Slow path. Need to run everything through the data converter. */
47670             totalFramesReadOut = 0;
47671             totalFramesReadIn  = 0;
47672             pRunningFramesOut  = pFramesOut;
47673
47674             while (totalFramesReadOut < frameCount) {
47675                 ma_uint8 pIntermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];  /* In internal format. */
47676                 ma_uint64 intermediaryBufferCap = sizeof(pIntermediaryBuffer) / ma_get_bytes_per_frame(pDecoder->internalFormat, pDecoder->internalChannels);
47677                 ma_uint64 framesToReadThisIterationIn;
47678                 ma_uint64 framesReadThisIterationIn;
47679                 ma_uint64 framesToReadThisIterationOut;
47680                 ma_uint64 framesReadThisIterationOut;
47681                 ma_uint64 requiredInputFrameCount;
47682
47683                 framesToReadThisIterationOut = (frameCount - totalFramesReadOut);
47684                 framesToReadThisIterationIn = framesToReadThisIterationOut;
47685                 if (framesToReadThisIterationIn > intermediaryBufferCap) {
47686                     framesToReadThisIterationIn = intermediaryBufferCap;
47687                 }
47688
47689                 requiredInputFrameCount = ma_data_converter_get_required_input_frame_count(&pDecoder->converter, framesToReadThisIterationOut);
47690                 if (framesToReadThisIterationIn > requiredInputFrameCount) {
47691                     framesToReadThisIterationIn = requiredInputFrameCount;
47692                 }
47693
47694                 if (requiredInputFrameCount > 0) {
47695                     framesReadThisIterationIn = pDecoder->onReadPCMFrames(pDecoder, pIntermediaryBuffer, framesToReadThisIterationIn);
47696                     totalFramesReadIn += framesReadThisIterationIn;
47697                 } else {
47698                     framesReadThisIterationIn = 0;
47699                 }
47700
47701                 /*
47702                 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
47703                 input frames, we still want to try processing frames because there may some output frames generated from cached input data.
47704                 */
47705                 framesReadThisIterationOut = framesToReadThisIterationOut;
47706                 result = ma_data_converter_process_pcm_frames(&pDecoder->converter, pIntermediaryBuffer, &framesReadThisIterationIn, pRunningFramesOut, &framesReadThisIterationOut);
47707                 if (result != MA_SUCCESS) {
47708                     break;
47709                 }
47710
47711                 totalFramesReadOut += framesReadThisIterationOut;
47712
47713                 if (pRunningFramesOut != NULL) {
47714                     pRunningFramesOut = ma_offset_ptr(pRunningFramesOut, framesReadThisIterationOut * ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels));
47715                 }
47716
47717                 if (framesReadThisIterationIn == 0 && framesReadThisIterationOut == 0) {
47718                     break;  /* We're done. */
47719                 }
47720             }
47721         }
47722     }
47723
47724     pDecoder->readPointerInPCMFrames += totalFramesReadOut;
47725
47726     return totalFramesReadOut;
47727 }
47728
47729 MA_API ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex)
47730 {
47731     if (pDecoder == NULL) {
47732         return MA_INVALID_ARGS;
47733     }
47734
47735     if (pDecoder->onSeekToPCMFrame) {
47736         ma_result result;
47737         ma_uint64 internalFrameIndex;
47738         if (pDecoder->internalSampleRate == pDecoder->outputSampleRate) {
47739             internalFrameIndex = frameIndex;
47740         } else {
47741             internalFrameIndex = ma_calculate_frame_count_after_resampling(pDecoder->internalSampleRate, pDecoder->outputSampleRate, frameIndex);
47742         }
47743
47744         result = pDecoder->onSeekToPCMFrame(pDecoder, internalFrameIndex);
47745         if (result == MA_SUCCESS) {
47746             pDecoder->readPointerInPCMFrames = frameIndex;
47747         }
47748
47749         return result;
47750     }
47751
47752     /* Should never get here, but if we do it means onSeekToPCMFrame was not set by the backend. */
47753     return MA_INVALID_ARGS;
47754 }
47755
47756 MA_API ma_result ma_decoder_get_available_frames(ma_decoder* pDecoder, ma_uint64* pAvailableFrames)
47757 {
47758     ma_uint64 totalFrameCount;
47759
47760     if (pAvailableFrames == NULL) {
47761         return MA_INVALID_ARGS;
47762     }
47763
47764     *pAvailableFrames = 0;
47765
47766     if (pDecoder == NULL) {
47767         return MA_INVALID_ARGS;
47768     }
47769
47770     totalFrameCount = ma_decoder_get_length_in_pcm_frames(pDecoder);
47771     if (totalFrameCount == 0) {
47772         return MA_NOT_IMPLEMENTED;
47773     }
47774
47775     if (totalFrameCount <= pDecoder->readPointerInPCMFrames) {
47776         *pAvailableFrames = 0;
47777     } else {
47778         *pAvailableFrames = totalFrameCount - pDecoder->readPointerInPCMFrames;
47779     }
47780
47781     return MA_SUCCESS;   /* No frames available. */
47782 }
47783
47784
47785 static ma_result ma_decoder__full_decode_and_uninit(ma_decoder* pDecoder, ma_decoder_config* pConfigOut, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
47786 {
47787     ma_uint64 totalFrameCount;
47788     ma_uint64 bpf;
47789     ma_uint64 dataCapInFrames;
47790     void* pPCMFramesOut;
47791
47792     MA_ASSERT(pDecoder != NULL);
47793
47794     totalFrameCount = 0;
47795     bpf = ma_get_bytes_per_frame(pDecoder->outputFormat, pDecoder->outputChannels);
47796
47797     /* The frame count is unknown until we try reading. Thus, we just run in a loop. */
47798     dataCapInFrames = 0;
47799     pPCMFramesOut = NULL;
47800     for (;;) {
47801         ma_uint64 frameCountToTryReading;
47802         ma_uint64 framesJustRead;
47803
47804         /* Make room if there's not enough. */
47805         if (totalFrameCount == dataCapInFrames) {
47806             void* pNewPCMFramesOut;
47807             ma_uint64 oldDataCapInFrames = dataCapInFrames;
47808             ma_uint64 newDataCapInFrames = dataCapInFrames*2;
47809             if (newDataCapInFrames == 0) {
47810                 newDataCapInFrames = 4096;
47811             }
47812
47813             if ((newDataCapInFrames * bpf) > MA_SIZE_MAX) {
47814                 ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
47815                 return MA_TOO_BIG;
47816             }
47817
47818
47819             pNewPCMFramesOut = (void*)ma__realloc_from_callbacks(pPCMFramesOut, (size_t)(newDataCapInFrames * bpf), (size_t)(oldDataCapInFrames * bpf), &pDecoder->allocationCallbacks);
47820             if (pNewPCMFramesOut == NULL) {
47821                 ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
47822                 return MA_OUT_OF_MEMORY;
47823             }
47824
47825             dataCapInFrames = newDataCapInFrames;
47826             pPCMFramesOut = pNewPCMFramesOut;
47827         }
47828
47829         frameCountToTryReading = dataCapInFrames - totalFrameCount;
47830         MA_ASSERT(frameCountToTryReading > 0);
47831
47832         framesJustRead = ma_decoder_read_pcm_frames(pDecoder, (ma_uint8*)pPCMFramesOut + (totalFrameCount * bpf), frameCountToTryReading);
47833         totalFrameCount += framesJustRead;
47834
47835         if (framesJustRead < frameCountToTryReading) {
47836             break;
47837         }
47838     }
47839
47840
47841     if (pConfigOut != NULL) {
47842         pConfigOut->format = pDecoder->outputFormat;
47843         pConfigOut->channels = pDecoder->outputChannels;
47844         pConfigOut->sampleRate = pDecoder->outputSampleRate;
47845         ma_channel_map_copy(pConfigOut->channelMap, pDecoder->outputChannelMap, pDecoder->outputChannels);
47846     }
47847
47848     if (ppPCMFramesOut != NULL) {
47849         *ppPCMFramesOut = pPCMFramesOut;
47850     } else {
47851         ma__free_from_callbacks(pPCMFramesOut, &pDecoder->allocationCallbacks);
47852     }
47853
47854     if (pFrameCountOut != NULL) {
47855         *pFrameCountOut = totalFrameCount;
47856     }
47857
47858     ma_decoder_uninit(pDecoder);
47859     return MA_SUCCESS;
47860 }
47861
47862 MA_API ma_result ma_decode_from_vfs(ma_vfs* pVFS, const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
47863 {
47864     ma_result result;
47865     ma_decoder_config config;
47866     ma_decoder decoder;
47867
47868     if (pFrameCountOut != NULL) {
47869         *pFrameCountOut = 0;
47870     }
47871     if (ppPCMFramesOut != NULL) {
47872         *ppPCMFramesOut = NULL;
47873     }
47874
47875     config = ma_decoder_config_init_copy(pConfig);
47876
47877     result = ma_decoder_init_vfs(pVFS, pFilePath, &config, &decoder);
47878     if (result != MA_SUCCESS) {
47879         return result;
47880     }
47881
47882     result = ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
47883
47884     return result;
47885 }
47886
47887 MA_API ma_result ma_decode_file(const char* pFilePath, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
47888 {
47889     return ma_decode_from_vfs(NULL, pFilePath, pConfig, pFrameCountOut, ppPCMFramesOut);
47890 }
47891
47892 MA_API ma_result ma_decode_memory(const void* pData, size_t dataSize, ma_decoder_config* pConfig, ma_uint64* pFrameCountOut, void** ppPCMFramesOut)
47893 {
47894     ma_decoder_config config;
47895     ma_decoder decoder;
47896     ma_result result;
47897
47898     if (pFrameCountOut != NULL) {
47899         *pFrameCountOut = 0;
47900     }
47901     if (ppPCMFramesOut != NULL) {
47902         *ppPCMFramesOut = NULL;
47903     }
47904
47905     if (pData == NULL || dataSize == 0) {
47906         return MA_INVALID_ARGS;
47907     }
47908
47909     config = ma_decoder_config_init_copy(pConfig);
47910
47911     result = ma_decoder_init_memory(pData, dataSize, &config, &decoder);
47912     if (result != MA_SUCCESS) {
47913         return result;
47914     }
47915
47916     return ma_decoder__full_decode_and_uninit(&decoder, pConfig, pFrameCountOut, ppPCMFramesOut);
47917 }
47918 #endif  /* MA_NO_DECODING */
47919
47920
47921 #ifndef MA_NO_ENCODING
47922
47923 #if defined(MA_HAS_WAV)
47924 static size_t ma_encoder__internal_on_write_wav(void* pUserData, const void* pData, size_t bytesToWrite)
47925 {
47926     ma_encoder* pEncoder = (ma_encoder*)pUserData;
47927     MA_ASSERT(pEncoder != NULL);
47928
47929     return pEncoder->onWrite(pEncoder, pData, bytesToWrite);
47930 }
47931
47932 static drwav_bool32 ma_encoder__internal_on_seek_wav(void* pUserData, int offset, drwav_seek_origin origin)
47933 {
47934     ma_encoder* pEncoder = (ma_encoder*)pUserData;
47935     MA_ASSERT(pEncoder != NULL);
47936
47937     return pEncoder->onSeek(pEncoder, offset, (origin == drwav_seek_origin_start) ? ma_seek_origin_start : ma_seek_origin_current);
47938 }
47939
47940 static ma_result ma_encoder__on_init_wav(ma_encoder* pEncoder)
47941 {
47942     drwav_data_format wavFormat;
47943     drwav_allocation_callbacks allocationCallbacks;
47944     drwav* pWav;
47945
47946     MA_ASSERT(pEncoder != NULL);
47947
47948     pWav = (drwav*)ma__malloc_from_callbacks(sizeof(*pWav), &pEncoder->config.allocationCallbacks);
47949     if (pWav == NULL) {
47950         return MA_OUT_OF_MEMORY;
47951     }
47952
47953     wavFormat.container     = drwav_container_riff;
47954     wavFormat.channels      = pEncoder->config.channels;
47955     wavFormat.sampleRate    = pEncoder->config.sampleRate;
47956     wavFormat.bitsPerSample = ma_get_bytes_per_sample(pEncoder->config.format) * 8;
47957     if (pEncoder->config.format == ma_format_f32) {
47958         wavFormat.format    = DR_WAVE_FORMAT_IEEE_FLOAT;
47959     } else {
47960         wavFormat.format    = DR_WAVE_FORMAT_PCM;
47961     }
47962
47963     allocationCallbacks.pUserData = pEncoder->config.allocationCallbacks.pUserData;
47964     allocationCallbacks.onMalloc  = pEncoder->config.allocationCallbacks.onMalloc;
47965     allocationCallbacks.onRealloc = pEncoder->config.allocationCallbacks.onRealloc;
47966     allocationCallbacks.onFree    = pEncoder->config.allocationCallbacks.onFree;
47967
47968     if (!drwav_init_write(pWav, &wavFormat, ma_encoder__internal_on_write_wav, ma_encoder__internal_on_seek_wav, pEncoder, &allocationCallbacks)) {
47969         return MA_ERROR;
47970     }
47971
47972     pEncoder->pInternalEncoder = pWav;
47973
47974     return MA_SUCCESS;
47975 }
47976
47977 static void ma_encoder__on_uninit_wav(ma_encoder* pEncoder)
47978 {
47979     drwav* pWav;
47980
47981     MA_ASSERT(pEncoder != NULL);
47982
47983     pWav = (drwav*)pEncoder->pInternalEncoder;
47984     MA_ASSERT(pWav != NULL);
47985
47986     drwav_uninit(pWav);
47987     ma__free_from_callbacks(pWav, &pEncoder->config.allocationCallbacks);
47988 }
47989
47990 static ma_uint64 ma_encoder__on_write_pcm_frames_wav(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount)
47991 {
47992     drwav* pWav;
47993
47994     MA_ASSERT(pEncoder != NULL);
47995
47996     pWav = (drwav*)pEncoder->pInternalEncoder;
47997     MA_ASSERT(pWav != NULL);
47998
47999     return drwav_write_pcm_frames(pWav, frameCount, pFramesIn);
48000 }
48001 #endif
48002
48003 MA_API ma_encoder_config ma_encoder_config_init(ma_resource_format resourceFormat, ma_format format, ma_uint32 channels, ma_uint32 sampleRate)
48004 {
48005     ma_encoder_config config;
48006
48007     MA_ZERO_OBJECT(&config);
48008     config.resourceFormat = resourceFormat;
48009     config.format = format;
48010     config.channels = channels;
48011     config.sampleRate = sampleRate;
48012
48013     return config;
48014 }
48015
48016 MA_API ma_result ma_encoder_preinit(const ma_encoder_config* pConfig, ma_encoder* pEncoder)
48017 {
48018     ma_result result;
48019
48020     if (pEncoder == NULL) {
48021         return MA_INVALID_ARGS;
48022     }
48023
48024     MA_ZERO_OBJECT(pEncoder);
48025
48026     if (pConfig == NULL) {
48027         return MA_INVALID_ARGS;
48028     }
48029
48030     if (pConfig->format == ma_format_unknown || pConfig->channels == 0 || pConfig->sampleRate == 0) {
48031         return MA_INVALID_ARGS;
48032     }
48033
48034     pEncoder->config = *pConfig;
48035
48036     result = ma_allocation_callbacks_init_copy(&pEncoder->config.allocationCallbacks, &pConfig->allocationCallbacks);
48037     if (result != MA_SUCCESS) {
48038         return result;
48039     }
48040
48041     return MA_SUCCESS;
48042 }
48043
48044 MA_API ma_result ma_encoder_init__internal(ma_encoder_write_proc onWrite, ma_encoder_seek_proc onSeek, void* pUserData, ma_encoder* pEncoder)
48045 {
48046     ma_result result = MA_SUCCESS;
48047
48048     /* This assumes ma_encoder_preinit() has been called prior. */
48049     MA_ASSERT(pEncoder != NULL);
48050
48051     if (onWrite == NULL || onSeek == NULL) {
48052         return MA_INVALID_ARGS;
48053     }
48054
48055     pEncoder->onWrite   = onWrite;
48056     pEncoder->onSeek    = onSeek;
48057     pEncoder->pUserData = pUserData;
48058
48059     switch (pEncoder->config.resourceFormat)
48060     {
48061         case ma_resource_format_wav:
48062         {
48063         #if defined(MA_HAS_WAV)
48064             pEncoder->onInit           = ma_encoder__on_init_wav;
48065             pEncoder->onUninit         = ma_encoder__on_uninit_wav;
48066             pEncoder->onWritePCMFrames = ma_encoder__on_write_pcm_frames_wav;
48067         #else
48068             result = MA_NO_BACKEND;
48069         #endif
48070         } break;
48071
48072         default:
48073         {
48074             result = MA_INVALID_ARGS;
48075         } break;
48076     }
48077
48078     /* Getting here means we should have our backend callbacks set up. */
48079     if (result == MA_SUCCESS) {
48080         result = pEncoder->onInit(pEncoder);
48081         if (result != MA_SUCCESS) {
48082             return result;
48083         }
48084     }
48085
48086     return MA_SUCCESS;
48087 }
48088
48089 MA_API size_t ma_encoder__on_write_stdio(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite)
48090 {
48091     return fwrite(pBufferIn, 1, bytesToWrite, (FILE*)pEncoder->pFile);
48092 }
48093
48094 MA_API ma_bool32 ma_encoder__on_seek_stdio(ma_encoder* pEncoder, int byteOffset, ma_seek_origin origin)
48095 {
48096     return fseek((FILE*)pEncoder->pFile, byteOffset, (origin == ma_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
48097 }
48098
48099 MA_API ma_result ma_encoder_init_file(const char* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
48100 {
48101     ma_result result;
48102     FILE* pFile;
48103
48104     result = ma_encoder_preinit(pConfig, pEncoder);
48105     if (result != MA_SUCCESS) {
48106         return result;
48107     }
48108
48109     /* Now open the file. If this fails we don't need to uninitialize the encoder. */
48110     result = ma_fopen(&pFile, pFilePath, "wb");
48111     if (pFile == NULL) {
48112         return result;
48113     }
48114
48115     pEncoder->pFile = pFile;
48116
48117     return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder);
48118 }
48119
48120 MA_API ma_result ma_encoder_init_file_w(const wchar_t* pFilePath, const ma_encoder_config* pConfig, ma_encoder* pEncoder)
48121 {
48122     ma_result result;
48123     FILE* pFile;
48124
48125     result = ma_encoder_preinit(pConfig, pEncoder);
48126     if (result != MA_SUCCESS) {
48127         return result;
48128     }
48129
48130     /* Now open the file. If this fails we don't need to uninitialize the encoder. */
48131     result = ma_wfopen(&pFile, pFilePath, L"wb", &pEncoder->config.allocationCallbacks);
48132     if (pFile != NULL) {
48133         return result;
48134     }
48135
48136     pEncoder->pFile = pFile;
48137
48138     return ma_encoder_init__internal(ma_encoder__on_write_stdio, ma_encoder__on_seek_stdio, NULL, pEncoder);
48139 }
48140
48141 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)
48142 {
48143     ma_result result;
48144
48145     result = ma_encoder_preinit(pConfig, pEncoder);
48146     if (result != MA_SUCCESS) {
48147         return result;
48148     }
48149
48150     return ma_encoder_init__internal(onWrite, onSeek, pUserData, pEncoder);
48151 }
48152
48153
48154 MA_API void ma_encoder_uninit(ma_encoder* pEncoder)
48155 {
48156     if (pEncoder == NULL) {
48157         return;
48158     }
48159
48160     if (pEncoder->onUninit) {
48161         pEncoder->onUninit(pEncoder);
48162     }
48163
48164     /* If we have a file handle, close it. */
48165     if (pEncoder->onWrite == ma_encoder__on_write_stdio) {
48166         fclose((FILE*)pEncoder->pFile);
48167     }
48168 }
48169
48170
48171 MA_API ma_uint64 ma_encoder_write_pcm_frames(ma_encoder* pEncoder, const void* pFramesIn, ma_uint64 frameCount)
48172 {
48173     if (pEncoder == NULL || pFramesIn == NULL) {
48174         return 0;
48175     }
48176
48177     return pEncoder->onWritePCMFrames(pEncoder, pFramesIn, frameCount);
48178 }
48179 #endif  /* MA_NO_ENCODING */
48180
48181
48182
48183 /**************************************************************************************************************************************************************
48184
48185 Generation
48186
48187 **************************************************************************************************************************************************************/
48188 #ifndef MA_NO_GENERATION
48189 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)
48190 {
48191     ma_waveform_config config;
48192
48193     MA_ZERO_OBJECT(&config);
48194     config.format     = format;
48195     config.channels   = channels;
48196     config.sampleRate = sampleRate;
48197     config.type       = type;
48198     config.amplitude  = amplitude;
48199     config.frequency  = frequency;
48200
48201     return config;
48202 }
48203
48204 static ma_result ma_waveform__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
48205 {
48206     ma_uint64 framesRead = ma_waveform_read_pcm_frames((ma_waveform*)pDataSource, pFramesOut, frameCount);
48207
48208     if (pFramesRead != NULL) {
48209         *pFramesRead = framesRead;
48210     }
48211
48212     if (framesRead < frameCount) {
48213         return MA_AT_END;
48214     }
48215
48216     return MA_SUCCESS;
48217 }
48218
48219 static ma_result ma_waveform__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
48220 {
48221     return ma_waveform_seek_to_pcm_frame((ma_waveform*)pDataSource, frameIndex);
48222 }
48223
48224 static ma_result ma_waveform__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
48225 {
48226     ma_waveform* pWaveform = (ma_waveform*)pDataSource;
48227
48228     *pFormat     = pWaveform->config.format;
48229     *pChannels   = pWaveform->config.channels;
48230     *pSampleRate = pWaveform->config.sampleRate;
48231
48232     return MA_SUCCESS;
48233 }
48234
48235 static ma_result ma_waveform__data_source_on_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
48236 {
48237     ma_waveform* pWaveform = (ma_waveform*)pDataSource;
48238
48239     *pCursor = (ma_uint64)(pWaveform->time / pWaveform->advance);
48240
48241     return MA_SUCCESS;
48242 }
48243
48244 static double ma_waveform__calculate_advance(ma_uint32 sampleRate, double frequency)
48245 {
48246     return (1.0 / (sampleRate / frequency));
48247 }
48248
48249 static void ma_waveform__update_advance(ma_waveform* pWaveform)
48250 {
48251     pWaveform->advance = ma_waveform__calculate_advance(pWaveform->config.sampleRate, pWaveform->config.frequency);
48252 }
48253
48254 MA_API ma_result ma_waveform_init(const ma_waveform_config* pConfig, ma_waveform* pWaveform)
48255 {
48256     if (pWaveform == NULL) {
48257         return MA_INVALID_ARGS;
48258     }
48259
48260     MA_ZERO_OBJECT(pWaveform);
48261     pWaveform->ds.onRead          = ma_waveform__data_source_on_read;
48262     pWaveform->ds.onSeek          = ma_waveform__data_source_on_seek;
48263     pWaveform->ds.onGetDataFormat = ma_waveform__data_source_on_get_data_format;
48264     pWaveform->ds.onGetCursor     = ma_waveform__data_source_on_get_cursor;
48265     pWaveform->ds.onGetLength     = NULL;   /* Intentionally set to NULL since there's no notion of a length in waveforms. */
48266     pWaveform->config             = *pConfig;
48267     pWaveform->advance            = ma_waveform__calculate_advance(pWaveform->config.sampleRate, pWaveform->config.frequency);
48268     pWaveform->time               = 0;
48269
48270     return MA_SUCCESS;
48271 }
48272
48273 MA_API ma_result ma_waveform_set_amplitude(ma_waveform* pWaveform, double amplitude)
48274 {
48275     if (pWaveform == NULL) {
48276         return MA_INVALID_ARGS;
48277     }
48278
48279     pWaveform->config.amplitude = amplitude;
48280     return MA_SUCCESS;
48281 }
48282
48283 MA_API ma_result ma_waveform_set_frequency(ma_waveform* pWaveform, double frequency)
48284 {
48285     if (pWaveform == NULL) {
48286         return MA_INVALID_ARGS;
48287     }
48288
48289     pWaveform->config.frequency = frequency;
48290     ma_waveform__update_advance(pWaveform);
48291
48292     return MA_SUCCESS;
48293 }
48294
48295 MA_API ma_result ma_waveform_set_type(ma_waveform* pWaveform, ma_waveform_type type)
48296 {
48297     if (pWaveform == NULL) {
48298         return MA_INVALID_ARGS;
48299     }
48300
48301     pWaveform->config.type = type;
48302     return MA_SUCCESS;
48303 }
48304
48305 MA_API ma_result ma_waveform_set_sample_rate(ma_waveform* pWaveform, ma_uint32 sampleRate)
48306 {
48307     if (pWaveform == NULL) {
48308         return MA_INVALID_ARGS;
48309     }
48310
48311     pWaveform->config.sampleRate = sampleRate;
48312     ma_waveform__update_advance(pWaveform);
48313
48314     return MA_SUCCESS;
48315 }
48316
48317 static float ma_waveform_sine_f32(double time, double amplitude)
48318 {
48319     return (float)(ma_sin(MA_TAU_D * time) * amplitude);
48320 }
48321
48322 static ma_int16 ma_waveform_sine_s16(double time, double amplitude)
48323 {
48324     return ma_pcm_sample_f32_to_s16(ma_waveform_sine_f32(time, amplitude));
48325 }
48326
48327 static float ma_waveform_square_f32(double time, double amplitude)
48328 {
48329     double f = time - (ma_int64)time;
48330     double r;
48331
48332     if (f < 0.5) {
48333         r =  amplitude;
48334     } else {
48335         r = -amplitude;
48336     }
48337
48338     return (float)r;
48339 }
48340
48341 static ma_int16 ma_waveform_square_s16(double time, double amplitude)
48342 {
48343     return ma_pcm_sample_f32_to_s16(ma_waveform_square_f32(time, amplitude));
48344 }
48345
48346 static float ma_waveform_triangle_f32(double time, double amplitude)
48347 {
48348     double f = time - (ma_int64)time;
48349     double r;
48350
48351     r = 2 * ma_abs(2 * (f - 0.5)) - 1;
48352
48353     return (float)(r * amplitude);
48354 }
48355
48356 static ma_int16 ma_waveform_triangle_s16(double time, double amplitude)
48357 {
48358     return ma_pcm_sample_f32_to_s16(ma_waveform_triangle_f32(time, amplitude));
48359 }
48360
48361 static float ma_waveform_sawtooth_f32(double time, double amplitude)
48362 {
48363     double f = time - (ma_int64)time;
48364     double r;
48365
48366     r = 2 * (f - 0.5);
48367
48368     return (float)(r * amplitude);
48369 }
48370
48371 static ma_int16 ma_waveform_sawtooth_s16(double time, double amplitude)
48372 {
48373     return ma_pcm_sample_f32_to_s16(ma_waveform_sawtooth_f32(time, amplitude));
48374 }
48375
48376 static void ma_waveform_read_pcm_frames__sine(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
48377 {
48378     ma_uint64 iFrame;
48379     ma_uint64 iChannel;
48380     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
48381     ma_uint32 bpf = bps * pWaveform->config.channels;
48382
48383     MA_ASSERT(pWaveform  != NULL);
48384     MA_ASSERT(pFramesOut != NULL);
48385
48386     if (pWaveform->config.format == ma_format_f32) {
48387         float* pFramesOutF32 = (float*)pFramesOut;
48388         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48389             float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.amplitude);
48390             pWaveform->time += pWaveform->advance;
48391
48392             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48393                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
48394             }
48395         }
48396     } else if (pWaveform->config.format == ma_format_s16) {
48397         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
48398         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48399             ma_int16 s = ma_waveform_sine_s16(pWaveform->time, pWaveform->config.amplitude);
48400             pWaveform->time += pWaveform->advance;
48401
48402             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48403                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
48404             }
48405         }
48406     } else {
48407         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48408             float s = ma_waveform_sine_f32(pWaveform->time, pWaveform->config.amplitude);
48409             pWaveform->time += pWaveform->advance;
48410
48411             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48412                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48413             }
48414         }
48415     }
48416 }
48417
48418 static void ma_waveform_read_pcm_frames__square(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
48419 {
48420     ma_uint64 iFrame;
48421     ma_uint64 iChannel;
48422     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
48423     ma_uint32 bpf = bps * pWaveform->config.channels;
48424
48425     MA_ASSERT(pWaveform  != NULL);
48426     MA_ASSERT(pFramesOut != NULL);
48427
48428     if (pWaveform->config.format == ma_format_f32) {
48429         float* pFramesOutF32 = (float*)pFramesOut;
48430         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48431             float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.amplitude);
48432             pWaveform->time += pWaveform->advance;
48433
48434             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48435                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
48436             }
48437         }
48438     } else if (pWaveform->config.format == ma_format_s16) {
48439         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
48440         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48441             ma_int16 s = ma_waveform_square_s16(pWaveform->time, pWaveform->config.amplitude);
48442             pWaveform->time += pWaveform->advance;
48443
48444             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48445                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
48446             }
48447         }
48448     } else {
48449         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48450             float s = ma_waveform_square_f32(pWaveform->time, pWaveform->config.amplitude);
48451             pWaveform->time += pWaveform->advance;
48452
48453             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48454                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48455             }
48456         }
48457     }
48458 }
48459
48460 static void ma_waveform_read_pcm_frames__triangle(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
48461 {
48462     ma_uint64 iFrame;
48463     ma_uint64 iChannel;
48464     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
48465     ma_uint32 bpf = bps * pWaveform->config.channels;
48466
48467     MA_ASSERT(pWaveform  != NULL);
48468     MA_ASSERT(pFramesOut != NULL);
48469
48470     if (pWaveform->config.format == ma_format_f32) {
48471         float* pFramesOutF32 = (float*)pFramesOut;
48472         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48473             float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.amplitude);
48474             pWaveform->time += pWaveform->advance;
48475
48476             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48477                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
48478             }
48479         }
48480     } else if (pWaveform->config.format == ma_format_s16) {
48481         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
48482         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48483             ma_int16 s = ma_waveform_triangle_s16(pWaveform->time, pWaveform->config.amplitude);
48484             pWaveform->time += pWaveform->advance;
48485
48486             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48487                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
48488             }
48489         }
48490     } else {
48491         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48492             float s = ma_waveform_triangle_f32(pWaveform->time, pWaveform->config.amplitude);
48493             pWaveform->time += pWaveform->advance;
48494
48495             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48496                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48497             }
48498         }
48499     }
48500 }
48501
48502 static void ma_waveform_read_pcm_frames__sawtooth(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
48503 {
48504     ma_uint64 iFrame;
48505     ma_uint64 iChannel;
48506     ma_uint32 bps = ma_get_bytes_per_sample(pWaveform->config.format);
48507     ma_uint32 bpf = bps * pWaveform->config.channels;
48508
48509     MA_ASSERT(pWaveform  != NULL);
48510     MA_ASSERT(pFramesOut != NULL);
48511
48512     if (pWaveform->config.format == ma_format_f32) {
48513         float* pFramesOutF32 = (float*)pFramesOut;
48514         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48515             float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.amplitude);
48516             pWaveform->time += pWaveform->advance;
48517
48518             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48519                 pFramesOutF32[iFrame*pWaveform->config.channels + iChannel] = s;
48520             }
48521         }
48522     } else if (pWaveform->config.format == ma_format_s16) {
48523         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
48524         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48525             ma_int16 s = ma_waveform_sawtooth_s16(pWaveform->time, pWaveform->config.amplitude);
48526             pWaveform->time += pWaveform->advance;
48527
48528             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48529                 pFramesOutS16[iFrame*pWaveform->config.channels + iChannel] = s;
48530             }
48531         }
48532     } else {
48533         for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48534             float s = ma_waveform_sawtooth_f32(pWaveform->time, pWaveform->config.amplitude);
48535             pWaveform->time += pWaveform->advance;
48536
48537             for (iChannel = 0; iChannel < pWaveform->config.channels; iChannel += 1) {
48538                 ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pWaveform->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48539             }
48540         }
48541     }
48542 }
48543
48544 MA_API ma_uint64 ma_waveform_read_pcm_frames(ma_waveform* pWaveform, void* pFramesOut, ma_uint64 frameCount)
48545 {
48546     if (pWaveform == NULL) {
48547         return 0;
48548     }
48549
48550     if (pFramesOut != NULL) {
48551         switch (pWaveform->config.type)
48552         {
48553             case ma_waveform_type_sine:
48554             {
48555                 ma_waveform_read_pcm_frames__sine(pWaveform, pFramesOut, frameCount);
48556             } break;
48557
48558             case ma_waveform_type_square:
48559             {
48560                 ma_waveform_read_pcm_frames__square(pWaveform, pFramesOut, frameCount);
48561             } break;
48562
48563             case ma_waveform_type_triangle:
48564             {
48565                 ma_waveform_read_pcm_frames__triangle(pWaveform, pFramesOut, frameCount);
48566             } break;
48567
48568             case ma_waveform_type_sawtooth:
48569             {
48570                 ma_waveform_read_pcm_frames__sawtooth(pWaveform, pFramesOut, frameCount);
48571             } break;
48572
48573             default: return 0;
48574         }
48575     } else {
48576         pWaveform->time += pWaveform->advance * (ma_int64)frameCount; /* Cast to int64 required for VC6. Won't affect anything in practice. */
48577     }
48578
48579     return frameCount;
48580 }
48581
48582 MA_API ma_result ma_waveform_seek_to_pcm_frame(ma_waveform* pWaveform, ma_uint64 frameIndex)
48583 {
48584     if (pWaveform == NULL) {
48585         return MA_INVALID_ARGS;
48586     }
48587
48588     pWaveform->time = pWaveform->advance * (ma_int64)frameIndex;    /* Casting for VC6. Won't be an issue in practice. */
48589
48590     return MA_SUCCESS;
48591 }
48592
48593
48594 MA_API ma_noise_config ma_noise_config_init(ma_format format, ma_uint32 channels, ma_noise_type type, ma_int32 seed, double amplitude)
48595 {
48596     ma_noise_config config;
48597     MA_ZERO_OBJECT(&config);
48598
48599     config.format    = format;
48600     config.channels  = channels;
48601     config.type      = type;
48602     config.seed      = seed;
48603     config.amplitude = amplitude;
48604
48605     if (config.seed == 0) {
48606         config.seed = MA_DEFAULT_LCG_SEED;
48607     }
48608
48609     return config;
48610 }
48611
48612
48613 static ma_result ma_noise__data_source_on_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
48614 {
48615     ma_uint64 framesRead = ma_noise_read_pcm_frames((ma_noise*)pDataSource, pFramesOut, frameCount);
48616
48617     if (pFramesRead != NULL) {
48618         *pFramesRead = framesRead;
48619     }
48620
48621     if (framesRead < frameCount) {
48622         return MA_AT_END;
48623     }
48624
48625     return MA_SUCCESS;
48626 }
48627
48628 static ma_result ma_noise__data_source_on_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
48629 {
48630     /* No-op. Just pretend to be successful. */
48631     (void)pDataSource;
48632     (void)frameIndex;
48633     return MA_SUCCESS;
48634 }
48635
48636 static ma_result ma_noise__data_source_on_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate)
48637 {
48638     ma_noise* pNoise = (ma_noise*)pDataSource;
48639
48640     *pFormat     = pNoise->config.format;
48641     *pChannels   = pNoise->config.channels;
48642     *pSampleRate = 0;   /* There is no notion of sample rate with noise generation. */
48643
48644     return MA_SUCCESS;
48645 }
48646
48647 MA_API ma_result ma_noise_init(const ma_noise_config* pConfig, ma_noise* pNoise)
48648 {
48649     if (pNoise == NULL) {
48650         return MA_INVALID_ARGS;
48651     }
48652
48653     MA_ZERO_OBJECT(pNoise);
48654
48655     if (pConfig == NULL) {
48656         return MA_INVALID_ARGS;
48657     }
48658
48659     if (pConfig->channels < MA_MIN_CHANNELS || pConfig->channels > MA_MAX_CHANNELS) {
48660         return MA_INVALID_ARGS;
48661     }
48662
48663     pNoise->ds.onRead          = ma_noise__data_source_on_read;
48664     pNoise->ds.onSeek          = ma_noise__data_source_on_seek;  /* <-- No-op for noise. */
48665     pNoise->ds.onGetDataFormat = ma_noise__data_source_on_get_data_format;
48666     pNoise->ds.onGetCursor     = NULL;  /* No notion of a cursor for noise. */
48667     pNoise->ds.onGetLength     = NULL;  /* No notion of a length for noise. */
48668     pNoise->config             = *pConfig;
48669     ma_lcg_seed(&pNoise->lcg, pConfig->seed);
48670
48671     if (pNoise->config.type == ma_noise_type_pink) {
48672         ma_uint32 iChannel;
48673         for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
48674             pNoise->state.pink.accumulation[iChannel] = 0;
48675             pNoise->state.pink.counter[iChannel]      = 1;
48676         }
48677     }
48678
48679     if (pNoise->config.type == ma_noise_type_brownian) {
48680         ma_uint32 iChannel;
48681         for (iChannel = 0; iChannel < pConfig->channels; iChannel += 1) {
48682             pNoise->state.brownian.accumulation[iChannel] = 0;
48683         }
48684     }
48685
48686     return MA_SUCCESS;
48687 }
48688
48689 MA_API ma_result ma_noise_set_amplitude(ma_noise* pNoise, double amplitude)
48690 {
48691     if (pNoise == NULL) {
48692         return MA_INVALID_ARGS;
48693     }
48694
48695     pNoise->config.amplitude = amplitude;
48696     return MA_SUCCESS;
48697 }
48698
48699 MA_API ma_result ma_noise_set_seed(ma_noise* pNoise, ma_int32 seed)
48700 {
48701     if (pNoise == NULL) {
48702         return MA_INVALID_ARGS;
48703     }
48704
48705     pNoise->lcg.state = seed;
48706     return MA_SUCCESS;
48707 }
48708
48709
48710 MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type)
48711 {
48712     if (pNoise == NULL) {
48713         return MA_INVALID_ARGS;
48714     }
48715
48716     pNoise->config.type = type;
48717     return MA_SUCCESS;
48718 }
48719
48720 static MA_INLINE float ma_noise_f32_white(ma_noise* pNoise)
48721 {
48722     return (float)(ma_lcg_rand_f64(&pNoise->lcg) * pNoise->config.amplitude);
48723 }
48724
48725 static MA_INLINE ma_int16 ma_noise_s16_white(ma_noise* pNoise)
48726 {
48727     return ma_pcm_sample_f32_to_s16(ma_noise_f32_white(pNoise));
48728 }
48729
48730 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__white(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
48731 {
48732     ma_uint64 iFrame;
48733     ma_uint32 iChannel;
48734     const ma_uint32 channels = pNoise->config.channels;
48735     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
48736
48737     if (pNoise->config.format == ma_format_f32) {
48738         float* pFramesOutF32 = (float*)pFramesOut;
48739         if (pNoise->config.duplicateChannels) {
48740             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48741                 float s = ma_noise_f32_white(pNoise);
48742                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48743                     pFramesOutF32[iFrame*channels + iChannel] = s;
48744                 }
48745             }
48746         } else {
48747             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48748                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48749                     pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_white(pNoise);
48750                 }
48751             }
48752         }
48753     } else if (pNoise->config.format == ma_format_s16) {
48754         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
48755         if (pNoise->config.duplicateChannels) {
48756             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48757                 ma_int16 s = ma_noise_s16_white(pNoise);
48758                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48759                     pFramesOutS16[iFrame*channels + iChannel] = s;
48760                 }
48761             }
48762         } else {
48763             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48764                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48765                     pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_white(pNoise);
48766                 }
48767             }
48768         }
48769     } else {
48770         const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format);
48771         const ma_uint32 bpf = bps * channels;
48772
48773         if (pNoise->config.duplicateChannels) {
48774             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48775                 float s = ma_noise_f32_white(pNoise);
48776                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48777                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48778                 }
48779             }
48780         } else {
48781             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48782                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48783                     float s = ma_noise_f32_white(pNoise);
48784                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48785                 }
48786             }
48787         }
48788     }
48789
48790     return frameCount;
48791 }
48792
48793
48794 static MA_INLINE unsigned int ma_tzcnt32(unsigned int x)
48795 {
48796     unsigned int n;
48797
48798     /* Special case for odd numbers since they should happen about half the time. */
48799     if (x & 0x1)  {
48800         return 0;
48801     }
48802
48803     if (x == 0) {
48804         return sizeof(x) << 3;
48805     }
48806
48807     n = 1;
48808     if ((x & 0x0000FFFF) == 0) { x >>= 16; n += 16; }
48809     if ((x & 0x000000FF) == 0) { x >>=  8; n +=  8; }
48810     if ((x & 0x0000000F) == 0) { x >>=  4; n +=  4; }
48811     if ((x & 0x00000003) == 0) { x >>=  2; n +=  2; }
48812     n -= x & 0x00000001;
48813
48814     return n;
48815 }
48816
48817 /*
48818 Pink noise generation based on Tonic (public domain) with modifications. https://github.com/TonicAudio/Tonic/blob/master/src/Tonic/Noise.h
48819
48820 This is basically _the_ reference for pink noise from what I've found: http://www.firstpr.com.au/dsp/pink-noise/
48821 */
48822 static MA_INLINE float ma_noise_f32_pink(ma_noise* pNoise, ma_uint32 iChannel)
48823 {
48824     double result;
48825     double binPrev;
48826     double binNext;
48827     unsigned int ibin;
48828
48829     ibin = ma_tzcnt32(pNoise->state.pink.counter[iChannel]) & (ma_countof(pNoise->state.pink.bin[0]) - 1);
48830
48831     binPrev = pNoise->state.pink.bin[iChannel][ibin];
48832     binNext = ma_lcg_rand_f64(&pNoise->lcg);
48833     pNoise->state.pink.bin[iChannel][ibin] = binNext;
48834
48835     pNoise->state.pink.accumulation[iChannel] += (binNext - binPrev);
48836     pNoise->state.pink.counter[iChannel]      += 1;
48837
48838     result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.pink.accumulation[iChannel]);
48839     result /= 10;
48840
48841     return (float)(result * pNoise->config.amplitude);
48842 }
48843
48844 static MA_INLINE ma_int16 ma_noise_s16_pink(ma_noise* pNoise, ma_uint32 iChannel)
48845 {
48846     return ma_pcm_sample_f32_to_s16(ma_noise_f32_pink(pNoise, iChannel));
48847 }
48848
48849 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__pink(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
48850 {
48851     ma_uint64 iFrame;
48852     ma_uint32 iChannel;
48853     const ma_uint32 channels = pNoise->config.channels;
48854     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
48855
48856     if (pNoise->config.format == ma_format_f32) {
48857         float* pFramesOutF32 = (float*)pFramesOut;
48858         if (pNoise->config.duplicateChannels) {
48859             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48860                 float s = ma_noise_f32_pink(pNoise, 0);
48861                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48862                     pFramesOutF32[iFrame*channels + iChannel] = s;
48863                 }
48864             }
48865         } else {
48866             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48867                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48868                     pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_pink(pNoise, iChannel);
48869                 }
48870             }
48871         }
48872     } else if (pNoise->config.format == ma_format_s16) {
48873         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
48874         if (pNoise->config.duplicateChannels) {
48875             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48876                 ma_int16 s = ma_noise_s16_pink(pNoise, 0);
48877                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48878                     pFramesOutS16[iFrame*channels + iChannel] = s;
48879                 }
48880             }
48881         } else {
48882             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48883                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48884                     pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_pink(pNoise, iChannel);
48885                 }
48886             }
48887         }
48888     } else {
48889         const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format);
48890         const ma_uint32 bpf = bps * channels;
48891
48892         if (pNoise->config.duplicateChannels) {
48893             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48894                 float s = ma_noise_f32_pink(pNoise, 0);
48895                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48896                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48897                 }
48898             }
48899         } else {
48900             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48901                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48902                     float s = ma_noise_f32_pink(pNoise, iChannel);
48903                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48904                 }
48905             }
48906         }
48907     }
48908
48909     return frameCount;
48910 }
48911
48912
48913 static MA_INLINE float ma_noise_f32_brownian(ma_noise* pNoise, ma_uint32 iChannel)
48914 {
48915     double result;
48916
48917     result = (ma_lcg_rand_f64(&pNoise->lcg) + pNoise->state.brownian.accumulation[iChannel]);
48918     result /= 1.005; /* Don't escape the -1..1 range on average. */
48919
48920     pNoise->state.brownian.accumulation[iChannel] = result;
48921     result /= 20;
48922
48923     return (float)(result * pNoise->config.amplitude);
48924 }
48925
48926 static MA_INLINE ma_int16 ma_noise_s16_brownian(ma_noise* pNoise, ma_uint32 iChannel)
48927 {
48928     return ma_pcm_sample_f32_to_s16(ma_noise_f32_brownian(pNoise, iChannel));
48929 }
48930
48931 static MA_INLINE ma_uint64 ma_noise_read_pcm_frames__brownian(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
48932 {
48933     ma_uint64 iFrame;
48934     ma_uint32 iChannel;
48935     const ma_uint32 channels = pNoise->config.channels;
48936     MA_ASSUME(channels >= MA_MIN_CHANNELS && channels <= MA_MAX_CHANNELS);
48937
48938     if (pNoise->config.format == ma_format_f32) {
48939         float* pFramesOutF32 = (float*)pFramesOut;
48940         if (pNoise->config.duplicateChannels) {
48941             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48942                 float s = ma_noise_f32_brownian(pNoise, 0);
48943                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48944                     pFramesOutF32[iFrame*channels + iChannel] = s;
48945                 }
48946             }
48947         } else {
48948             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48949                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48950                     pFramesOutF32[iFrame*channels + iChannel] = ma_noise_f32_brownian(pNoise, iChannel);
48951                 }
48952             }
48953         }
48954     } else if (pNoise->config.format == ma_format_s16) {
48955         ma_int16* pFramesOutS16 = (ma_int16*)pFramesOut;
48956         if (pNoise->config.duplicateChannels) {
48957             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48958                 ma_int16 s = ma_noise_s16_brownian(pNoise, 0);
48959                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48960                     pFramesOutS16[iFrame*channels + iChannel] = s;
48961                 }
48962             }
48963         } else {
48964             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48965                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48966                     pFramesOutS16[iFrame*channels + iChannel] = ma_noise_s16_brownian(pNoise, iChannel);
48967                 }
48968             }
48969         }
48970     } else {
48971         const ma_uint32 bps = ma_get_bytes_per_sample(pNoise->config.format);
48972         const ma_uint32 bpf = bps * channels;
48973
48974         if (pNoise->config.duplicateChannels) {
48975             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48976                 float s = ma_noise_f32_brownian(pNoise, 0);
48977                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48978                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48979                 }
48980             }
48981         } else {
48982             for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
48983                 for (iChannel = 0; iChannel < channels; iChannel += 1) {
48984                     float s = ma_noise_f32_brownian(pNoise, iChannel);
48985                     ma_pcm_convert(ma_offset_ptr(pFramesOut, iFrame*bpf + iChannel*bps), pNoise->config.format, &s, ma_format_f32, 1, ma_dither_mode_none);
48986                 }
48987             }
48988         }
48989     }
48990
48991     return frameCount;
48992 }
48993
48994 MA_API ma_uint64 ma_noise_read_pcm_frames(ma_noise* pNoise, void* pFramesOut, ma_uint64 frameCount)
48995 {
48996     if (pNoise == NULL) {
48997         return 0;
48998     }
48999
49000     /* 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. */
49001     if (pFramesOut == NULL) {
49002         return frameCount;
49003     }
49004
49005     if (pNoise->config.type == ma_noise_type_white) {
49006         return ma_noise_read_pcm_frames__white(pNoise, pFramesOut, frameCount);
49007     }
49008
49009     if (pNoise->config.type == ma_noise_type_pink) {
49010         return ma_noise_read_pcm_frames__pink(pNoise, pFramesOut, frameCount);
49011     }
49012
49013     if (pNoise->config.type == ma_noise_type_brownian) {
49014         return ma_noise_read_pcm_frames__brownian(pNoise, pFramesOut, frameCount);
49015     }
49016
49017     /* Should never get here. */
49018     MA_ASSERT(MA_FALSE);
49019     return 0;
49020 }
49021 #endif /* MA_NO_GENERATION */
49022
49023
49024
49025 /**************************************************************************************************************************************************************
49026 ***************************************************************************************************************************************************************
49027
49028 Auto Generated
49029 ==============
49030 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
49031 code below please report the bug to the respective repository for the relevant project (probably dr_libs).
49032
49033 ***************************************************************************************************************************************************************
49034 **************************************************************************************************************************************************************/
49035 #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING))
49036 #if !defined(DR_WAV_IMPLEMENTATION) && !defined(DRWAV_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
49037 /* dr_wav_c begin */
49038 #ifndef dr_wav_c
49039 #define dr_wav_c
49040 #include <stdlib.h>
49041 #include <string.h>
49042 #include <limits.h>
49043 #ifndef DR_WAV_NO_STDIO
49044 #include <stdio.h>
49045 #include <wchar.h>
49046 #endif
49047 #ifndef DRWAV_ASSERT
49048 #include <assert.h>
49049 #define DRWAV_ASSERT(expression)           assert(expression)
49050 #endif
49051 #ifndef DRWAV_MALLOC
49052 #define DRWAV_MALLOC(sz)                   malloc((sz))
49053 #endif
49054 #ifndef DRWAV_REALLOC
49055 #define DRWAV_REALLOC(p, sz)               realloc((p), (sz))
49056 #endif
49057 #ifndef DRWAV_FREE
49058 #define DRWAV_FREE(p)                      free((p))
49059 #endif
49060 #ifndef DRWAV_COPY_MEMORY
49061 #define DRWAV_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
49062 #endif
49063 #ifndef DRWAV_ZERO_MEMORY
49064 #define DRWAV_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
49065 #endif
49066 #ifndef DRWAV_ZERO_OBJECT
49067 #define DRWAV_ZERO_OBJECT(p)               DRWAV_ZERO_MEMORY((p), sizeof(*p))
49068 #endif
49069 #define drwav_countof(x)                   (sizeof(x) / sizeof(x[0]))
49070 #define drwav_align(x, a)                  ((((x) + (a) - 1) / (a)) * (a))
49071 #define drwav_min(a, b)                    (((a) < (b)) ? (a) : (b))
49072 #define drwav_max(a, b)                    (((a) > (b)) ? (a) : (b))
49073 #define drwav_clamp(x, lo, hi)             (drwav_max((lo), drwav_min((hi), (x))))
49074 #define DRWAV_MAX_SIMD_VECTOR_SIZE         64
49075 #if defined(__x86_64__) || defined(_M_X64)
49076     #define DRWAV_X64
49077 #elif defined(__i386) || defined(_M_IX86)
49078     #define DRWAV_X86
49079 #elif defined(__arm__) || defined(_M_ARM)
49080     #define DRWAV_ARM
49081 #endif
49082 #ifdef _MSC_VER
49083     #define DRWAV_INLINE __forceinline
49084 #elif defined(__GNUC__)
49085     #if defined(__STRICT_ANSI__)
49086         #define DRWAV_INLINE __inline__ __attribute__((always_inline))
49087     #else
49088         #define DRWAV_INLINE inline __attribute__((always_inline))
49089     #endif
49090 #elif defined(__WATCOMC__)
49091     #define DRWAV_INLINE __inline
49092 #else
49093     #define DRWAV_INLINE
49094 #endif
49095 #if defined(SIZE_MAX)
49096     #define DRWAV_SIZE_MAX  SIZE_MAX
49097 #else
49098     #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
49099         #define DRWAV_SIZE_MAX  ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
49100     #else
49101         #define DRWAV_SIZE_MAX  0xFFFFFFFF
49102     #endif
49103 #endif
49104 #if defined(_MSC_VER) && _MSC_VER >= 1400
49105     #define DRWAV_HAS_BYTESWAP16_INTRINSIC
49106     #define DRWAV_HAS_BYTESWAP32_INTRINSIC
49107     #define DRWAV_HAS_BYTESWAP64_INTRINSIC
49108 #elif defined(__clang__)
49109     #if defined(__has_builtin)
49110         #if __has_builtin(__builtin_bswap16)
49111             #define DRWAV_HAS_BYTESWAP16_INTRINSIC
49112         #endif
49113         #if __has_builtin(__builtin_bswap32)
49114             #define DRWAV_HAS_BYTESWAP32_INTRINSIC
49115         #endif
49116         #if __has_builtin(__builtin_bswap64)
49117             #define DRWAV_HAS_BYTESWAP64_INTRINSIC
49118         #endif
49119     #endif
49120 #elif defined(__GNUC__)
49121     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
49122         #define DRWAV_HAS_BYTESWAP32_INTRINSIC
49123         #define DRWAV_HAS_BYTESWAP64_INTRINSIC
49124     #endif
49125     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
49126         #define DRWAV_HAS_BYTESWAP16_INTRINSIC
49127     #endif
49128 #endif
49129 DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision)
49130 {
49131     if (pMajor) {
49132         *pMajor = DRWAV_VERSION_MAJOR;
49133     }
49134     if (pMinor) {
49135         *pMinor = DRWAV_VERSION_MINOR;
49136     }
49137     if (pRevision) {
49138         *pRevision = DRWAV_VERSION_REVISION;
49139     }
49140 }
49141 DRWAV_API const char* drwav_version_string(void)
49142 {
49143     return DRWAV_VERSION_STRING;
49144 }
49145 #ifndef DRWAV_MAX_SAMPLE_RATE
49146 #define DRWAV_MAX_SAMPLE_RATE       384000
49147 #endif
49148 #ifndef DRWAV_MAX_CHANNELS
49149 #define DRWAV_MAX_CHANNELS          256
49150 #endif
49151 #ifndef DRWAV_MAX_BITS_PER_SAMPLE
49152 #define DRWAV_MAX_BITS_PER_SAMPLE   64
49153 #endif
49154 static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00};
49155 static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
49156 static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
49157 static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
49158 static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
49159 static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};
49160 static DRWAV_INLINE int drwav__is_little_endian(void)
49161 {
49162 #if defined(DRWAV_X86) || defined(DRWAV_X64)
49163     return DRWAV_TRUE;
49164 #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
49165     return DRWAV_TRUE;
49166 #else
49167     int n = 1;
49168     return (*(char*)&n) == 1;
49169 #endif
49170 }
49171 static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid)
49172 {
49173     int i;
49174     for (i = 0; i < 16; ++i) {
49175         guid[i] = data[i];
49176     }
49177 }
49178 static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
49179 {
49180 #ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC
49181     #if defined(_MSC_VER)
49182         return _byteswap_ushort(n);
49183     #elif defined(__GNUC__) || defined(__clang__)
49184         return __builtin_bswap16(n);
49185     #else
49186         #error "This compiler does not support the byte swap intrinsic."
49187     #endif
49188 #else
49189     return ((n & 0xFF00) >> 8) |
49190            ((n & 0x00FF) << 8);
49191 #endif
49192 }
49193 static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
49194 {
49195 #ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC
49196     #if defined(_MSC_VER)
49197         return _byteswap_ulong(n);
49198     #elif defined(__GNUC__) || defined(__clang__)
49199         #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_64BIT)
49200             drwav_uint32 r;
49201             __asm__ __volatile__ (
49202             #if defined(DRWAV_64BIT)
49203                 "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)
49204             #else
49205                 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
49206             #endif
49207             );
49208             return r;
49209         #else
49210             return __builtin_bswap32(n);
49211         #endif
49212     #else
49213         #error "This compiler does not support the byte swap intrinsic."
49214     #endif
49215 #else
49216     return ((n & 0xFF000000) >> 24) |
49217            ((n & 0x00FF0000) >>  8) |
49218            ((n & 0x0000FF00) <<  8) |
49219            ((n & 0x000000FF) << 24);
49220 #endif
49221 }
49222 static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
49223 {
49224 #ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC
49225     #if defined(_MSC_VER)
49226         return _byteswap_uint64(n);
49227     #elif defined(__GNUC__) || defined(__clang__)
49228         return __builtin_bswap64(n);
49229     #else
49230         #error "This compiler does not support the byte swap intrinsic."
49231     #endif
49232 #else
49233     return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
49234            ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
49235            ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
49236            ((n & ((drwav_uint64)0x000000FF << 32)) >>  8) |
49237            ((n & ((drwav_uint64)0xFF000000      )) <<  8) |
49238            ((n & ((drwav_uint64)0x00FF0000      )) << 24) |
49239            ((n & ((drwav_uint64)0x0000FF00      )) << 40) |
49240            ((n & ((drwav_uint64)0x000000FF      )) << 56);
49241 #endif
49242 }
49243 static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
49244 {
49245     return (drwav_int16)drwav__bswap16((drwav_uint16)n);
49246 }
49247 static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
49248 {
49249     drwav_uint64 iSample;
49250     for (iSample = 0; iSample < sampleCount; iSample += 1) {
49251         pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
49252     }
49253 }
49254 static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
49255 {
49256     drwav_uint8 t;
49257     t = p[0];
49258     p[0] = p[2];
49259     p[2] = t;
49260 }
49261 static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
49262 {
49263     drwav_uint64 iSample;
49264     for (iSample = 0; iSample < sampleCount; iSample += 1) {
49265         drwav_uint8* pSample = pSamples + (iSample*3);
49266         drwav__bswap_s24(pSample);
49267     }
49268 }
49269 static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
49270 {
49271     return (drwav_int32)drwav__bswap32((drwav_uint32)n);
49272 }
49273 static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
49274 {
49275     drwav_uint64 iSample;
49276     for (iSample = 0; iSample < sampleCount; iSample += 1) {
49277         pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
49278     }
49279 }
49280 static DRWAV_INLINE float drwav__bswap_f32(float n)
49281 {
49282     union {
49283         drwav_uint32 i;
49284         float f;
49285     } x;
49286     x.f = n;
49287     x.i = drwav__bswap32(x.i);
49288     return x.f;
49289 }
49290 static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
49291 {
49292     drwav_uint64 iSample;
49293     for (iSample = 0; iSample < sampleCount; iSample += 1) {
49294         pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
49295     }
49296 }
49297 static DRWAV_INLINE double drwav__bswap_f64(double n)
49298 {
49299     union {
49300         drwav_uint64 i;
49301         double f;
49302     } x;
49303     x.f = n;
49304     x.i = drwav__bswap64(x.i);
49305     return x.f;
49306 }
49307 static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount)
49308 {
49309     drwav_uint64 iSample;
49310     for (iSample = 0; iSample < sampleCount; iSample += 1) {
49311         pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]);
49312     }
49313 }
49314 static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
49315 {
49316     switch (bytesPerSample)
49317     {
49318         case 2:
49319         {
49320             drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
49321         } break;
49322         case 3:
49323         {
49324             drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
49325         } break;
49326         case 4:
49327         {
49328             drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
49329         } break;
49330         default:
49331         {
49332             DRWAV_ASSERT(DRWAV_FALSE);
49333         } break;
49334     }
49335 }
49336 static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
49337 {
49338     switch (bytesPerSample)
49339     {
49340     #if 0
49341         case 2:
49342         {
49343             drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount);
49344         } break;
49345     #endif
49346         case 4:
49347         {
49348             drwav__bswap_samples_f32((float*)pSamples, sampleCount);
49349         } break;
49350         case 8:
49351         {
49352             drwav__bswap_samples_f64((double*)pSamples, sampleCount);
49353         } break;
49354         default:
49355         {
49356             DRWAV_ASSERT(DRWAV_FALSE);
49357         } break;
49358     }
49359 }
49360 static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format)
49361 {
49362     switch (format)
49363     {
49364         case DR_WAVE_FORMAT_PCM:
49365         {
49366             drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample);
49367         } break;
49368         case DR_WAVE_FORMAT_IEEE_FLOAT:
49369         {
49370             drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample);
49371         } break;
49372         case DR_WAVE_FORMAT_ALAW:
49373         case DR_WAVE_FORMAT_MULAW:
49374         {
49375             drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
49376         } break;
49377         case DR_WAVE_FORMAT_ADPCM:
49378         case DR_WAVE_FORMAT_DVI_ADPCM:
49379         default:
49380         {
49381             DRWAV_ASSERT(DRWAV_FALSE);
49382         } break;
49383     }
49384 }
49385 DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData)
49386 {
49387     (void)pUserData;
49388     return DRWAV_MALLOC(sz);
49389 }
49390 DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
49391 {
49392     (void)pUserData;
49393     return DRWAV_REALLOC(p, sz);
49394 }
49395 DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData)
49396 {
49397     (void)pUserData;
49398     DRWAV_FREE(p);
49399 }
49400 DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
49401 {
49402     if (pAllocationCallbacks == NULL) {
49403         return NULL;
49404     }
49405     if (pAllocationCallbacks->onMalloc != NULL) {
49406         return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
49407     }
49408     if (pAllocationCallbacks->onRealloc != NULL) {
49409         return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
49410     }
49411     return NULL;
49412 }
49413 DRWAV_PRIVATE void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
49414 {
49415     if (pAllocationCallbacks == NULL) {
49416         return NULL;
49417     }
49418     if (pAllocationCallbacks->onRealloc != NULL) {
49419         return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
49420     }
49421     if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
49422         void* p2;
49423         p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
49424         if (p2 == NULL) {
49425             return NULL;
49426         }
49427         if (p != NULL) {
49428             DRWAV_COPY_MEMORY(p2, p, szOld);
49429             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
49430         }
49431         return p2;
49432     }
49433     return NULL;
49434 }
49435 DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
49436 {
49437     if (p == NULL || pAllocationCallbacks == NULL) {
49438         return;
49439     }
49440     if (pAllocationCallbacks->onFree != NULL) {
49441         pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
49442     }
49443 }
49444 DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
49445 {
49446     if (pAllocationCallbacks != NULL) {
49447         return *pAllocationCallbacks;
49448     } else {
49449         drwav_allocation_callbacks allocationCallbacks;
49450         allocationCallbacks.pUserData = NULL;
49451         allocationCallbacks.onMalloc  = drwav__malloc_default;
49452         allocationCallbacks.onRealloc = drwav__realloc_default;
49453         allocationCallbacks.onFree    = drwav__free_default;
49454         return allocationCallbacks;
49455     }
49456 }
49457 static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
49458 {
49459     return
49460         formatTag == DR_WAVE_FORMAT_ADPCM ||
49461         formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
49462 }
49463 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
49464 {
49465     return (unsigned int)(chunkSize % 2);
49466 }
49467 DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
49468 {
49469     return (unsigned int)(chunkSize % 8);
49470 }
49471 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
49472 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
49473 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
49474 DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
49475 {
49476     if (container == drwav_container_riff || container == drwav_container_rf64) {
49477         drwav_uint8 sizeInBytes[4];
49478         if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
49479             return DRWAV_AT_END;
49480         }
49481         if (onRead(pUserData, sizeInBytes, 4) != 4) {
49482             return DRWAV_INVALID_FILE;
49483         }
49484         pHeaderOut->sizeInBytes = drwav_bytes_to_u32(sizeInBytes);
49485         pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
49486         *pRunningBytesReadOut += 8;
49487     } else {
49488         drwav_uint8 sizeInBytes[8];
49489         if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
49490             return DRWAV_AT_END;
49491         }
49492         if (onRead(pUserData, sizeInBytes, 8) != 8) {
49493             return DRWAV_INVALID_FILE;
49494         }
49495         pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24;
49496         pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
49497         *pRunningBytesReadOut += 24;
49498     }
49499     return DRWAV_SUCCESS;
49500 }
49501 DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
49502 {
49503     drwav_uint64 bytesRemainingToSeek = offset;
49504     while (bytesRemainingToSeek > 0) {
49505         if (bytesRemainingToSeek > 0x7FFFFFFF) {
49506             if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
49507                 return DRWAV_FALSE;
49508             }
49509             bytesRemainingToSeek -= 0x7FFFFFFF;
49510         } else {
49511             if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
49512                 return DRWAV_FALSE;
49513             }
49514             bytesRemainingToSeek = 0;
49515         }
49516     }
49517     return DRWAV_TRUE;
49518 }
49519 DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
49520 {
49521     if (offset <= 0x7FFFFFFF) {
49522         return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
49523     }
49524     if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
49525         return DRWAV_FALSE;
49526     }
49527     offset -= 0x7FFFFFFF;
49528     for (;;) {
49529         if (offset <= 0x7FFFFFFF) {
49530             return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
49531         }
49532         if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
49533             return DRWAV_FALSE;
49534         }
49535         offset -= 0x7FFFFFFF;
49536     }
49537 }
49538 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)
49539 {
49540     drwav_chunk_header header;
49541     drwav_uint8 fmt[16];
49542     if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
49543         return DRWAV_FALSE;
49544     }
49545     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))) {
49546         if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
49547             return DRWAV_FALSE;
49548         }
49549         *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
49550         if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
49551             return DRWAV_FALSE;
49552         }
49553     }
49554     if (container == drwav_container_riff || container == drwav_container_rf64) {
49555         if (!drwav_fourcc_equal(header.id.fourcc, "fmt ")) {
49556             return DRWAV_FALSE;
49557         }
49558     } else {
49559         if (!drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
49560             return DRWAV_FALSE;
49561         }
49562     }
49563     if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
49564         return DRWAV_FALSE;
49565     }
49566     *pRunningBytesReadOut += sizeof(fmt);
49567     fmtOut->formatTag      = drwav_bytes_to_u16(fmt + 0);
49568     fmtOut->channels       = drwav_bytes_to_u16(fmt + 2);
49569     fmtOut->sampleRate     = drwav_bytes_to_u32(fmt + 4);
49570     fmtOut->avgBytesPerSec = drwav_bytes_to_u32(fmt + 8);
49571     fmtOut->blockAlign     = drwav_bytes_to_u16(fmt + 12);
49572     fmtOut->bitsPerSample  = drwav_bytes_to_u16(fmt + 14);
49573     fmtOut->extendedSize       = 0;
49574     fmtOut->validBitsPerSample = 0;
49575     fmtOut->channelMask        = 0;
49576     memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
49577     if (header.sizeInBytes > 16) {
49578         drwav_uint8 fmt_cbSize[2];
49579         int bytesReadSoFar = 0;
49580         if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
49581             return DRWAV_FALSE;
49582         }
49583         *pRunningBytesReadOut += sizeof(fmt_cbSize);
49584         bytesReadSoFar = 18;
49585         fmtOut->extendedSize = drwav_bytes_to_u16(fmt_cbSize);
49586         if (fmtOut->extendedSize > 0) {
49587             if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
49588                 if (fmtOut->extendedSize != 22) {
49589                     return DRWAV_FALSE;
49590                 }
49591             }
49592             if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
49593                 drwav_uint8 fmtext[22];
49594                 if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) {
49595                     return DRWAV_FALSE;
49596                 }
49597                 fmtOut->validBitsPerSample = drwav_bytes_to_u16(fmtext + 0);
49598                 fmtOut->channelMask        = drwav_bytes_to_u32(fmtext + 2);
49599                 drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat);
49600             } else {
49601                 if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) {
49602                     return DRWAV_FALSE;
49603                 }
49604             }
49605             *pRunningBytesReadOut += fmtOut->extendedSize;
49606             bytesReadSoFar += fmtOut->extendedSize;
49607         }
49608         if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
49609             return DRWAV_FALSE;
49610         }
49611         *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
49612     }
49613     if (header.paddingSize > 0) {
49614         if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
49615             return DRWAV_FALSE;
49616         }
49617         *pRunningBytesReadOut += header.paddingSize;
49618     }
49619     return DRWAV_TRUE;
49620 }
49621 DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
49622 {
49623     size_t bytesRead;
49624     DRWAV_ASSERT(onRead != NULL);
49625     DRWAV_ASSERT(pCursor != NULL);
49626     bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
49627     *pCursor += bytesRead;
49628     return bytesRead;
49629 }
49630 #if 0
49631 DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
49632 {
49633     DRWAV_ASSERT(onSeek != NULL);
49634     DRWAV_ASSERT(pCursor != NULL);
49635     if (!onSeek(pUserData, offset, origin)) {
49636         return DRWAV_FALSE;
49637     }
49638     if (origin == drwav_seek_origin_start) {
49639         *pCursor = offset;
49640     } else {
49641         *pCursor += offset;
49642     }
49643     return DRWAV_TRUE;
49644 }
49645 #endif
49646 DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
49647 {
49648     if ((pWav->bitsPerSample & 0x7) == 0) {
49649         return (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
49650     } else {
49651         return pWav->fmt.blockAlign;
49652     }
49653 }
49654 DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
49655 {
49656     if (pFMT == NULL) {
49657         return 0;
49658     }
49659     if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
49660         return pFMT->formatTag;
49661     } else {
49662         return drwav_bytes_to_u16(pFMT->subFormat);
49663     }
49664 }
49665 DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
49666 {
49667     if (pWav == NULL || onRead == NULL || onSeek == NULL) {
49668         return DRWAV_FALSE;
49669     }
49670     DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
49671     pWav->onRead    = onRead;
49672     pWav->onSeek    = onSeek;
49673     pWav->pUserData = pReadSeekUserData;
49674     pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
49675     if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
49676         return DRWAV_FALSE;
49677     }
49678     return DRWAV_TRUE;
49679 }
49680 DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
49681 {
49682     drwav_uint64 cursor;
49683     drwav_bool32 sequential;
49684     drwav_uint8 riff[4];
49685     drwav_fmt fmt;
49686     unsigned short translatedFormatTag;
49687     drwav_bool32 foundDataChunk;
49688     drwav_uint64 dataChunkSize = 0;
49689     drwav_uint64 sampleCountFromFactChunk = 0;
49690     drwav_uint64 chunkSize;
49691     cursor = 0;
49692     sequential = (flags & DRWAV_SEQUENTIAL) != 0;
49693     if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
49694         return DRWAV_FALSE;
49695     }
49696     if (drwav_fourcc_equal(riff, "RIFF")) {
49697         pWav->container = drwav_container_riff;
49698     } else if (drwav_fourcc_equal(riff, "riff")) {
49699         int i;
49700         drwav_uint8 riff2[12];
49701         pWav->container = drwav_container_w64;
49702         if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
49703             return DRWAV_FALSE;
49704         }
49705         for (i = 0; i < 12; ++i) {
49706             if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
49707                 return DRWAV_FALSE;
49708             }
49709         }
49710     } else if (drwav_fourcc_equal(riff, "RF64")) {
49711         pWav->container = drwav_container_rf64;
49712     } else {
49713         return DRWAV_FALSE;
49714     }
49715     if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
49716         drwav_uint8 chunkSizeBytes[4];
49717         drwav_uint8 wave[4];
49718         if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
49719             return DRWAV_FALSE;
49720         }
49721         if (pWav->container == drwav_container_riff) {
49722             if (drwav_bytes_to_u32(chunkSizeBytes) < 36) {
49723                 return DRWAV_FALSE;
49724             }
49725         } else {
49726             if (drwav_bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) {
49727                 return DRWAV_FALSE;
49728             }
49729         }
49730         if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
49731             return DRWAV_FALSE;
49732         }
49733         if (!drwav_fourcc_equal(wave, "WAVE")) {
49734             return DRWAV_FALSE;
49735         }
49736     } else {
49737         drwav_uint8 chunkSizeBytes[8];
49738         drwav_uint8 wave[16];
49739         if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
49740             return DRWAV_FALSE;
49741         }
49742         if (drwav_bytes_to_u64(chunkSizeBytes) < 80) {
49743             return DRWAV_FALSE;
49744         }
49745         if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
49746             return DRWAV_FALSE;
49747         }
49748         if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) {
49749             return DRWAV_FALSE;
49750         }
49751     }
49752     if (pWav->container == drwav_container_rf64) {
49753         drwav_uint8 sizeBytes[8];
49754         drwav_uint64 bytesRemainingInChunk;
49755         drwav_chunk_header header;
49756         drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
49757         if (result != DRWAV_SUCCESS) {
49758             return DRWAV_FALSE;
49759         }
49760         if (!drwav_fourcc_equal(header.id.fourcc, "ds64")) {
49761             return DRWAV_FALSE;
49762         }
49763         bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
49764         if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
49765             return DRWAV_FALSE;
49766         }
49767         bytesRemainingInChunk -= 8;
49768         cursor += 8;
49769         if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
49770             return DRWAV_FALSE;
49771         }
49772         bytesRemainingInChunk -= 8;
49773         dataChunkSize = drwav_bytes_to_u64(sizeBytes);
49774         if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
49775             return DRWAV_FALSE;
49776         }
49777         bytesRemainingInChunk -= 8;
49778         sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes);
49779         if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
49780             return DRWAV_FALSE;
49781         }
49782         cursor += bytesRemainingInChunk;
49783     }
49784     if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
49785         return DRWAV_FALSE;
49786     }
49787     if ((fmt.sampleRate    == 0 || fmt.sampleRate    > DRWAV_MAX_SAMPLE_RATE)     ||
49788         (fmt.channels      == 0 || fmt.channels      > DRWAV_MAX_CHANNELS)        ||
49789         (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
49790         fmt.blockAlign == 0) {
49791         return DRWAV_FALSE;
49792     }
49793     translatedFormatTag = fmt.formatTag;
49794     if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
49795         translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0);
49796     }
49797     foundDataChunk = DRWAV_FALSE;
49798     for (;;)
49799     {
49800         drwav_chunk_header header;
49801         drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
49802         if (result != DRWAV_SUCCESS) {
49803             if (!foundDataChunk) {
49804                 return DRWAV_FALSE;
49805             } else {
49806                 break;
49807             }
49808         }
49809         if (!sequential && onChunk != NULL) {
49810             drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
49811             if (callbackBytesRead > 0) {
49812                 if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) {
49813                     return DRWAV_FALSE;
49814                 }
49815             }
49816         }
49817         if (!foundDataChunk) {
49818             pWav->dataChunkDataPos = cursor;
49819         }
49820         chunkSize = header.sizeInBytes;
49821         if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
49822             if (drwav_fourcc_equal(header.id.fourcc, "data")) {
49823                 foundDataChunk = DRWAV_TRUE;
49824                 if (pWav->container != drwav_container_rf64) {
49825                     dataChunkSize = chunkSize;
49826                 }
49827             }
49828         } else {
49829             if (drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
49830                 foundDataChunk = DRWAV_TRUE;
49831                 dataChunkSize = chunkSize;
49832             }
49833         }
49834         if (foundDataChunk && sequential) {
49835             break;
49836         }
49837         if (pWav->container == drwav_container_riff) {
49838             if (drwav_fourcc_equal(header.id.fourcc, "fact")) {
49839                 drwav_uint32 sampleCount;
49840                 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
49841                     return DRWAV_FALSE;
49842                 }
49843                 chunkSize -= 4;
49844                 if (!foundDataChunk) {
49845                     pWav->dataChunkDataPos = cursor;
49846                 }
49847                 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
49848                     sampleCountFromFactChunk = sampleCount;
49849                 } else {
49850                     sampleCountFromFactChunk = 0;
49851                 }
49852             }
49853         } else if (pWav->container == drwav_container_w64) {
49854             if (drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
49855                 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
49856                     return DRWAV_FALSE;
49857                 }
49858                 chunkSize -= 8;
49859                 if (!foundDataChunk) {
49860                     pWav->dataChunkDataPos = cursor;
49861                 }
49862             }
49863         } else if (pWav->container == drwav_container_rf64) {
49864         }
49865         if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
49866             if (drwav_fourcc_equal(header.id.fourcc, "smpl")) {
49867                 drwav_uint8 smplHeaderData[36];
49868                 if (chunkSize >= sizeof(smplHeaderData)) {
49869                     drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor);
49870                     chunkSize -= bytesJustRead;
49871                     if (bytesJustRead == sizeof(smplHeaderData)) {
49872                         drwav_uint32 iLoop;
49873                         pWav->smpl.manufacturer      = drwav_bytes_to_u32(smplHeaderData+0);
49874                         pWav->smpl.product           = drwav_bytes_to_u32(smplHeaderData+4);
49875                         pWav->smpl.samplePeriod      = drwav_bytes_to_u32(smplHeaderData+8);
49876                         pWav->smpl.midiUnityNotes    = drwav_bytes_to_u32(smplHeaderData+12);
49877                         pWav->smpl.midiPitchFraction = drwav_bytes_to_u32(smplHeaderData+16);
49878                         pWav->smpl.smpteFormat       = drwav_bytes_to_u32(smplHeaderData+20);
49879                         pWav->smpl.smpteOffset       = drwav_bytes_to_u32(smplHeaderData+24);
49880                         pWav->smpl.numSampleLoops    = drwav_bytes_to_u32(smplHeaderData+28);
49881                         pWav->smpl.samplerData       = drwav_bytes_to_u32(smplHeaderData+32);
49882                         for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) {
49883                             drwav_uint8 smplLoopData[24];
49884                             bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor);
49885                             chunkSize -= bytesJustRead;
49886                             if (bytesJustRead == sizeof(smplLoopData)) {
49887                                 pWav->smpl.loops[iLoop].cuePointId = drwav_bytes_to_u32(smplLoopData+0);
49888                                 pWav->smpl.loops[iLoop].type       = drwav_bytes_to_u32(smplLoopData+4);
49889                                 pWav->smpl.loops[iLoop].start      = drwav_bytes_to_u32(smplLoopData+8);
49890                                 pWav->smpl.loops[iLoop].end        = drwav_bytes_to_u32(smplLoopData+12);
49891                                 pWav->smpl.loops[iLoop].fraction   = drwav_bytes_to_u32(smplLoopData+16);
49892                                 pWav->smpl.loops[iLoop].playCount  = drwav_bytes_to_u32(smplLoopData+20);
49893                             } else {
49894                                 break;
49895                             }
49896                         }
49897                     }
49898                 } else {
49899                 }
49900             }
49901         } else {
49902             if (drwav_guid_equal(header.id.guid, drwavGUID_W64_SMPL)) {
49903             }
49904         }
49905         chunkSize += header.paddingSize;
49906         if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) {
49907             break;
49908         }
49909         cursor += chunkSize;
49910         if (!foundDataChunk) {
49911             pWav->dataChunkDataPos = cursor;
49912         }
49913     }
49914     if (!foundDataChunk) {
49915         return DRWAV_FALSE;
49916     }
49917     if (!sequential) {
49918         if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
49919             return DRWAV_FALSE;
49920         }
49921         cursor = pWav->dataChunkDataPos;
49922     }
49923     pWav->fmt                 = fmt;
49924     pWav->sampleRate          = fmt.sampleRate;
49925     pWav->channels            = fmt.channels;
49926     pWav->bitsPerSample       = fmt.bitsPerSample;
49927     pWav->bytesRemaining      = dataChunkSize;
49928     pWav->translatedFormatTag = translatedFormatTag;
49929     pWav->dataChunkDataSize   = dataChunkSize;
49930     if (sampleCountFromFactChunk != 0) {
49931         pWav->totalPCMFrameCount = sampleCountFromFactChunk;
49932     } else {
49933         pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav);
49934         if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
49935             drwav_uint64 totalBlockHeaderSizeInBytes;
49936             drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
49937             if ((blockCount * fmt.blockAlign) < dataChunkSize) {
49938                 blockCount += 1;
49939             }
49940             totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
49941             pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
49942         }
49943         if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
49944             drwav_uint64 totalBlockHeaderSizeInBytes;
49945             drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
49946             if ((blockCount * fmt.blockAlign) < dataChunkSize) {
49947                 blockCount += 1;
49948             }
49949             totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
49950             pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
49951             pWav->totalPCMFrameCount += blockCount;
49952         }
49953     }
49954     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
49955         if (pWav->channels > 2) {
49956             return DRWAV_FALSE;
49957         }
49958     }
49959 #ifdef DR_WAV_LIBSNDFILE_COMPAT
49960     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
49961         drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
49962         pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels;
49963     }
49964     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
49965         drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
49966         pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
49967     }
49968 #endif
49969     return DRWAV_TRUE;
49970 }
49971 DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
49972 {
49973     return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
49974 }
49975 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)
49976 {
49977     if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
49978         return DRWAV_FALSE;
49979     }
49980     return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
49981 }
49982 DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)
49983 {
49984     drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
49985     if (chunkSize > 0xFFFFFFFFUL) {
49986         chunkSize = 0xFFFFFFFFUL;
49987     }
49988     return (drwav_uint32)chunkSize;
49989 }
49990 DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
49991 {
49992     if (dataChunkSize <= 0xFFFFFFFFUL) {
49993         return (drwav_uint32)dataChunkSize;
49994     } else {
49995         return 0xFFFFFFFFUL;
49996     }
49997 }
49998 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
49999 {
50000     drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
50001     return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize;
50002 }
50003 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
50004 {
50005     return 24 + dataChunkSize;
50006 }
50007 DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize)
50008 {
50009     drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
50010     if (chunkSize > 0xFFFFFFFFUL) {
50011         chunkSize = 0xFFFFFFFFUL;
50012     }
50013     return chunkSize;
50014 }
50015 DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
50016 {
50017     return dataChunkSize;
50018 }
50019 DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
50020 {
50021     DRWAV_ASSERT(pWav          != NULL);
50022     DRWAV_ASSERT(pWav->onWrite != NULL);
50023     return pWav->onWrite(pWav->pUserData, pData, dataSize);
50024 }
50025 DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
50026 {
50027     DRWAV_ASSERT(pWav          != NULL);
50028     DRWAV_ASSERT(pWav->onWrite != NULL);
50029     if (!drwav__is_little_endian()) {
50030         value = drwav__bswap16(value);
50031     }
50032     return drwav__write(pWav, &value, 2);
50033 }
50034 DRWAV_PRIVATE size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
50035 {
50036     DRWAV_ASSERT(pWav          != NULL);
50037     DRWAV_ASSERT(pWav->onWrite != NULL);
50038     if (!drwav__is_little_endian()) {
50039         value = drwav__bswap32(value);
50040     }
50041     return drwav__write(pWav, &value, 4);
50042 }
50043 DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
50044 {
50045     DRWAV_ASSERT(pWav          != NULL);
50046     DRWAV_ASSERT(pWav->onWrite != NULL);
50047     if (!drwav__is_little_endian()) {
50048         value = drwav__bswap64(value);
50049     }
50050     return drwav__write(pWav, &value, 8);
50051 }
50052 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)
50053 {
50054     if (pWav == NULL || onWrite == NULL) {
50055         return DRWAV_FALSE;
50056     }
50057     if (!isSequential && onSeek == NULL) {
50058         return DRWAV_FALSE;
50059     }
50060     if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
50061         return DRWAV_FALSE;
50062     }
50063     if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
50064         return DRWAV_FALSE;
50065     }
50066     DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
50067     pWav->onWrite   = onWrite;
50068     pWav->onSeek    = onSeek;
50069     pWav->pUserData = pUserData;
50070     pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
50071     if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
50072         return DRWAV_FALSE;
50073     }
50074     pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
50075     pWav->fmt.channels = (drwav_uint16)pFormat->channels;
50076     pWav->fmt.sampleRate = pFormat->sampleRate;
50077     pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
50078     pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
50079     pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
50080     pWav->fmt.extendedSize = 0;
50081     pWav->isSequentialWrite = isSequential;
50082     return DRWAV_TRUE;
50083 }
50084 DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
50085 {
50086     size_t runningPos = 0;
50087     drwav_uint64 initialDataChunkSize = 0;
50088     drwav_uint64 chunkSizeFMT;
50089     if (pWav->isSequentialWrite) {
50090         initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
50091         if (pFormat->container == drwav_container_riff) {
50092             if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
50093                 return DRWAV_FALSE;
50094             }
50095         }
50096     }
50097     pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
50098     if (pFormat->container == drwav_container_riff) {
50099         drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize;
50100         runningPos += drwav__write(pWav, "RIFF", 4);
50101         runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
50102         runningPos += drwav__write(pWav, "WAVE", 4);
50103     } else if (pFormat->container == drwav_container_w64) {
50104         drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize;
50105         runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
50106         runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
50107         runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
50108     } else if (pFormat->container == drwav_container_rf64) {
50109         runningPos += drwav__write(pWav, "RF64", 4);
50110         runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
50111         runningPos += drwav__write(pWav, "WAVE", 4);
50112     }
50113     if (pFormat->container == drwav_container_rf64) {
50114         drwav_uint32 initialds64ChunkSize = 28;
50115         drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize;
50116         runningPos += drwav__write(pWav, "ds64", 4);
50117         runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize);
50118         runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize);
50119         runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize);
50120         runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount);
50121         runningPos += drwav__write_u32ne_to_le(pWav, 0);
50122     }
50123     if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
50124         chunkSizeFMT = 16;
50125         runningPos += drwav__write(pWav, "fmt ", 4);
50126         runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
50127     } else if (pFormat->container == drwav_container_w64) {
50128         chunkSizeFMT = 40;
50129         runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
50130         runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
50131     }
50132     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag);
50133     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels);
50134     runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate);
50135     runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec);
50136     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign);
50137     runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample);
50138     if (pFormat->container == drwav_container_riff) {
50139         drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
50140         runningPos += drwav__write(pWav, "data", 4);
50141         runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
50142     } else if (pFormat->container == drwav_container_w64) {
50143         drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize;
50144         runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
50145         runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
50146     } else if (pFormat->container == drwav_container_rf64) {
50147         runningPos += drwav__write(pWav, "data", 4);
50148         runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
50149     }
50150     pWav->container = pFormat->container;
50151     pWav->channels = (drwav_uint16)pFormat->channels;
50152     pWav->sampleRate = pFormat->sampleRate;
50153     pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
50154     pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
50155     pWav->dataChunkDataPos = runningPos;
50156     return DRWAV_TRUE;
50157 }
50158 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)
50159 {
50160     if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
50161         return DRWAV_FALSE;
50162     }
50163     return drwav_init_write__internal(pWav, pFormat, 0);
50164 }
50165 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)
50166 {
50167     if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
50168         return DRWAV_FALSE;
50169     }
50170     return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
50171 }
50172 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)
50173 {
50174     if (pFormat == NULL) {
50175         return DRWAV_FALSE;
50176     }
50177     return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
50178 }
50179 DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
50180 {
50181     drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0);
50182     drwav_uint64 riffChunkSizeBytes;
50183     drwav_uint64 fileSizeBytes = 0;
50184     if (pFormat->container == drwav_container_riff) {
50185         riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes);
50186         fileSizeBytes = (8 + riffChunkSizeBytes);
50187     } else if (pFormat->container == drwav_container_w64) {
50188         riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
50189         fileSizeBytes = riffChunkSizeBytes;
50190     } else if (pFormat->container == drwav_container_rf64) {
50191         riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes);
50192         fileSizeBytes = (8 + riffChunkSizeBytes);
50193     }
50194     return fileSizeBytes;
50195 }
50196 #ifndef DR_WAV_NO_STDIO
50197 #include <errno.h>
50198 DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e)
50199 {
50200     switch (e)
50201     {
50202         case 0: return DRWAV_SUCCESS;
50203     #ifdef EPERM
50204         case EPERM: return DRWAV_INVALID_OPERATION;
50205     #endif
50206     #ifdef ENOENT
50207         case ENOENT: return DRWAV_DOES_NOT_EXIST;
50208     #endif
50209     #ifdef ESRCH
50210         case ESRCH: return DRWAV_DOES_NOT_EXIST;
50211     #endif
50212     #ifdef EINTR
50213         case EINTR: return DRWAV_INTERRUPT;
50214     #endif
50215     #ifdef EIO
50216         case EIO: return DRWAV_IO_ERROR;
50217     #endif
50218     #ifdef ENXIO
50219         case ENXIO: return DRWAV_DOES_NOT_EXIST;
50220     #endif
50221     #ifdef E2BIG
50222         case E2BIG: return DRWAV_INVALID_ARGS;
50223     #endif
50224     #ifdef ENOEXEC
50225         case ENOEXEC: return DRWAV_INVALID_FILE;
50226     #endif
50227     #ifdef EBADF
50228         case EBADF: return DRWAV_INVALID_FILE;
50229     #endif
50230     #ifdef ECHILD
50231         case ECHILD: return DRWAV_ERROR;
50232     #endif
50233     #ifdef EAGAIN
50234         case EAGAIN: return DRWAV_UNAVAILABLE;
50235     #endif
50236     #ifdef ENOMEM
50237         case ENOMEM: return DRWAV_OUT_OF_MEMORY;
50238     #endif
50239     #ifdef EACCES
50240         case EACCES: return DRWAV_ACCESS_DENIED;
50241     #endif
50242     #ifdef EFAULT
50243         case EFAULT: return DRWAV_BAD_ADDRESS;
50244     #endif
50245     #ifdef ENOTBLK
50246         case ENOTBLK: return DRWAV_ERROR;
50247     #endif
50248     #ifdef EBUSY
50249         case EBUSY: return DRWAV_BUSY;
50250     #endif
50251     #ifdef EEXIST
50252         case EEXIST: return DRWAV_ALREADY_EXISTS;
50253     #endif
50254     #ifdef EXDEV
50255         case EXDEV: return DRWAV_ERROR;
50256     #endif
50257     #ifdef ENODEV
50258         case ENODEV: return DRWAV_DOES_NOT_EXIST;
50259     #endif
50260     #ifdef ENOTDIR
50261         case ENOTDIR: return DRWAV_NOT_DIRECTORY;
50262     #endif
50263     #ifdef EISDIR
50264         case EISDIR: return DRWAV_IS_DIRECTORY;
50265     #endif
50266     #ifdef EINVAL
50267         case EINVAL: return DRWAV_INVALID_ARGS;
50268     #endif
50269     #ifdef ENFILE
50270         case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES;
50271     #endif
50272     #ifdef EMFILE
50273         case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES;
50274     #endif
50275     #ifdef ENOTTY
50276         case ENOTTY: return DRWAV_INVALID_OPERATION;
50277     #endif
50278     #ifdef ETXTBSY
50279         case ETXTBSY: return DRWAV_BUSY;
50280     #endif
50281     #ifdef EFBIG
50282         case EFBIG: return DRWAV_TOO_BIG;
50283     #endif
50284     #ifdef ENOSPC
50285         case ENOSPC: return DRWAV_NO_SPACE;
50286     #endif
50287     #ifdef ESPIPE
50288         case ESPIPE: return DRWAV_BAD_SEEK;
50289     #endif
50290     #ifdef EROFS
50291         case EROFS: return DRWAV_ACCESS_DENIED;
50292     #endif
50293     #ifdef EMLINK
50294         case EMLINK: return DRWAV_TOO_MANY_LINKS;
50295     #endif
50296     #ifdef EPIPE
50297         case EPIPE: return DRWAV_BAD_PIPE;
50298     #endif
50299     #ifdef EDOM
50300         case EDOM: return DRWAV_OUT_OF_RANGE;
50301     #endif
50302     #ifdef ERANGE
50303         case ERANGE: return DRWAV_OUT_OF_RANGE;
50304     #endif
50305     #ifdef EDEADLK
50306         case EDEADLK: return DRWAV_DEADLOCK;
50307     #endif
50308     #ifdef ENAMETOOLONG
50309         case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG;
50310     #endif
50311     #ifdef ENOLCK
50312         case ENOLCK: return DRWAV_ERROR;
50313     #endif
50314     #ifdef ENOSYS
50315         case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
50316     #endif
50317     #ifdef ENOTEMPTY
50318         case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
50319     #endif
50320     #ifdef ELOOP
50321         case ELOOP: return DRWAV_TOO_MANY_LINKS;
50322     #endif
50323     #ifdef ENOMSG
50324         case ENOMSG: return DRWAV_NO_MESSAGE;
50325     #endif
50326     #ifdef EIDRM
50327         case EIDRM: return DRWAV_ERROR;
50328     #endif
50329     #ifdef ECHRNG
50330         case ECHRNG: return DRWAV_ERROR;
50331     #endif
50332     #ifdef EL2NSYNC
50333         case EL2NSYNC: return DRWAV_ERROR;
50334     #endif
50335     #ifdef EL3HLT
50336         case EL3HLT: return DRWAV_ERROR;
50337     #endif
50338     #ifdef EL3RST
50339         case EL3RST: return DRWAV_ERROR;
50340     #endif
50341     #ifdef ELNRNG
50342         case ELNRNG: return DRWAV_OUT_OF_RANGE;
50343     #endif
50344     #ifdef EUNATCH
50345         case EUNATCH: return DRWAV_ERROR;
50346     #endif
50347     #ifdef ENOCSI
50348         case ENOCSI: return DRWAV_ERROR;
50349     #endif
50350     #ifdef EL2HLT
50351         case EL2HLT: return DRWAV_ERROR;
50352     #endif
50353     #ifdef EBADE
50354         case EBADE: return DRWAV_ERROR;
50355     #endif
50356     #ifdef EBADR
50357         case EBADR: return DRWAV_ERROR;
50358     #endif
50359     #ifdef EXFULL
50360         case EXFULL: return DRWAV_ERROR;
50361     #endif
50362     #ifdef ENOANO
50363         case ENOANO: return DRWAV_ERROR;
50364     #endif
50365     #ifdef EBADRQC
50366         case EBADRQC: return DRWAV_ERROR;
50367     #endif
50368     #ifdef EBADSLT
50369         case EBADSLT: return DRWAV_ERROR;
50370     #endif
50371     #ifdef EBFONT
50372         case EBFONT: return DRWAV_INVALID_FILE;
50373     #endif
50374     #ifdef ENOSTR
50375         case ENOSTR: return DRWAV_ERROR;
50376     #endif
50377     #ifdef ENODATA
50378         case ENODATA: return DRWAV_NO_DATA_AVAILABLE;
50379     #endif
50380     #ifdef ETIME
50381         case ETIME: return DRWAV_TIMEOUT;
50382     #endif
50383     #ifdef ENOSR
50384         case ENOSR: return DRWAV_NO_DATA_AVAILABLE;
50385     #endif
50386     #ifdef ENONET
50387         case ENONET: return DRWAV_NO_NETWORK;
50388     #endif
50389     #ifdef ENOPKG
50390         case ENOPKG: return DRWAV_ERROR;
50391     #endif
50392     #ifdef EREMOTE
50393         case EREMOTE: return DRWAV_ERROR;
50394     #endif
50395     #ifdef ENOLINK
50396         case ENOLINK: return DRWAV_ERROR;
50397     #endif
50398     #ifdef EADV
50399         case EADV: return DRWAV_ERROR;
50400     #endif
50401     #ifdef ESRMNT
50402         case ESRMNT: return DRWAV_ERROR;
50403     #endif
50404     #ifdef ECOMM
50405         case ECOMM: return DRWAV_ERROR;
50406     #endif
50407     #ifdef EPROTO
50408         case EPROTO: return DRWAV_ERROR;
50409     #endif
50410     #ifdef EMULTIHOP
50411         case EMULTIHOP: return DRWAV_ERROR;
50412     #endif
50413     #ifdef EDOTDOT
50414         case EDOTDOT: return DRWAV_ERROR;
50415     #endif
50416     #ifdef EBADMSG
50417         case EBADMSG: return DRWAV_BAD_MESSAGE;
50418     #endif
50419     #ifdef EOVERFLOW
50420         case EOVERFLOW: return DRWAV_TOO_BIG;
50421     #endif
50422     #ifdef ENOTUNIQ
50423         case ENOTUNIQ: return DRWAV_NOT_UNIQUE;
50424     #endif
50425     #ifdef EBADFD
50426         case EBADFD: return DRWAV_ERROR;
50427     #endif
50428     #ifdef EREMCHG
50429         case EREMCHG: return DRWAV_ERROR;
50430     #endif
50431     #ifdef ELIBACC
50432         case ELIBACC: return DRWAV_ACCESS_DENIED;
50433     #endif
50434     #ifdef ELIBBAD
50435         case ELIBBAD: return DRWAV_INVALID_FILE;
50436     #endif
50437     #ifdef ELIBSCN
50438         case ELIBSCN: return DRWAV_INVALID_FILE;
50439     #endif
50440     #ifdef ELIBMAX
50441         case ELIBMAX: return DRWAV_ERROR;
50442     #endif
50443     #ifdef ELIBEXEC
50444         case ELIBEXEC: return DRWAV_ERROR;
50445     #endif
50446     #ifdef EILSEQ
50447         case EILSEQ: return DRWAV_INVALID_DATA;
50448     #endif
50449     #ifdef ERESTART
50450         case ERESTART: return DRWAV_ERROR;
50451     #endif
50452     #ifdef ESTRPIPE
50453         case ESTRPIPE: return DRWAV_ERROR;
50454     #endif
50455     #ifdef EUSERS
50456         case EUSERS: return DRWAV_ERROR;
50457     #endif
50458     #ifdef ENOTSOCK
50459         case ENOTSOCK: return DRWAV_NOT_SOCKET;
50460     #endif
50461     #ifdef EDESTADDRREQ
50462         case EDESTADDRREQ: return DRWAV_NO_ADDRESS;
50463     #endif
50464     #ifdef EMSGSIZE
50465         case EMSGSIZE: return DRWAV_TOO_BIG;
50466     #endif
50467     #ifdef EPROTOTYPE
50468         case EPROTOTYPE: return DRWAV_BAD_PROTOCOL;
50469     #endif
50470     #ifdef ENOPROTOOPT
50471         case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE;
50472     #endif
50473     #ifdef EPROTONOSUPPORT
50474         case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED;
50475     #endif
50476     #ifdef ESOCKTNOSUPPORT
50477         case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED;
50478     #endif
50479     #ifdef EOPNOTSUPP
50480         case EOPNOTSUPP: return DRWAV_INVALID_OPERATION;
50481     #endif
50482     #ifdef EPFNOSUPPORT
50483         case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED;
50484     #endif
50485     #ifdef EAFNOSUPPORT
50486         case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED;
50487     #endif
50488     #ifdef EADDRINUSE
50489         case EADDRINUSE: return DRWAV_ALREADY_IN_USE;
50490     #endif
50491     #ifdef EADDRNOTAVAIL
50492         case EADDRNOTAVAIL: return DRWAV_ERROR;
50493     #endif
50494     #ifdef ENETDOWN
50495         case ENETDOWN: return DRWAV_NO_NETWORK;
50496     #endif
50497     #ifdef ENETUNREACH
50498         case ENETUNREACH: return DRWAV_NO_NETWORK;
50499     #endif
50500     #ifdef ENETRESET
50501         case ENETRESET: return DRWAV_NO_NETWORK;
50502     #endif
50503     #ifdef ECONNABORTED
50504         case ECONNABORTED: return DRWAV_NO_NETWORK;
50505     #endif
50506     #ifdef ECONNRESET
50507         case ECONNRESET: return DRWAV_CONNECTION_RESET;
50508     #endif
50509     #ifdef ENOBUFS
50510         case ENOBUFS: return DRWAV_NO_SPACE;
50511     #endif
50512     #ifdef EISCONN
50513         case EISCONN: return DRWAV_ALREADY_CONNECTED;
50514     #endif
50515     #ifdef ENOTCONN
50516         case ENOTCONN: return DRWAV_NOT_CONNECTED;
50517     #endif
50518     #ifdef ESHUTDOWN
50519         case ESHUTDOWN: return DRWAV_ERROR;
50520     #endif
50521     #ifdef ETOOMANYREFS
50522         case ETOOMANYREFS: return DRWAV_ERROR;
50523     #endif
50524     #ifdef ETIMEDOUT
50525         case ETIMEDOUT: return DRWAV_TIMEOUT;
50526     #endif
50527     #ifdef ECONNREFUSED
50528         case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED;
50529     #endif
50530     #ifdef EHOSTDOWN
50531         case EHOSTDOWN: return DRWAV_NO_HOST;
50532     #endif
50533     #ifdef EHOSTUNREACH
50534         case EHOSTUNREACH: return DRWAV_NO_HOST;
50535     #endif
50536     #ifdef EALREADY
50537         case EALREADY: return DRWAV_IN_PROGRESS;
50538     #endif
50539     #ifdef EINPROGRESS
50540         case EINPROGRESS: return DRWAV_IN_PROGRESS;
50541     #endif
50542     #ifdef ESTALE
50543         case ESTALE: return DRWAV_INVALID_FILE;
50544     #endif
50545     #ifdef EUCLEAN
50546         case EUCLEAN: return DRWAV_ERROR;
50547     #endif
50548     #ifdef ENOTNAM
50549         case ENOTNAM: return DRWAV_ERROR;
50550     #endif
50551     #ifdef ENAVAIL
50552         case ENAVAIL: return DRWAV_ERROR;
50553     #endif
50554     #ifdef EISNAM
50555         case EISNAM: return DRWAV_ERROR;
50556     #endif
50557     #ifdef EREMOTEIO
50558         case EREMOTEIO: return DRWAV_IO_ERROR;
50559     #endif
50560     #ifdef EDQUOT
50561         case EDQUOT: return DRWAV_NO_SPACE;
50562     #endif
50563     #ifdef ENOMEDIUM
50564         case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST;
50565     #endif
50566     #ifdef EMEDIUMTYPE
50567         case EMEDIUMTYPE: return DRWAV_ERROR;
50568     #endif
50569     #ifdef ECANCELED
50570         case ECANCELED: return DRWAV_CANCELLED;
50571     #endif
50572     #ifdef ENOKEY
50573         case ENOKEY: return DRWAV_ERROR;
50574     #endif
50575     #ifdef EKEYEXPIRED
50576         case EKEYEXPIRED: return DRWAV_ERROR;
50577     #endif
50578     #ifdef EKEYREVOKED
50579         case EKEYREVOKED: return DRWAV_ERROR;
50580     #endif
50581     #ifdef EKEYREJECTED
50582         case EKEYREJECTED: return DRWAV_ERROR;
50583     #endif
50584     #ifdef EOWNERDEAD
50585         case EOWNERDEAD: return DRWAV_ERROR;
50586     #endif
50587     #ifdef ENOTRECOVERABLE
50588         case ENOTRECOVERABLE: return DRWAV_ERROR;
50589     #endif
50590     #ifdef ERFKILL
50591         case ERFKILL: return DRWAV_ERROR;
50592     #endif
50593     #ifdef EHWPOISON
50594         case EHWPOISON: return DRWAV_ERROR;
50595     #endif
50596         default: return DRWAV_ERROR;
50597     }
50598 }
50599 DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
50600 {
50601 #if defined(_MSC_VER) && _MSC_VER >= 1400
50602     errno_t err;
50603 #endif
50604     if (ppFile != NULL) {
50605         *ppFile = NULL;
50606     }
50607     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
50608         return DRWAV_INVALID_ARGS;
50609     }
50610 #if defined(_MSC_VER) && _MSC_VER >= 1400
50611     err = fopen_s(ppFile, pFilePath, pOpenMode);
50612     if (err != 0) {
50613         return drwav_result_from_errno(err);
50614     }
50615 #else
50616 #if defined(_WIN32) || defined(__APPLE__)
50617     *ppFile = fopen(pFilePath, pOpenMode);
50618 #else
50619     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
50620         *ppFile = fopen64(pFilePath, pOpenMode);
50621     #else
50622         *ppFile = fopen(pFilePath, pOpenMode);
50623     #endif
50624 #endif
50625     if (*ppFile == NULL) {
50626         drwav_result result = drwav_result_from_errno(errno);
50627         if (result == DRWAV_SUCCESS) {
50628             result = DRWAV_ERROR;
50629         }
50630         return result;
50631     }
50632 #endif
50633     return DRWAV_SUCCESS;
50634 }
50635 #if defined(_WIN32)
50636     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
50637         #define DRWAV_HAS_WFOPEN
50638     #endif
50639 #endif
50640 DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
50641 {
50642     if (ppFile != NULL) {
50643         *ppFile = NULL;
50644     }
50645     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
50646         return DRWAV_INVALID_ARGS;
50647     }
50648 #if defined(DRWAV_HAS_WFOPEN)
50649     {
50650     #if defined(_MSC_VER) && _MSC_VER >= 1400
50651         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
50652         if (err != 0) {
50653             return drwav_result_from_errno(err);
50654         }
50655     #else
50656         *ppFile = _wfopen(pFilePath, pOpenMode);
50657         if (*ppFile == NULL) {
50658             return drwav_result_from_errno(errno);
50659         }
50660     #endif
50661         (void)pAllocationCallbacks;
50662     }
50663 #else
50664     {
50665         mbstate_t mbs;
50666         size_t lenMB;
50667         const wchar_t* pFilePathTemp = pFilePath;
50668         char* pFilePathMB = NULL;
50669         char pOpenModeMB[32] = {0};
50670         DRWAV_ZERO_OBJECT(&mbs);
50671         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
50672         if (lenMB == (size_t)-1) {
50673             return drwav_result_from_errno(errno);
50674         }
50675         pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
50676         if (pFilePathMB == NULL) {
50677             return DRWAV_OUT_OF_MEMORY;
50678         }
50679         pFilePathTemp = pFilePath;
50680         DRWAV_ZERO_OBJECT(&mbs);
50681         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
50682         {
50683             size_t i = 0;
50684             for (;;) {
50685                 if (pOpenMode[i] == 0) {
50686                     pOpenModeMB[i] = '\0';
50687                     break;
50688                 }
50689                 pOpenModeMB[i] = (char)pOpenMode[i];
50690                 i += 1;
50691             }
50692         }
50693         *ppFile = fopen(pFilePathMB, pOpenModeMB);
50694         drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
50695     }
50696     if (*ppFile == NULL) {
50697         return DRWAV_ERROR;
50698     }
50699 #endif
50700     return DRWAV_SUCCESS;
50701 }
50702 DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
50703 {
50704     return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
50705 }
50706 DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
50707 {
50708     return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
50709 }
50710 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
50711 {
50712     return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
50713 }
50714 DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
50715 {
50716     return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
50717 }
50718 DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
50719 {
50720     drwav_bool32 result;
50721     result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
50722     if (result != DRWAV_TRUE) {
50723         fclose(pFile);
50724         return result;
50725     }
50726     result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
50727     if (result != DRWAV_TRUE) {
50728         fclose(pFile);
50729         return result;
50730     }
50731     return DRWAV_TRUE;
50732 }
50733 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)
50734 {
50735     FILE* pFile;
50736     if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
50737         return DRWAV_FALSE;
50738     }
50739     return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
50740 }
50741 DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
50742 {
50743     return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
50744 }
50745 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)
50746 {
50747     FILE* pFile;
50748     if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
50749         return DRWAV_FALSE;
50750     }
50751     return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
50752 }
50753 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)
50754 {
50755     drwav_bool32 result;
50756     result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
50757     if (result != DRWAV_TRUE) {
50758         fclose(pFile);
50759         return result;
50760     }
50761     result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
50762     if (result != DRWAV_TRUE) {
50763         fclose(pFile);
50764         return result;
50765     }
50766     return DRWAV_TRUE;
50767 }
50768 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)
50769 {
50770     FILE* pFile;
50771     if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
50772         return DRWAV_FALSE;
50773     }
50774     return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
50775 }
50776 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)
50777 {
50778     FILE* pFile;
50779     if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
50780         return DRWAV_FALSE;
50781     }
50782     return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
50783 }
50784 DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
50785 {
50786     return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
50787 }
50788 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)
50789 {
50790     return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
50791 }
50792 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)
50793 {
50794     if (pFormat == NULL) {
50795         return DRWAV_FALSE;
50796     }
50797     return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
50798 }
50799 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)
50800 {
50801     return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
50802 }
50803 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)
50804 {
50805     return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
50806 }
50807 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)
50808 {
50809     if (pFormat == NULL) {
50810         return DRWAV_FALSE;
50811     }
50812     return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
50813 }
50814 #endif
50815 DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
50816 {
50817     drwav* pWav = (drwav*)pUserData;
50818     size_t bytesRemaining;
50819     DRWAV_ASSERT(pWav != NULL);
50820     DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
50821     bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
50822     if (bytesToRead > bytesRemaining) {
50823         bytesToRead = bytesRemaining;
50824     }
50825     if (bytesToRead > 0) {
50826         DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
50827         pWav->memoryStream.currentReadPos += bytesToRead;
50828     }
50829     return bytesToRead;
50830 }
50831 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
50832 {
50833     drwav* pWav = (drwav*)pUserData;
50834     DRWAV_ASSERT(pWav != NULL);
50835     if (origin == drwav_seek_origin_current) {
50836         if (offset > 0) {
50837             if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
50838                 return DRWAV_FALSE;
50839             }
50840         } else {
50841             if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
50842                 return DRWAV_FALSE;
50843             }
50844         }
50845         pWav->memoryStream.currentReadPos += offset;
50846     } else {
50847         if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
50848             pWav->memoryStream.currentReadPos = offset;
50849         } else {
50850             return DRWAV_FALSE;
50851         }
50852     }
50853     return DRWAV_TRUE;
50854 }
50855 DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
50856 {
50857     drwav* pWav = (drwav*)pUserData;
50858     size_t bytesRemaining;
50859     DRWAV_ASSERT(pWav != NULL);
50860     DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
50861     bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
50862     if (bytesRemaining < bytesToWrite) {
50863         void* pNewData;
50864         size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
50865         if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
50866             newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
50867         }
50868         pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
50869         if (pNewData == NULL) {
50870             return 0;
50871         }
50872         *pWav->memoryStreamWrite.ppData = pNewData;
50873         pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
50874     }
50875     DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
50876     pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
50877     if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
50878         pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
50879     }
50880     *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
50881     return bytesToWrite;
50882 }
50883 DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
50884 {
50885     drwav* pWav = (drwav*)pUserData;
50886     DRWAV_ASSERT(pWav != NULL);
50887     if (origin == drwav_seek_origin_current) {
50888         if (offset > 0) {
50889             if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
50890                 offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos);
50891             }
50892         } else {
50893             if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
50894                 offset = -(int)pWav->memoryStreamWrite.currentWritePos;
50895             }
50896         }
50897         pWav->memoryStreamWrite.currentWritePos += offset;
50898     } else {
50899         if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
50900             pWav->memoryStreamWrite.currentWritePos = offset;
50901         } else {
50902             pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize;
50903         }
50904     }
50905     return DRWAV_TRUE;
50906 }
50907 DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
50908 {
50909     return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
50910 }
50911 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)
50912 {
50913     if (data == NULL || dataSize == 0) {
50914         return DRWAV_FALSE;
50915     }
50916     if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
50917         return DRWAV_FALSE;
50918     }
50919     pWav->memoryStream.data = (const drwav_uint8*)data;
50920     pWav->memoryStream.dataSize = dataSize;
50921     pWav->memoryStream.currentReadPos = 0;
50922     return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
50923 }
50924 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)
50925 {
50926     if (ppData == NULL || pDataSize == NULL) {
50927         return DRWAV_FALSE;
50928     }
50929     *ppData = NULL;
50930     *pDataSize = 0;
50931     if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
50932         return DRWAV_FALSE;
50933     }
50934     pWav->memoryStreamWrite.ppData = ppData;
50935     pWav->memoryStreamWrite.pDataSize = pDataSize;
50936     pWav->memoryStreamWrite.dataSize = 0;
50937     pWav->memoryStreamWrite.dataCapacity = 0;
50938     pWav->memoryStreamWrite.currentWritePos = 0;
50939     return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
50940 }
50941 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)
50942 {
50943     return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
50944 }
50945 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)
50946 {
50947     return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
50948 }
50949 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)
50950 {
50951     if (pFormat == NULL) {
50952         return DRWAV_FALSE;
50953     }
50954     return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
50955 }
50956 DRWAV_API drwav_result drwav_uninit(drwav* pWav)
50957 {
50958     drwav_result result = DRWAV_SUCCESS;
50959     if (pWav == NULL) {
50960         return DRWAV_INVALID_ARGS;
50961     }
50962     if (pWav->onWrite != NULL) {
50963         drwav_uint32 paddingSize = 0;
50964         if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
50965             paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
50966         } else {
50967             paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
50968         }
50969         if (paddingSize > 0) {
50970             drwav_uint64 paddingData = 0;
50971             drwav__write(pWav, &paddingData, paddingSize);
50972         }
50973         if (pWav->onSeek && !pWav->isSequentialWrite) {
50974             if (pWav->container == drwav_container_riff) {
50975                 if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
50976                     drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize);
50977                     drwav__write_u32ne_to_le(pWav, riffChunkSize);
50978                 }
50979                 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, drwav_seek_origin_start)) {
50980                     drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
50981                     drwav__write_u32ne_to_le(pWav, dataChunkSize);
50982                 }
50983             } else if (pWav->container == drwav_container_w64) {
50984                 if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
50985                     drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
50986                     drwav__write_u64ne_to_le(pWav, riffChunkSize);
50987                 }
50988                 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, drwav_seek_origin_start)) {
50989                     drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
50990                     drwav__write_u64ne_to_le(pWav, dataChunkSize);
50991                 }
50992             } else if (pWav->container == drwav_container_rf64) {
50993                 int ds64BodyPos = 12 + 8;
50994                 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
50995                     drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize);
50996                     drwav__write_u64ne_to_le(pWav, riffChunkSize);
50997                 }
50998                 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
50999                     drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
51000                     drwav__write_u64ne_to_le(pWav, dataChunkSize);
51001                 }
51002             }
51003         }
51004         if (pWav->isSequentialWrite) {
51005             if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
51006                 result = DRWAV_INVALID_FILE;
51007             }
51008         }
51009     }
51010 #ifndef DR_WAV_NO_STDIO
51011     if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
51012         fclose((FILE*)pWav->pUserData);
51013     }
51014 #endif
51015     return result;
51016 }
51017 DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
51018 {
51019     size_t bytesRead;
51020     if (pWav == NULL || bytesToRead == 0) {
51021         return 0;
51022     }
51023     if (bytesToRead > pWav->bytesRemaining) {
51024         bytesToRead = (size_t)pWav->bytesRemaining;
51025     }
51026     if (pBufferOut != NULL) {
51027         bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
51028     } else {
51029         bytesRead = 0;
51030         while (bytesRead < bytesToRead) {
51031             size_t bytesToSeek = (bytesToRead - bytesRead);
51032             if (bytesToSeek > 0x7FFFFFFF) {
51033                 bytesToSeek = 0x7FFFFFFF;
51034             }
51035             if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
51036                 break;
51037             }
51038             bytesRead += bytesToSeek;
51039         }
51040         while (bytesRead < bytesToRead) {
51041             drwav_uint8 buffer[4096];
51042             size_t bytesSeeked;
51043             size_t bytesToSeek = (bytesToRead - bytesRead);
51044             if (bytesToSeek > sizeof(buffer)) {
51045                 bytesToSeek = sizeof(buffer);
51046             }
51047             bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek);
51048             bytesRead += bytesSeeked;
51049             if (bytesSeeked < bytesToSeek) {
51050                 break;
51051             }
51052         }
51053     }
51054     pWav->bytesRemaining -= bytesRead;
51055     return bytesRead;
51056 }
51057 DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
51058 {
51059     drwav_uint32 bytesPerFrame;
51060     drwav_uint64 bytesToRead;
51061     if (pWav == NULL || framesToRead == 0) {
51062         return 0;
51063     }
51064     if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
51065         return 0;
51066     }
51067     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51068     if (bytesPerFrame == 0) {
51069         return 0;
51070     }
51071     bytesToRead = framesToRead * bytesPerFrame;
51072     if (bytesToRead > DRWAV_SIZE_MAX) {
51073         bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame;
51074     }
51075     if (bytesToRead == 0) {
51076         return 0;
51077     }
51078     return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame;
51079 }
51080 DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
51081 {
51082     drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
51083     if (pBufferOut != NULL) {
51084         drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag);
51085     }
51086     return framesRead;
51087 }
51088 DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
51089 {
51090     if (drwav__is_little_endian()) {
51091         return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
51092     } else {
51093         return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
51094     }
51095 }
51096 DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
51097 {
51098     if (pWav->onWrite != NULL) {
51099         return DRWAV_FALSE;
51100     }
51101     if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
51102         return DRWAV_FALSE;
51103     }
51104     if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
51105         pWav->compressed.iCurrentPCMFrame = 0;
51106         if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
51107             DRWAV_ZERO_OBJECT(&pWav->msadpcm);
51108         } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
51109             DRWAV_ZERO_OBJECT(&pWav->ima);
51110         } else {
51111             DRWAV_ASSERT(DRWAV_FALSE);
51112         }
51113     }
51114     pWav->bytesRemaining = pWav->dataChunkDataSize;
51115     return DRWAV_TRUE;
51116 }
51117 DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
51118 {
51119     if (pWav == NULL || pWav->onSeek == NULL) {
51120         return DRWAV_FALSE;
51121     }
51122     if (pWav->onWrite != NULL) {
51123         return DRWAV_FALSE;
51124     }
51125     if (pWav->totalPCMFrameCount == 0) {
51126         return DRWAV_TRUE;
51127     }
51128     if (targetFrameIndex >= pWav->totalPCMFrameCount) {
51129         targetFrameIndex  = pWav->totalPCMFrameCount - 1;
51130     }
51131     if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
51132         if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) {
51133             if (!drwav_seek_to_first_pcm_frame(pWav)) {
51134                 return DRWAV_FALSE;
51135             }
51136         }
51137         if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) {
51138             drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame;
51139             drwav_int16 devnull[2048];
51140             while (offsetInFrames > 0) {
51141                 drwav_uint64 framesRead = 0;
51142                 drwav_uint64 framesToRead = offsetInFrames;
51143                 if (framesToRead > drwav_countof(devnull)/pWav->channels) {
51144                     framesToRead = drwav_countof(devnull)/pWav->channels;
51145                 }
51146                 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
51147                     framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull);
51148                 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
51149                     framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull);
51150                 } else {
51151                     DRWAV_ASSERT(DRWAV_FALSE);
51152                 }
51153                 if (framesRead != framesToRead) {
51154                     return DRWAV_FALSE;
51155                 }
51156                 offsetInFrames -= framesRead;
51157             }
51158         }
51159     } else {
51160         drwav_uint64 totalSizeInBytes;
51161         drwav_uint64 currentBytePos;
51162         drwav_uint64 targetBytePos;
51163         drwav_uint64 offset;
51164         totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav);
51165         DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);
51166         currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
51167         targetBytePos  = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav);
51168         if (currentBytePos < targetBytePos) {
51169             offset = (targetBytePos - currentBytePos);
51170         } else {
51171             if (!drwav_seek_to_first_pcm_frame(pWav)) {
51172                 return DRWAV_FALSE;
51173             }
51174             offset = targetBytePos;
51175         }
51176         while (offset > 0) {
51177             int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
51178             if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
51179                 return DRWAV_FALSE;
51180             }
51181             pWav->bytesRemaining -= offset32;
51182             offset -= offset32;
51183         }
51184     }
51185     return DRWAV_TRUE;
51186 }
51187 DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
51188 {
51189     size_t bytesWritten;
51190     if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
51191         return 0;
51192     }
51193     bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
51194     pWav->dataChunkDataSize += bytesWritten;
51195     return bytesWritten;
51196 }
51197 DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
51198 {
51199     drwav_uint64 bytesToWrite;
51200     drwav_uint64 bytesWritten;
51201     const drwav_uint8* pRunningData;
51202     if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
51203         return 0;
51204     }
51205     bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
51206     if (bytesToWrite > DRWAV_SIZE_MAX) {
51207         return 0;
51208     }
51209     bytesWritten = 0;
51210     pRunningData = (const drwav_uint8*)pData;
51211     while (bytesToWrite > 0) {
51212         size_t bytesJustWritten;
51213         drwav_uint64 bytesToWriteThisIteration;
51214         bytesToWriteThisIteration = bytesToWrite;
51215         DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);
51216         bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
51217         if (bytesJustWritten == 0) {
51218             break;
51219         }
51220         bytesToWrite -= bytesJustWritten;
51221         bytesWritten += bytesJustWritten;
51222         pRunningData += bytesJustWritten;
51223     }
51224     return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
51225 }
51226 DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
51227 {
51228     drwav_uint64 bytesToWrite;
51229     drwav_uint64 bytesWritten;
51230     drwav_uint32 bytesPerSample;
51231     const drwav_uint8* pRunningData;
51232     if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
51233         return 0;
51234     }
51235     bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
51236     if (bytesToWrite > DRWAV_SIZE_MAX) {
51237         return 0;
51238     }
51239     bytesWritten = 0;
51240     pRunningData = (const drwav_uint8*)pData;
51241     bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
51242     while (bytesToWrite > 0) {
51243         drwav_uint8 temp[4096];
51244         drwav_uint32 sampleCount;
51245         size_t bytesJustWritten;
51246         drwav_uint64 bytesToWriteThisIteration;
51247         bytesToWriteThisIteration = bytesToWrite;
51248         DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX);
51249         sampleCount = sizeof(temp)/bytesPerSample;
51250         if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
51251             bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
51252         }
51253         DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
51254         drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag);
51255         bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
51256         if (bytesJustWritten == 0) {
51257             break;
51258         }
51259         bytesToWrite -= bytesJustWritten;
51260         bytesWritten += bytesJustWritten;
51261         pRunningData += bytesJustWritten;
51262     }
51263     return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
51264 }
51265 DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
51266 {
51267     if (drwav__is_little_endian()) {
51268         return drwav_write_pcm_frames_le(pWav, framesToWrite, pData);
51269     } else {
51270         return drwav_write_pcm_frames_be(pWav, framesToWrite, pData);
51271     }
51272 }
51273 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51274 {
51275     drwav_uint64 totalFramesRead = 0;
51276     DRWAV_ASSERT(pWav != NULL);
51277     DRWAV_ASSERT(framesToRead > 0);
51278     while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
51279         DRWAV_ASSERT(framesToRead > 0);
51280         if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
51281             if (pWav->channels == 1) {
51282                 drwav_uint8 header[7];
51283                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
51284                     return totalFramesRead;
51285                 }
51286                 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
51287                 pWav->msadpcm.predictor[0]     = header[0];
51288                 pWav->msadpcm.delta[0]         = drwav_bytes_to_s16(header + 1);
51289                 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 3);
51290                 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 5);
51291                 pWav->msadpcm.cachedFrames[2]  = pWav->msadpcm.prevFrames[0][0];
51292                 pWav->msadpcm.cachedFrames[3]  = pWav->msadpcm.prevFrames[0][1];
51293                 pWav->msadpcm.cachedFrameCount = 2;
51294             } else {
51295                 drwav_uint8 header[14];
51296                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
51297                     return totalFramesRead;
51298                 }
51299                 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
51300                 pWav->msadpcm.predictor[0] = header[0];
51301                 pWav->msadpcm.predictor[1] = header[1];
51302                 pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 2);
51303                 pWav->msadpcm.delta[1] = drwav_bytes_to_s16(header + 4);
51304                 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 6);
51305                 pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav_bytes_to_s16(header + 8);
51306                 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 10);
51307                 pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav_bytes_to_s16(header + 12);
51308                 pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0];
51309                 pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0];
51310                 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
51311                 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
51312                 pWav->msadpcm.cachedFrameCount = 2;
51313             }
51314         }
51315         while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
51316             if (pBufferOut != NULL) {
51317                 drwav_uint32 iSample = 0;
51318                 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
51319                     pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample];
51320                 }
51321                 pBufferOut += pWav->channels;
51322             }
51323             framesToRead    -= 1;
51324             totalFramesRead += 1;
51325             pWav->compressed.iCurrentPCMFrame += 1;
51326             pWav->msadpcm.cachedFrameCount -= 1;
51327         }
51328         if (framesToRead == 0) {
51329             break;
51330         }
51331         if (pWav->msadpcm.cachedFrameCount == 0) {
51332             if (pWav->msadpcm.bytesRemainingInBlock == 0) {
51333                 continue;
51334             } else {
51335                 static drwav_int32 adaptationTable[] = {
51336                     230, 230, 230, 230, 307, 409, 512, 614,
51337                     768, 614, 512, 409, 307, 230, 230, 230
51338                 };
51339                 static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460,  392 };
51340                 static drwav_int32 coeff2Table[] = { 0,  -256, 0, 64,  0,  -208, -232 };
51341                 drwav_uint8 nibbles;
51342                 drwav_int32 nibble0;
51343                 drwav_int32 nibble1;
51344                 if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
51345                     return totalFramesRead;
51346                 }
51347                 pWav->msadpcm.bytesRemainingInBlock -= 1;
51348                 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
51349                 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
51350                 if (pWav->channels == 1) {
51351                     drwav_int32 newSample0;
51352                     drwav_int32 newSample1;
51353                     newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
51354                     newSample0 += nibble0 * pWav->msadpcm.delta[0];
51355                     newSample0  = drwav_clamp(newSample0, -32768, 32767);
51356                     pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
51357                     if (pWav->msadpcm.delta[0] < 16) {
51358                         pWav->msadpcm.delta[0] = 16;
51359                     }
51360                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
51361                     pWav->msadpcm.prevFrames[0][1] = newSample0;
51362                     newSample1  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
51363                     newSample1 += nibble1 * pWav->msadpcm.delta[0];
51364                     newSample1  = drwav_clamp(newSample1, -32768, 32767);
51365                     pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
51366                     if (pWav->msadpcm.delta[0] < 16) {
51367                         pWav->msadpcm.delta[0] = 16;
51368                     }
51369                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
51370                     pWav->msadpcm.prevFrames[0][1] = newSample1;
51371                     pWav->msadpcm.cachedFrames[2] = newSample0;
51372                     pWav->msadpcm.cachedFrames[3] = newSample1;
51373                     pWav->msadpcm.cachedFrameCount = 2;
51374                 } else {
51375                     drwav_int32 newSample0;
51376                     drwav_int32 newSample1;
51377                     newSample0  = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
51378                     newSample0 += nibble0 * pWav->msadpcm.delta[0];
51379                     newSample0  = drwav_clamp(newSample0, -32768, 32767);
51380                     pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
51381                     if (pWav->msadpcm.delta[0] < 16) {
51382                         pWav->msadpcm.delta[0] = 16;
51383                     }
51384                     pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
51385                     pWav->msadpcm.prevFrames[0][1] = newSample0;
51386                     newSample1  = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
51387                     newSample1 += nibble1 * pWav->msadpcm.delta[1];
51388                     newSample1  = drwav_clamp(newSample1, -32768, 32767);
51389                     pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
51390                     if (pWav->msadpcm.delta[1] < 16) {
51391                         pWav->msadpcm.delta[1] = 16;
51392                     }
51393                     pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
51394                     pWav->msadpcm.prevFrames[1][1] = newSample1;
51395                     pWav->msadpcm.cachedFrames[2] = newSample0;
51396                     pWav->msadpcm.cachedFrames[3] = newSample1;
51397                     pWav->msadpcm.cachedFrameCount = 1;
51398                 }
51399             }
51400         }
51401     }
51402     return totalFramesRead;
51403 }
51404 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51405 {
51406     drwav_uint64 totalFramesRead = 0;
51407     drwav_uint32 iChannel;
51408     static drwav_int32 indexTable[16] = {
51409         -1, -1, -1, -1, 2, 4, 6, 8,
51410         -1, -1, -1, -1, 2, 4, 6, 8
51411     };
51412     static drwav_int32 stepTable[89] = {
51413         7,     8,     9,     10,    11,    12,    13,    14,    16,    17,
51414         19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
51415         50,    55,    60,    66,    73,    80,    88,    97,    107,   118,
51416         130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
51417         337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
51418         876,   963,   1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066,
51419         2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
51420         5894,  6484,  7132,  7845,  8630,  9493,  10442, 11487, 12635, 13899,
51421         15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
51422     };
51423     DRWAV_ASSERT(pWav != NULL);
51424     DRWAV_ASSERT(framesToRead > 0);
51425     while (pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
51426         DRWAV_ASSERT(framesToRead > 0);
51427         if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
51428             if (pWav->channels == 1) {
51429                 drwav_uint8 header[4];
51430                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
51431                     return totalFramesRead;
51432                 }
51433                 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
51434                 if (header[2] >= drwav_countof(stepTable)) {
51435                     pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
51436                     pWav->ima.bytesRemainingInBlock = 0;
51437                     return totalFramesRead;
51438                 }
51439                 pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
51440                 pWav->ima.stepIndex[0] = header[2];
51441                 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0];
51442                 pWav->ima.cachedFrameCount = 1;
51443             } else {
51444                 drwav_uint8 header[8];
51445                 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
51446                     return totalFramesRead;
51447                 }
51448                 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
51449                 if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
51450                     pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
51451                     pWav->ima.bytesRemainingInBlock = 0;
51452                     return totalFramesRead;
51453                 }
51454                 pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
51455                 pWav->ima.stepIndex[0] = header[2];
51456                 pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4);
51457                 pWav->ima.stepIndex[1] = header[6];
51458                 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0];
51459                 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1];
51460                 pWav->ima.cachedFrameCount = 1;
51461             }
51462         }
51463         while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) {
51464             if (pBufferOut != NULL) {
51465                 drwav_uint32 iSample;
51466                 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
51467                     pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample];
51468                 }
51469                 pBufferOut += pWav->channels;
51470             }
51471             framesToRead    -= 1;
51472             totalFramesRead += 1;
51473             pWav->compressed.iCurrentPCMFrame += 1;
51474             pWav->ima.cachedFrameCount -= 1;
51475         }
51476         if (framesToRead == 0) {
51477             break;
51478         }
51479         if (pWav->ima.cachedFrameCount == 0) {
51480             if (pWav->ima.bytesRemainingInBlock == 0) {
51481                 continue;
51482             } else {
51483                 pWav->ima.cachedFrameCount = 8;
51484                 for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
51485                     drwav_uint32 iByte;
51486                     drwav_uint8 nibbles[4];
51487                     if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
51488                         pWav->ima.cachedFrameCount = 0;
51489                         return totalFramesRead;
51490                     }
51491                     pWav->ima.bytesRemainingInBlock -= 4;
51492                     for (iByte = 0; iByte < 4; ++iByte) {
51493                         drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
51494                         drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
51495                         drwav_int32 step      = stepTable[pWav->ima.stepIndex[iChannel]];
51496                         drwav_int32 predictor = pWav->ima.predictor[iChannel];
51497                         drwav_int32      diff  = step >> 3;
51498                         if (nibble0 & 1) diff += step >> 2;
51499                         if (nibble0 & 2) diff += step >> 1;
51500                         if (nibble0 & 4) diff += step;
51501                         if (nibble0 & 8) diff  = -diff;
51502                         predictor = drwav_clamp(predictor + diff, -32768, 32767);
51503                         pWav->ima.predictor[iChannel] = predictor;
51504                         pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
51505                         pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
51506                         step      = stepTable[pWav->ima.stepIndex[iChannel]];
51507                         predictor = pWav->ima.predictor[iChannel];
51508                                          diff  = step >> 3;
51509                         if (nibble1 & 1) diff += step >> 2;
51510                         if (nibble1 & 2) diff += step >> 1;
51511                         if (nibble1 & 4) diff += step;
51512                         if (nibble1 & 8) diff  = -diff;
51513                         predictor = drwav_clamp(predictor + diff, -32768, 32767);
51514                         pWav->ima.predictor[iChannel] = predictor;
51515                         pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
51516                         pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
51517                     }
51518                 }
51519             }
51520         }
51521     }
51522     return totalFramesRead;
51523 }
51524 #ifndef DR_WAV_NO_CONVERSION_API
51525 static unsigned short g_drwavAlawTable[256] = {
51526     0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
51527     0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
51528     0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
51529     0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
51530     0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
51531     0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
51532     0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
51533     0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
51534     0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
51535     0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
51536     0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
51537     0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
51538     0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
51539     0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
51540     0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
51541     0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
51542 };
51543 static unsigned short g_drwavMulawTable[256] = {
51544     0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
51545     0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
51546     0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
51547     0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
51548     0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
51549     0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
51550     0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
51551     0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
51552     0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
51553     0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
51554     0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
51555     0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
51556     0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
51557     0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
51558     0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
51559     0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
51560 };
51561 static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
51562 {
51563     return (short)g_drwavAlawTable[sampleIn];
51564 }
51565 static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
51566 {
51567     return (short)g_drwavMulawTable[sampleIn];
51568 }
51569 DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
51570 {
51571     unsigned int i;
51572     if (bytesPerSample == 1) {
51573         drwav_u8_to_s16(pOut, pIn, totalSampleCount);
51574         return;
51575     }
51576     if (bytesPerSample == 2) {
51577         for (i = 0; i < totalSampleCount; ++i) {
51578            *pOut++ = ((const drwav_int16*)pIn)[i];
51579         }
51580         return;
51581     }
51582     if (bytesPerSample == 3) {
51583         drwav_s24_to_s16(pOut, pIn, totalSampleCount);
51584         return;
51585     }
51586     if (bytesPerSample == 4) {
51587         drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
51588         return;
51589     }
51590     if (bytesPerSample > 8) {
51591         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
51592         return;
51593     }
51594     for (i = 0; i < totalSampleCount; ++i) {
51595         drwav_uint64 sample = 0;
51596         unsigned int shift  = (8 - bytesPerSample) * 8;
51597         unsigned int j;
51598         for (j = 0; j < bytesPerSample; j += 1) {
51599             DRWAV_ASSERT(j < 8);
51600             sample |= (drwav_uint64)(pIn[j]) << shift;
51601             shift  += 8;
51602         }
51603         pIn += j;
51604         *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
51605     }
51606 }
51607 DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
51608 {
51609     if (bytesPerSample == 4) {
51610         drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount);
51611         return;
51612     } else if (bytesPerSample == 8) {
51613         drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount);
51614         return;
51615     } else {
51616         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
51617         return;
51618     }
51619 }
51620 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51621 {
51622     drwav_uint64 totalFramesRead;
51623     drwav_uint8 sampleData[4096];
51624     drwav_uint32 bytesPerFrame;
51625     if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) {
51626         return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
51627     }
51628     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51629     if (bytesPerFrame == 0) {
51630         return 0;
51631     }
51632     totalFramesRead = 0;
51633     while (framesToRead > 0) {
51634         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
51635         if (framesRead == 0) {
51636             break;
51637         }
51638         drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
51639         pBufferOut      += framesRead*pWav->channels;
51640         framesToRead    -= framesRead;
51641         totalFramesRead += framesRead;
51642     }
51643     return totalFramesRead;
51644 }
51645 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51646 {
51647     drwav_uint64 totalFramesRead;
51648     drwav_uint8 sampleData[4096];
51649     drwav_uint32 bytesPerFrame;
51650     if (pBufferOut == NULL) {
51651         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
51652     }
51653     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51654     if (bytesPerFrame == 0) {
51655         return 0;
51656     }
51657     totalFramesRead = 0;
51658     while (framesToRead > 0) {
51659         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
51660         if (framesRead == 0) {
51661             break;
51662         }
51663         drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
51664         pBufferOut      += framesRead*pWav->channels;
51665         framesToRead    -= framesRead;
51666         totalFramesRead += framesRead;
51667     }
51668     return totalFramesRead;
51669 }
51670 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51671 {
51672     drwav_uint64 totalFramesRead;
51673     drwav_uint8 sampleData[4096];
51674     drwav_uint32 bytesPerFrame;
51675     if (pBufferOut == NULL) {
51676         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
51677     }
51678     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51679     if (bytesPerFrame == 0) {
51680         return 0;
51681     }
51682     totalFramesRead = 0;
51683     while (framesToRead > 0) {
51684         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
51685         if (framesRead == 0) {
51686             break;
51687         }
51688         drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
51689         pBufferOut      += framesRead*pWav->channels;
51690         framesToRead    -= framesRead;
51691         totalFramesRead += framesRead;
51692     }
51693     return totalFramesRead;
51694 }
51695 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51696 {
51697     drwav_uint64 totalFramesRead;
51698     drwav_uint8 sampleData[4096];
51699     drwav_uint32 bytesPerFrame;
51700     if (pBufferOut == NULL) {
51701         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
51702     }
51703     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51704     if (bytesPerFrame == 0) {
51705         return 0;
51706     }
51707     totalFramesRead = 0;
51708     while (framesToRead > 0) {
51709         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
51710         if (framesRead == 0) {
51711             break;
51712         }
51713         drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
51714         pBufferOut      += framesRead*pWav->channels;
51715         framesToRead    -= framesRead;
51716         totalFramesRead += framesRead;
51717     }
51718     return totalFramesRead;
51719 }
51720 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51721 {
51722     if (pWav == NULL || framesToRead == 0) {
51723         return 0;
51724     }
51725     if (pBufferOut == NULL) {
51726         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
51727     }
51728     if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) {
51729         framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels;
51730     }
51731     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
51732         return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
51733     }
51734     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
51735         return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
51736     }
51737     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
51738         return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
51739     }
51740     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
51741         return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
51742     }
51743     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
51744         return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
51745     }
51746     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
51747         return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
51748     }
51749     return 0;
51750 }
51751 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51752 {
51753     drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
51754     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
51755         drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
51756     }
51757     return framesRead;
51758 }
51759 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
51760 {
51761     drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
51762     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
51763         drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
51764     }
51765     return framesRead;
51766 }
51767 DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
51768 {
51769     int r;
51770     size_t i;
51771     for (i = 0; i < sampleCount; ++i) {
51772         int x = pIn[i];
51773         r = x << 8;
51774         r = r - 32768;
51775         pOut[i] = (short)r;
51776     }
51777 }
51778 DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
51779 {
51780     int r;
51781     size_t i;
51782     for (i = 0; i < sampleCount; ++i) {
51783         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;
51784         r = x >> 8;
51785         pOut[i] = (short)r;
51786     }
51787 }
51788 DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
51789 {
51790     int r;
51791     size_t i;
51792     for (i = 0; i < sampleCount; ++i) {
51793         int x = pIn[i];
51794         r = x >> 16;
51795         pOut[i] = (short)r;
51796     }
51797 }
51798 DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
51799 {
51800     int r;
51801     size_t i;
51802     for (i = 0; i < sampleCount; ++i) {
51803         float x = pIn[i];
51804         float c;
51805         c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
51806         c = c + 1;
51807         r = (int)(c * 32767.5f);
51808         r = r - 32768;
51809         pOut[i] = (short)r;
51810     }
51811 }
51812 DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
51813 {
51814     int r;
51815     size_t i;
51816     for (i = 0; i < sampleCount; ++i) {
51817         double x = pIn[i];
51818         double c;
51819         c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
51820         c = c + 1;
51821         r = (int)(c * 32767.5);
51822         r = r - 32768;
51823         pOut[i] = (short)r;
51824     }
51825 }
51826 DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
51827 {
51828     size_t i;
51829     for (i = 0; i < sampleCount; ++i) {
51830         pOut[i] = drwav__alaw_to_s16(pIn[i]);
51831     }
51832 }
51833 DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
51834 {
51835     size_t i;
51836     for (i = 0; i < sampleCount; ++i) {
51837         pOut[i] = drwav__mulaw_to_s16(pIn[i]);
51838     }
51839 }
51840 DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
51841 {
51842     unsigned int i;
51843     if (bytesPerSample == 1) {
51844         drwav_u8_to_f32(pOut, pIn, sampleCount);
51845         return;
51846     }
51847     if (bytesPerSample == 2) {
51848         drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
51849         return;
51850     }
51851     if (bytesPerSample == 3) {
51852         drwav_s24_to_f32(pOut, pIn, sampleCount);
51853         return;
51854     }
51855     if (bytesPerSample == 4) {
51856         drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
51857         return;
51858     }
51859     if (bytesPerSample > 8) {
51860         DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
51861         return;
51862     }
51863     for (i = 0; i < sampleCount; ++i) {
51864         drwav_uint64 sample = 0;
51865         unsigned int shift  = (8 - bytesPerSample) * 8;
51866         unsigned int j;
51867         for (j = 0; j < bytesPerSample; j += 1) {
51868             DRWAV_ASSERT(j < 8);
51869             sample |= (drwav_uint64)(pIn[j]) << shift;
51870             shift  += 8;
51871         }
51872         pIn += j;
51873         *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
51874     }
51875 }
51876 DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
51877 {
51878     if (bytesPerSample == 4) {
51879         unsigned int i;
51880         for (i = 0; i < sampleCount; ++i) {
51881             *pOut++ = ((const float*)pIn)[i];
51882         }
51883         return;
51884     } else if (bytesPerSample == 8) {
51885         drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount);
51886         return;
51887     } else {
51888         DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
51889         return;
51890     }
51891 }
51892 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
51893 {
51894     drwav_uint64 totalFramesRead;
51895     drwav_uint8 sampleData[4096];
51896     drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51897     if (bytesPerFrame == 0) {
51898         return 0;
51899     }
51900     totalFramesRead = 0;
51901     while (framesToRead > 0) {
51902         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
51903         if (framesRead == 0) {
51904             break;
51905         }
51906         drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels);
51907         pBufferOut      += framesRead*pWav->channels;
51908         framesToRead    -= framesRead;
51909         totalFramesRead += framesRead;
51910     }
51911     return totalFramesRead;
51912 }
51913 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
51914 {
51915     drwav_uint64 totalFramesRead = 0;
51916     drwav_int16 samples16[2048];
51917     while (framesToRead > 0) {
51918         drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
51919         if (framesRead == 0) {
51920             break;
51921         }
51922         drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));
51923         pBufferOut      += framesRead*pWav->channels;
51924         framesToRead    -= framesRead;
51925         totalFramesRead += framesRead;
51926     }
51927     return totalFramesRead;
51928 }
51929 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
51930 {
51931     drwav_uint64 totalFramesRead = 0;
51932     drwav_int16 samples16[2048];
51933     while (framesToRead > 0) {
51934         drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
51935         if (framesRead == 0) {
51936             break;
51937         }
51938         drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));
51939         pBufferOut      += framesRead*pWav->channels;
51940         framesToRead    -= framesRead;
51941         totalFramesRead += framesRead;
51942     }
51943     return totalFramesRead;
51944 }
51945 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
51946 {
51947     drwav_uint64 totalFramesRead;
51948     drwav_uint8 sampleData[4096];
51949     drwav_uint32 bytesPerFrame;
51950     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
51951         return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
51952     }
51953     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51954     if (bytesPerFrame == 0) {
51955         return 0;
51956     }
51957     totalFramesRead = 0;
51958     while (framesToRead > 0) {
51959         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
51960         if (framesRead == 0) {
51961             break;
51962         }
51963         drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
51964         pBufferOut      += framesRead*pWav->channels;
51965         framesToRead    -= framesRead;
51966         totalFramesRead += framesRead;
51967     }
51968     return totalFramesRead;
51969 }
51970 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
51971 {
51972     drwav_uint64 totalFramesRead;
51973     drwav_uint8 sampleData[4096];
51974     drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51975     if (bytesPerFrame == 0) {
51976         return 0;
51977     }
51978     totalFramesRead = 0;
51979     while (framesToRead > 0) {
51980         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
51981         if (framesRead == 0) {
51982             break;
51983         }
51984         drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
51985         pBufferOut      += framesRead*pWav->channels;
51986         framesToRead    -= framesRead;
51987         totalFramesRead += framesRead;
51988     }
51989     return totalFramesRead;
51990 }
51991 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
51992 {
51993     drwav_uint64 totalFramesRead;
51994     drwav_uint8 sampleData[4096];
51995     drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
51996     if (bytesPerFrame == 0) {
51997         return 0;
51998     }
51999     totalFramesRead = 0;
52000     while (framesToRead > 0) {
52001         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
52002         if (framesRead == 0) {
52003             break;
52004         }
52005         drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
52006         pBufferOut      += framesRead*pWav->channels;
52007         framesToRead    -= framesRead;
52008         totalFramesRead += framesRead;
52009     }
52010     return totalFramesRead;
52011 }
52012 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
52013 {
52014     if (pWav == NULL || framesToRead == 0) {
52015         return 0;
52016     }
52017     if (pBufferOut == NULL) {
52018         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
52019     }
52020     if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) {
52021         framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels;
52022     }
52023     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
52024         return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
52025     }
52026     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
52027         return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut);
52028     }
52029     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
52030         return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
52031     }
52032     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
52033         return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
52034     }
52035     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
52036         return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
52037     }
52038     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
52039         return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut);
52040     }
52041     return 0;
52042 }
52043 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
52044 {
52045     drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
52046     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
52047         drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
52048     }
52049     return framesRead;
52050 }
52051 DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
52052 {
52053     drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
52054     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
52055         drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
52056     }
52057     return framesRead;
52058 }
52059 DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
52060 {
52061     size_t i;
52062     if (pOut == NULL || pIn == NULL) {
52063         return;
52064     }
52065 #ifdef DR_WAV_LIBSNDFILE_COMPAT
52066     for (i = 0; i < sampleCount; ++i) {
52067         *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
52068     }
52069 #else
52070     for (i = 0; i < sampleCount; ++i) {
52071         float x = pIn[i];
52072         x = x * 0.00784313725490196078f;
52073         x = x - 1;
52074         *pOut++ = x;
52075     }
52076 #endif
52077 }
52078 DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
52079 {
52080     size_t i;
52081     if (pOut == NULL || pIn == NULL) {
52082         return;
52083     }
52084     for (i = 0; i < sampleCount; ++i) {
52085         *pOut++ = pIn[i] * 0.000030517578125f;
52086     }
52087 }
52088 DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
52089 {
52090     size_t i;
52091     if (pOut == NULL || pIn == NULL) {
52092         return;
52093     }
52094     for (i = 0; i < sampleCount; ++i) {
52095         double x;
52096         drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) <<  8);
52097         drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16);
52098         drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24);
52099         x = (double)((drwav_int32)(a | b | c) >> 8);
52100         *pOut++ = (float)(x * 0.00000011920928955078125);
52101     }
52102 }
52103 DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
52104 {
52105     size_t i;
52106     if (pOut == NULL || pIn == NULL) {
52107         return;
52108     }
52109     for (i = 0; i < sampleCount; ++i) {
52110         *pOut++ = (float)(pIn[i] / 2147483648.0);
52111     }
52112 }
52113 DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
52114 {
52115     size_t i;
52116     if (pOut == NULL || pIn == NULL) {
52117         return;
52118     }
52119     for (i = 0; i < sampleCount; ++i) {
52120         *pOut++ = (float)pIn[i];
52121     }
52122 }
52123 DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
52124 {
52125     size_t i;
52126     if (pOut == NULL || pIn == NULL) {
52127         return;
52128     }
52129     for (i = 0; i < sampleCount; ++i) {
52130         *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
52131     }
52132 }
52133 DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
52134 {
52135     size_t i;
52136     if (pOut == NULL || pIn == NULL) {
52137         return;
52138     }
52139     for (i = 0; i < sampleCount; ++i) {
52140         *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
52141     }
52142 }
52143 DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
52144 {
52145     unsigned int i;
52146     if (bytesPerSample == 1) {
52147         drwav_u8_to_s32(pOut, pIn, totalSampleCount);
52148         return;
52149     }
52150     if (bytesPerSample == 2) {
52151         drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
52152         return;
52153     }
52154     if (bytesPerSample == 3) {
52155         drwav_s24_to_s32(pOut, pIn, totalSampleCount);
52156         return;
52157     }
52158     if (bytesPerSample == 4) {
52159         for (i = 0; i < totalSampleCount; ++i) {
52160            *pOut++ = ((const drwav_int32*)pIn)[i];
52161         }
52162         return;
52163     }
52164     if (bytesPerSample > 8) {
52165         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
52166         return;
52167     }
52168     for (i = 0; i < totalSampleCount; ++i) {
52169         drwav_uint64 sample = 0;
52170         unsigned int shift  = (8 - bytesPerSample) * 8;
52171         unsigned int j;
52172         for (j = 0; j < bytesPerSample; j += 1) {
52173             DRWAV_ASSERT(j < 8);
52174             sample |= (drwav_uint64)(pIn[j]) << shift;
52175             shift  += 8;
52176         }
52177         pIn += j;
52178         *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
52179     }
52180 }
52181 DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
52182 {
52183     if (bytesPerSample == 4) {
52184         drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount);
52185         return;
52186     } else if (bytesPerSample == 8) {
52187         drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount);
52188         return;
52189     } else {
52190         DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
52191         return;
52192     }
52193 }
52194 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52195 {
52196     drwav_uint64 totalFramesRead;
52197     drwav_uint8 sampleData[4096];
52198     drwav_uint32 bytesPerFrame;
52199     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
52200         return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
52201     }
52202     bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
52203     if (bytesPerFrame == 0) {
52204         return 0;
52205     }
52206     totalFramesRead = 0;
52207     while (framesToRead > 0) {
52208         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
52209         if (framesRead == 0) {
52210             break;
52211         }
52212         drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
52213         pBufferOut      += framesRead*pWav->channels;
52214         framesToRead    -= framesRead;
52215         totalFramesRead += framesRead;
52216     }
52217     return totalFramesRead;
52218 }
52219 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52220 {
52221     drwav_uint64 totalFramesRead = 0;
52222     drwav_int16 samples16[2048];
52223     while (framesToRead > 0) {
52224         drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
52225         if (framesRead == 0) {
52226             break;
52227         }
52228         drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));
52229         pBufferOut      += framesRead*pWav->channels;
52230         framesToRead    -= framesRead;
52231         totalFramesRead += framesRead;
52232     }
52233     return totalFramesRead;
52234 }
52235 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52236 {
52237     drwav_uint64 totalFramesRead = 0;
52238     drwav_int16 samples16[2048];
52239     while (framesToRead > 0) {
52240         drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16);
52241         if (framesRead == 0) {
52242             break;
52243         }
52244         drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels));
52245         pBufferOut      += framesRead*pWav->channels;
52246         framesToRead    -= framesRead;
52247         totalFramesRead += framesRead;
52248     }
52249     return totalFramesRead;
52250 }
52251 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52252 {
52253     drwav_uint64 totalFramesRead;
52254     drwav_uint8 sampleData[4096];
52255     drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
52256     if (bytesPerFrame == 0) {
52257         return 0;
52258     }
52259     totalFramesRead = 0;
52260     while (framesToRead > 0) {
52261         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
52262         if (framesRead == 0) {
52263             break;
52264         }
52265         drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels);
52266         pBufferOut      += framesRead*pWav->channels;
52267         framesToRead    -= framesRead;
52268         totalFramesRead += framesRead;
52269     }
52270     return totalFramesRead;
52271 }
52272 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52273 {
52274     drwav_uint64 totalFramesRead;
52275     drwav_uint8 sampleData[4096];
52276     drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
52277     if (bytesPerFrame == 0) {
52278         return 0;
52279     }
52280     totalFramesRead = 0;
52281     while (framesToRead > 0) {
52282         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
52283         if (framesRead == 0) {
52284             break;
52285         }
52286         drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
52287         pBufferOut      += framesRead*pWav->channels;
52288         framesToRead    -= framesRead;
52289         totalFramesRead += framesRead;
52290     }
52291     return totalFramesRead;
52292 }
52293 DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52294 {
52295     drwav_uint64 totalFramesRead;
52296     drwav_uint8 sampleData[4096];
52297     drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
52298     if (bytesPerFrame == 0) {
52299         return 0;
52300     }
52301     totalFramesRead = 0;
52302     while (framesToRead > 0) {
52303         drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData);
52304         if (framesRead == 0) {
52305             break;
52306         }
52307         drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels));
52308         pBufferOut      += framesRead*pWav->channels;
52309         framesToRead    -= framesRead;
52310         totalFramesRead += framesRead;
52311     }
52312     return totalFramesRead;
52313 }
52314 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52315 {
52316     if (pWav == NULL || framesToRead == 0) {
52317         return 0;
52318     }
52319     if (pBufferOut == NULL) {
52320         return drwav_read_pcm_frames(pWav, framesToRead, NULL);
52321     }
52322     if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) {
52323         framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels;
52324     }
52325     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
52326         return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
52327     }
52328     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
52329         return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut);
52330     }
52331     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
52332         return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
52333     }
52334     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
52335         return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
52336     }
52337     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
52338         return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
52339     }
52340     if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
52341         return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut);
52342     }
52343     return 0;
52344 }
52345 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52346 {
52347     drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
52348     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
52349         drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
52350     }
52351     return framesRead;
52352 }
52353 DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
52354 {
52355     drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
52356     if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
52357         drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
52358     }
52359     return framesRead;
52360 }
52361 DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
52362 {
52363     size_t i;
52364     if (pOut == NULL || pIn == NULL) {
52365         return;
52366     }
52367     for (i = 0; i < sampleCount; ++i) {
52368         *pOut++ = ((int)pIn[i] - 128) << 24;
52369     }
52370 }
52371 DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
52372 {
52373     size_t i;
52374     if (pOut == NULL || pIn == NULL) {
52375         return;
52376     }
52377     for (i = 0; i < sampleCount; ++i) {
52378         *pOut++ = pIn[i] << 16;
52379     }
52380 }
52381 DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
52382 {
52383     size_t i;
52384     if (pOut == NULL || pIn == NULL) {
52385         return;
52386     }
52387     for (i = 0; i < sampleCount; ++i) {
52388         unsigned int s0 = pIn[i*3 + 0];
52389         unsigned int s1 = pIn[i*3 + 1];
52390         unsigned int s2 = pIn[i*3 + 2];
52391         drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
52392         *pOut++ = sample32;
52393     }
52394 }
52395 DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
52396 {
52397     size_t i;
52398     if (pOut == NULL || pIn == NULL) {
52399         return;
52400     }
52401     for (i = 0; i < sampleCount; ++i) {
52402         *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
52403     }
52404 }
52405 DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
52406 {
52407     size_t i;
52408     if (pOut == NULL || pIn == NULL) {
52409         return;
52410     }
52411     for (i = 0; i < sampleCount; ++i) {
52412         *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
52413     }
52414 }
52415 DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
52416 {
52417     size_t i;
52418     if (pOut == NULL || pIn == NULL) {
52419         return;
52420     }
52421     for (i = 0; i < sampleCount; ++i) {
52422         *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
52423     }
52424 }
52425 DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
52426 {
52427     size_t i;
52428     if (pOut == NULL || pIn == NULL) {
52429         return;
52430     }
52431     for (i= 0; i < sampleCount; ++i) {
52432         *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
52433     }
52434 }
52435 DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
52436 {
52437     drwav_uint64 sampleDataSize;
52438     drwav_int16* pSampleData;
52439     drwav_uint64 framesRead;
52440     DRWAV_ASSERT(pWav != NULL);
52441     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
52442     if (sampleDataSize > DRWAV_SIZE_MAX) {
52443         drwav_uninit(pWav);
52444         return NULL;
52445     }
52446     pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
52447     if (pSampleData == NULL) {
52448         drwav_uninit(pWav);
52449         return NULL;
52450     }
52451     framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
52452     if (framesRead != pWav->totalPCMFrameCount) {
52453         drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
52454         drwav_uninit(pWav);
52455         return NULL;
52456     }
52457     drwav_uninit(pWav);
52458     if (sampleRate) {
52459         *sampleRate = pWav->sampleRate;
52460     }
52461     if (channels) {
52462         *channels = pWav->channels;
52463     }
52464     if (totalFrameCount) {
52465         *totalFrameCount = pWav->totalPCMFrameCount;
52466     }
52467     return pSampleData;
52468 }
52469 DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
52470 {
52471     drwav_uint64 sampleDataSize;
52472     float* pSampleData;
52473     drwav_uint64 framesRead;
52474     DRWAV_ASSERT(pWav != NULL);
52475     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
52476     if (sampleDataSize > DRWAV_SIZE_MAX) {
52477         drwav_uninit(pWav);
52478         return NULL;
52479     }
52480     pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
52481     if (pSampleData == NULL) {
52482         drwav_uninit(pWav);
52483         return NULL;
52484     }
52485     framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
52486     if (framesRead != pWav->totalPCMFrameCount) {
52487         drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
52488         drwav_uninit(pWav);
52489         return NULL;
52490     }
52491     drwav_uninit(pWav);
52492     if (sampleRate) {
52493         *sampleRate = pWav->sampleRate;
52494     }
52495     if (channels) {
52496         *channels = pWav->channels;
52497     }
52498     if (totalFrameCount) {
52499         *totalFrameCount = pWav->totalPCMFrameCount;
52500     }
52501     return pSampleData;
52502 }
52503 DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
52504 {
52505     drwav_uint64 sampleDataSize;
52506     drwav_int32* pSampleData;
52507     drwav_uint64 framesRead;
52508     DRWAV_ASSERT(pWav != NULL);
52509     sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
52510     if (sampleDataSize > DRWAV_SIZE_MAX) {
52511         drwav_uninit(pWav);
52512         return NULL;
52513     }
52514     pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks);
52515     if (pSampleData == NULL) {
52516         drwav_uninit(pWav);
52517         return NULL;
52518     }
52519     framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
52520     if (framesRead != pWav->totalPCMFrameCount) {
52521         drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
52522         drwav_uninit(pWav);
52523         return NULL;
52524     }
52525     drwav_uninit(pWav);
52526     if (sampleRate) {
52527         *sampleRate = pWav->sampleRate;
52528     }
52529     if (channels) {
52530         *channels = pWav->channels;
52531     }
52532     if (totalFrameCount) {
52533         *totalFrameCount = pWav->totalPCMFrameCount;
52534     }
52535     return pSampleData;
52536 }
52537 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)
52538 {
52539     drwav wav;
52540     if (channelsOut) {
52541         *channelsOut = 0;
52542     }
52543     if (sampleRateOut) {
52544         *sampleRateOut = 0;
52545     }
52546     if (totalFrameCountOut) {
52547         *totalFrameCountOut = 0;
52548     }
52549     if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
52550         return NULL;
52551     }
52552     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52553 }
52554 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)
52555 {
52556     drwav wav;
52557     if (channelsOut) {
52558         *channelsOut = 0;
52559     }
52560     if (sampleRateOut) {
52561         *sampleRateOut = 0;
52562     }
52563     if (totalFrameCountOut) {
52564         *totalFrameCountOut = 0;
52565     }
52566     if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
52567         return NULL;
52568     }
52569     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52570 }
52571 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)
52572 {
52573     drwav wav;
52574     if (channelsOut) {
52575         *channelsOut = 0;
52576     }
52577     if (sampleRateOut) {
52578         *sampleRateOut = 0;
52579     }
52580     if (totalFrameCountOut) {
52581         *totalFrameCountOut = 0;
52582     }
52583     if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
52584         return NULL;
52585     }
52586     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52587 }
52588 #ifndef DR_WAV_NO_STDIO
52589 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)
52590 {
52591     drwav wav;
52592     if (channelsOut) {
52593         *channelsOut = 0;
52594     }
52595     if (sampleRateOut) {
52596         *sampleRateOut = 0;
52597     }
52598     if (totalFrameCountOut) {
52599         *totalFrameCountOut = 0;
52600     }
52601     if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
52602         return NULL;
52603     }
52604     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52605 }
52606 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)
52607 {
52608     drwav wav;
52609     if (channelsOut) {
52610         *channelsOut = 0;
52611     }
52612     if (sampleRateOut) {
52613         *sampleRateOut = 0;
52614     }
52615     if (totalFrameCountOut) {
52616         *totalFrameCountOut = 0;
52617     }
52618     if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
52619         return NULL;
52620     }
52621     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52622 }
52623 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)
52624 {
52625     drwav wav;
52626     if (channelsOut) {
52627         *channelsOut = 0;
52628     }
52629     if (sampleRateOut) {
52630         *sampleRateOut = 0;
52631     }
52632     if (totalFrameCountOut) {
52633         *totalFrameCountOut = 0;
52634     }
52635     if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
52636         return NULL;
52637     }
52638     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52639 }
52640 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)
52641 {
52642     drwav wav;
52643     if (sampleRateOut) {
52644         *sampleRateOut = 0;
52645     }
52646     if (channelsOut) {
52647         *channelsOut = 0;
52648     }
52649     if (totalFrameCountOut) {
52650         *totalFrameCountOut = 0;
52651     }
52652     if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
52653         return NULL;
52654     }
52655     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52656 }
52657 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)
52658 {
52659     drwav wav;
52660     if (sampleRateOut) {
52661         *sampleRateOut = 0;
52662     }
52663     if (channelsOut) {
52664         *channelsOut = 0;
52665     }
52666     if (totalFrameCountOut) {
52667         *totalFrameCountOut = 0;
52668     }
52669     if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
52670         return NULL;
52671     }
52672     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52673 }
52674 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)
52675 {
52676     drwav wav;
52677     if (sampleRateOut) {
52678         *sampleRateOut = 0;
52679     }
52680     if (channelsOut) {
52681         *channelsOut = 0;
52682     }
52683     if (totalFrameCountOut) {
52684         *totalFrameCountOut = 0;
52685     }
52686     if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
52687         return NULL;
52688     }
52689     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52690 }
52691 #endif
52692 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)
52693 {
52694     drwav wav;
52695     if (channelsOut) {
52696         *channelsOut = 0;
52697     }
52698     if (sampleRateOut) {
52699         *sampleRateOut = 0;
52700     }
52701     if (totalFrameCountOut) {
52702         *totalFrameCountOut = 0;
52703     }
52704     if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
52705         return NULL;
52706     }
52707     return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52708 }
52709 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)
52710 {
52711     drwav wav;
52712     if (channelsOut) {
52713         *channelsOut = 0;
52714     }
52715     if (sampleRateOut) {
52716         *sampleRateOut = 0;
52717     }
52718     if (totalFrameCountOut) {
52719         *totalFrameCountOut = 0;
52720     }
52721     if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
52722         return NULL;
52723     }
52724     return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52725 }
52726 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)
52727 {
52728     drwav wav;
52729     if (channelsOut) {
52730         *channelsOut = 0;
52731     }
52732     if (sampleRateOut) {
52733         *sampleRateOut = 0;
52734     }
52735     if (totalFrameCountOut) {
52736         *totalFrameCountOut = 0;
52737     }
52738     if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
52739         return NULL;
52740     }
52741     return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
52742 }
52743 #endif
52744 DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
52745 {
52746     if (pAllocationCallbacks != NULL) {
52747         drwav__free_from_callbacks(p, pAllocationCallbacks);
52748     } else {
52749         drwav__free_default(p, NULL);
52750     }
52751 }
52752 DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
52753 {
52754     return (data[0] << 0) | (data[1] << 8);
52755 }
52756 DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
52757 {
52758     return (short)drwav_bytes_to_u16(data);
52759 }
52760 DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
52761 {
52762     return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
52763 }
52764 DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
52765 {
52766     return (drwav_int32)drwav_bytes_to_u32(data);
52767 }
52768 DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
52769 {
52770     return
52771         ((drwav_uint64)data[0] <<  0) | ((drwav_uint64)data[1] <<  8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
52772         ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
52773 }
52774 DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
52775 {
52776     return (drwav_int64)drwav_bytes_to_u64(data);
52777 }
52778 DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
52779 {
52780     int i;
52781     for (i = 0; i < 16; i += 1) {
52782         if (a[i] != b[i]) {
52783             return DRWAV_FALSE;
52784         }
52785     }
52786     return DRWAV_TRUE;
52787 }
52788 DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
52789 {
52790     return
52791         a[0] == b[0] &&
52792         a[1] == b[1] &&
52793         a[2] == b[2] &&
52794         a[3] == b[3];
52795 }
52796 #endif
52797 /* dr_wav_c end */
52798 #endif  /* DRWAV_IMPLEMENTATION */
52799 #endif  /* MA_NO_WAV */
52800
52801 #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING)
52802 #if !defined(DR_FLAC_IMPLEMENTATION) && !defined(DRFLAC_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
52803 /* dr_flac_c begin */
52804 #ifndef dr_flac_c
52805 #define dr_flac_c
52806 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
52807     #pragma GCC diagnostic push
52808     #if __GNUC__ >= 7
52809     #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
52810     #endif
52811 #endif
52812 #ifdef __linux__
52813     #ifndef _BSD_SOURCE
52814         #define _BSD_SOURCE
52815     #endif
52816     #ifndef _DEFAULT_SOURCE
52817         #define _DEFAULT_SOURCE
52818     #endif
52819     #ifndef __USE_BSD
52820         #define __USE_BSD
52821     #endif
52822     #include <endian.h>
52823 #endif
52824 #include <stdlib.h>
52825 #include <string.h>
52826 #ifdef _MSC_VER
52827     #define DRFLAC_INLINE __forceinline
52828 #elif defined(__GNUC__)
52829     #if defined(__STRICT_ANSI__)
52830         #define DRFLAC_INLINE __inline__ __attribute__((always_inline))
52831     #else
52832         #define DRFLAC_INLINE inline __attribute__((always_inline))
52833     #endif
52834 #elif defined(__WATCOMC__)
52835     #define DRFLAC_INLINE __inline
52836 #else
52837     #define DRFLAC_INLINE
52838 #endif
52839 #if defined(__x86_64__) || defined(_M_X64)
52840     #define DRFLAC_X64
52841 #elif defined(__i386) || defined(_M_IX86)
52842     #define DRFLAC_X86
52843 #elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64)
52844     #define DRFLAC_ARM
52845 #endif
52846 #if !defined(DR_FLAC_NO_SIMD)
52847     #if defined(DRFLAC_X64) || defined(DRFLAC_X86)
52848         #if defined(_MSC_VER) && !defined(__clang__)
52849             #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2)
52850                 #define DRFLAC_SUPPORT_SSE2
52851             #endif
52852             #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41)
52853                 #define DRFLAC_SUPPORT_SSE41
52854             #endif
52855         #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
52856             #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2)
52857                 #define DRFLAC_SUPPORT_SSE2
52858             #endif
52859             #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41)
52860                 #define DRFLAC_SUPPORT_SSE41
52861             #endif
52862         #endif
52863         #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
52864             #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include(<emmintrin.h>)
52865                 #define DRFLAC_SUPPORT_SSE2
52866             #endif
52867             #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include(<smmintrin.h>)
52868                 #define DRFLAC_SUPPORT_SSE41
52869             #endif
52870         #endif
52871         #if defined(DRFLAC_SUPPORT_SSE41)
52872             #include <smmintrin.h>
52873         #elif defined(DRFLAC_SUPPORT_SSE2)
52874             #include <emmintrin.h>
52875         #endif
52876     #endif
52877     #if defined(DRFLAC_ARM)
52878         #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
52879             #define DRFLAC_SUPPORT_NEON
52880         #endif
52881         #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
52882             #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include(<arm_neon.h>)
52883                 #define DRFLAC_SUPPORT_NEON
52884             #endif
52885         #endif
52886         #if defined(DRFLAC_SUPPORT_NEON)
52887             #include <arm_neon.h>
52888         #endif
52889     #endif
52890 #endif
52891 #if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64))
52892     #if defined(_MSC_VER) && !defined(__clang__)
52893         #if _MSC_VER >= 1400
52894             #include <intrin.h>
52895             static void drflac__cpuid(int info[4], int fid)
52896             {
52897                 __cpuid(info, fid);
52898             }
52899         #else
52900             #define DRFLAC_NO_CPUID
52901         #endif
52902     #else
52903         #if defined(__GNUC__) || defined(__clang__)
52904             static void drflac__cpuid(int info[4], int fid)
52905             {
52906                 #if defined(DRFLAC_X86) && defined(__PIC__)
52907                     __asm__ __volatile__ (
52908                         "xchg{l} {%%}ebx, %k1;"
52909                         "cpuid;"
52910                         "xchg{l} {%%}ebx, %k1;"
52911                         : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
52912                     );
52913                 #else
52914                     __asm__ __volatile__ (
52915                         "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
52916                     );
52917                 #endif
52918             }
52919         #else
52920             #define DRFLAC_NO_CPUID
52921         #endif
52922     #endif
52923 #else
52924     #define DRFLAC_NO_CPUID
52925 #endif
52926 static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void)
52927 {
52928 #if defined(DRFLAC_SUPPORT_SSE2)
52929     #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2)
52930         #if defined(DRFLAC_X64)
52931             return DRFLAC_TRUE;
52932         #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
52933             return DRFLAC_TRUE;
52934         #else
52935             #if defined(DRFLAC_NO_CPUID)
52936                 return DRFLAC_FALSE;
52937             #else
52938                 int info[4];
52939                 drflac__cpuid(info, 1);
52940                 return (info[3] & (1 << 26)) != 0;
52941             #endif
52942         #endif
52943     #else
52944         return DRFLAC_FALSE;
52945     #endif
52946 #else
52947     return DRFLAC_FALSE;
52948 #endif
52949 }
52950 static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
52951 {
52952 #if defined(DRFLAC_SUPPORT_SSE41)
52953     #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41)
52954         #if defined(DRFLAC_X64)
52955             return DRFLAC_TRUE;
52956         #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__)
52957             return DRFLAC_TRUE;
52958         #else
52959             #if defined(DRFLAC_NO_CPUID)
52960                 return DRFLAC_FALSE;
52961             #else
52962                 int info[4];
52963                 drflac__cpuid(info, 1);
52964                 return (info[2] & (1 << 19)) != 0;
52965             #endif
52966         #endif
52967     #else
52968         return DRFLAC_FALSE;
52969     #endif
52970 #else
52971     return DRFLAC_FALSE;
52972 #endif
52973 }
52974 #if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) && !defined(__clang__)
52975     #define DRFLAC_HAS_LZCNT_INTRINSIC
52976 #elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
52977     #define DRFLAC_HAS_LZCNT_INTRINSIC
52978 #elif defined(__clang__)
52979     #if defined(__has_builtin)
52980         #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl)
52981             #define DRFLAC_HAS_LZCNT_INTRINSIC
52982         #endif
52983     #endif
52984 #endif
52985 #if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__)
52986     #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
52987     #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
52988     #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
52989 #elif defined(__clang__)
52990     #if defined(__has_builtin)
52991         #if __has_builtin(__builtin_bswap16)
52992             #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
52993         #endif
52994         #if __has_builtin(__builtin_bswap32)
52995             #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
52996         #endif
52997         #if __has_builtin(__builtin_bswap64)
52998             #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
52999         #endif
53000     #endif
53001 #elif defined(__GNUC__)
53002     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
53003         #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
53004         #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
53005     #endif
53006     #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
53007         #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
53008     #endif
53009 #elif defined(__WATCOMC__) && defined(__386__)
53010     #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
53011     #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
53012     #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
53013     extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16);
53014     extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32);
53015     extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64);
53016 #pragma aux _watcom_bswap16 = \
53017     "xchg al, ah" \
53018     parm   [ax]   \
53019     modify [ax];
53020 #pragma aux _watcom_bswap32 = \
53021     "bswap eax"  \
53022     parm   [eax] \
53023     modify [eax];
53024 #pragma aux _watcom_bswap64 = \
53025     "bswap eax"     \
53026     "bswap edx"     \
53027     "xchg eax,edx"  \
53028     parm [eax edx]  \
53029     modify [eax edx];
53030 #endif
53031 #ifndef DRFLAC_ASSERT
53032 #include <assert.h>
53033 #define DRFLAC_ASSERT(expression)           assert(expression)
53034 #endif
53035 #ifndef DRFLAC_MALLOC
53036 #define DRFLAC_MALLOC(sz)                   malloc((sz))
53037 #endif
53038 #ifndef DRFLAC_REALLOC
53039 #define DRFLAC_REALLOC(p, sz)               realloc((p), (sz))
53040 #endif
53041 #ifndef DRFLAC_FREE
53042 #define DRFLAC_FREE(p)                      free((p))
53043 #endif
53044 #ifndef DRFLAC_COPY_MEMORY
53045 #define DRFLAC_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
53046 #endif
53047 #ifndef DRFLAC_ZERO_MEMORY
53048 #define DRFLAC_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
53049 #endif
53050 #ifndef DRFLAC_ZERO_OBJECT
53051 #define DRFLAC_ZERO_OBJECT(p)               DRFLAC_ZERO_MEMORY((p), sizeof(*(p)))
53052 #endif
53053 #define DRFLAC_MAX_SIMD_VECTOR_SIZE                     64
53054 typedef drflac_int32 drflac_result;
53055 #define DRFLAC_SUCCESS                                   0
53056 #define DRFLAC_ERROR                                    -1
53057 #define DRFLAC_INVALID_ARGS                             -2
53058 #define DRFLAC_INVALID_OPERATION                        -3
53059 #define DRFLAC_OUT_OF_MEMORY                            -4
53060 #define DRFLAC_OUT_OF_RANGE                             -5
53061 #define DRFLAC_ACCESS_DENIED                            -6
53062 #define DRFLAC_DOES_NOT_EXIST                           -7
53063 #define DRFLAC_ALREADY_EXISTS                           -8
53064 #define DRFLAC_TOO_MANY_OPEN_FILES                      -9
53065 #define DRFLAC_INVALID_FILE                             -10
53066 #define DRFLAC_TOO_BIG                                  -11
53067 #define DRFLAC_PATH_TOO_LONG                            -12
53068 #define DRFLAC_NAME_TOO_LONG                            -13
53069 #define DRFLAC_NOT_DIRECTORY                            -14
53070 #define DRFLAC_IS_DIRECTORY                             -15
53071 #define DRFLAC_DIRECTORY_NOT_EMPTY                      -16
53072 #define DRFLAC_END_OF_FILE                              -17
53073 #define DRFLAC_NO_SPACE                                 -18
53074 #define DRFLAC_BUSY                                     -19
53075 #define DRFLAC_IO_ERROR                                 -20
53076 #define DRFLAC_INTERRUPT                                -21
53077 #define DRFLAC_UNAVAILABLE                              -22
53078 #define DRFLAC_ALREADY_IN_USE                           -23
53079 #define DRFLAC_BAD_ADDRESS                              -24
53080 #define DRFLAC_BAD_SEEK                                 -25
53081 #define DRFLAC_BAD_PIPE                                 -26
53082 #define DRFLAC_DEADLOCK                                 -27
53083 #define DRFLAC_TOO_MANY_LINKS                           -28
53084 #define DRFLAC_NOT_IMPLEMENTED                          -29
53085 #define DRFLAC_NO_MESSAGE                               -30
53086 #define DRFLAC_BAD_MESSAGE                              -31
53087 #define DRFLAC_NO_DATA_AVAILABLE                        -32
53088 #define DRFLAC_INVALID_DATA                             -33
53089 #define DRFLAC_TIMEOUT                                  -34
53090 #define DRFLAC_NO_NETWORK                               -35
53091 #define DRFLAC_NOT_UNIQUE                               -36
53092 #define DRFLAC_NOT_SOCKET                               -37
53093 #define DRFLAC_NO_ADDRESS                               -38
53094 #define DRFLAC_BAD_PROTOCOL                             -39
53095 #define DRFLAC_PROTOCOL_UNAVAILABLE                     -40
53096 #define DRFLAC_PROTOCOL_NOT_SUPPORTED                   -41
53097 #define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED            -42
53098 #define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED             -43
53099 #define DRFLAC_SOCKET_NOT_SUPPORTED                     -44
53100 #define DRFLAC_CONNECTION_RESET                         -45
53101 #define DRFLAC_ALREADY_CONNECTED                        -46
53102 #define DRFLAC_NOT_CONNECTED                            -47
53103 #define DRFLAC_CONNECTION_REFUSED                       -48
53104 #define DRFLAC_NO_HOST                                  -49
53105 #define DRFLAC_IN_PROGRESS                              -50
53106 #define DRFLAC_CANCELLED                                -51
53107 #define DRFLAC_MEMORY_ALREADY_MAPPED                    -52
53108 #define DRFLAC_AT_END                                   -53
53109 #define DRFLAC_CRC_MISMATCH                             -128
53110 #define DRFLAC_SUBFRAME_CONSTANT                        0
53111 #define DRFLAC_SUBFRAME_VERBATIM                        1
53112 #define DRFLAC_SUBFRAME_FIXED                           8
53113 #define DRFLAC_SUBFRAME_LPC                             32
53114 #define DRFLAC_SUBFRAME_RESERVED                        255
53115 #define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE  0
53116 #define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
53117 #define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT           0
53118 #define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE             8
53119 #define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE            9
53120 #define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE              10
53121 #define drflac_align(x, a)                              ((((x) + (a) - 1) / (a)) * (a))
53122 DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision)
53123 {
53124     if (pMajor) {
53125         *pMajor = DRFLAC_VERSION_MAJOR;
53126     }
53127     if (pMinor) {
53128         *pMinor = DRFLAC_VERSION_MINOR;
53129     }
53130     if (pRevision) {
53131         *pRevision = DRFLAC_VERSION_REVISION;
53132     }
53133 }
53134 DRFLAC_API const char* drflac_version_string(void)
53135 {
53136     return DRFLAC_VERSION_STRING;
53137 }
53138 #if defined(__has_feature)
53139     #if __has_feature(thread_sanitizer)
53140         #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
53141     #else
53142         #define DRFLAC_NO_THREAD_SANITIZE
53143     #endif
53144 #else
53145     #define DRFLAC_NO_THREAD_SANITIZE
53146 #endif
53147 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
53148 static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
53149 #endif
53150 #ifndef DRFLAC_NO_CPUID
53151 static drflac_bool32 drflac__gIsSSE2Supported  = DRFLAC_FALSE;
53152 static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE;
53153 DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
53154 {
53155     static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE;
53156     if (!isCPUCapsInitialized) {
53157 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
53158         int info[4] = {0};
53159         drflac__cpuid(info, 0x80000001);
53160         drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0;
53161 #endif
53162         drflac__gIsSSE2Supported = drflac_has_sse2();
53163         drflac__gIsSSE41Supported = drflac_has_sse41();
53164         isCPUCapsInitialized = DRFLAC_TRUE;
53165     }
53166 }
53167 #else
53168 static drflac_bool32 drflac__gIsNEONSupported  = DRFLAC_FALSE;
53169 static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void)
53170 {
53171 #if defined(DRFLAC_SUPPORT_NEON)
53172     #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON)
53173         #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
53174             return DRFLAC_TRUE;
53175         #else
53176             return DRFLAC_FALSE;
53177         #endif
53178     #else
53179         return DRFLAC_FALSE;
53180     #endif
53181 #else
53182     return DRFLAC_FALSE;
53183 #endif
53184 }
53185 DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
53186 {
53187     drflac__gIsNEONSupported = drflac__has_neon();
53188 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
53189     drflac__gIsLZCNTSupported = DRFLAC_TRUE;
53190 #endif
53191 }
53192 #endif
53193 static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void)
53194 {
53195 #if defined(DRFLAC_X86) || defined(DRFLAC_X64)
53196     return DRFLAC_TRUE;
53197 #elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
53198     return DRFLAC_TRUE;
53199 #else
53200     int n = 1;
53201     return (*(char*)&n) == 1;
53202 #endif
53203 }
53204 static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n)
53205 {
53206 #ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC
53207     #if defined(_MSC_VER) && !defined(__clang__)
53208         return _byteswap_ushort(n);
53209     #elif defined(__GNUC__) || defined(__clang__)
53210         return __builtin_bswap16(n);
53211     #elif defined(__WATCOMC__) && defined(__386__)
53212         return _watcom_bswap16(n);
53213     #else
53214         #error "This compiler does not support the byte swap intrinsic."
53215     #endif
53216 #else
53217     return ((n & 0xFF00) >> 8) |
53218            ((n & 0x00FF) << 8);
53219 #endif
53220 }
53221 static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n)
53222 {
53223 #ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC
53224     #if defined(_MSC_VER) && !defined(__clang__)
53225         return _byteswap_ulong(n);
53226     #elif defined(__GNUC__) || defined(__clang__)
53227         #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRFLAC_64BIT)
53228             drflac_uint32 r;
53229             __asm__ __volatile__ (
53230             #if defined(DRFLAC_64BIT)
53231                 "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)
53232             #else
53233                 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
53234             #endif
53235             );
53236             return r;
53237         #else
53238             return __builtin_bswap32(n);
53239         #endif
53240     #elif defined(__WATCOMC__) && defined(__386__)
53241         return _watcom_bswap32(n);
53242     #else
53243         #error "This compiler does not support the byte swap intrinsic."
53244     #endif
53245 #else
53246     return ((n & 0xFF000000) >> 24) |
53247            ((n & 0x00FF0000) >>  8) |
53248            ((n & 0x0000FF00) <<  8) |
53249            ((n & 0x000000FF) << 24);
53250 #endif
53251 }
53252 static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n)
53253 {
53254 #ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC
53255     #if defined(_MSC_VER) && !defined(__clang__)
53256         return _byteswap_uint64(n);
53257     #elif defined(__GNUC__) || defined(__clang__)
53258         return __builtin_bswap64(n);
53259     #elif defined(__WATCOMC__) && defined(__386__)
53260         return _watcom_bswap64(n);
53261     #else
53262         #error "This compiler does not support the byte swap intrinsic."
53263     #endif
53264 #else
53265     return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) |
53266            ((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) |
53267            ((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) |
53268            ((n & ((drflac_uint64)0x000000FF << 32)) >>  8) |
53269            ((n & ((drflac_uint64)0xFF000000      )) <<  8) |
53270            ((n & ((drflac_uint64)0x00FF0000      )) << 24) |
53271            ((n & ((drflac_uint64)0x0000FF00      )) << 40) |
53272            ((n & ((drflac_uint64)0x000000FF      )) << 56);
53273 #endif
53274 }
53275 static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n)
53276 {
53277     if (drflac__is_little_endian()) {
53278         return drflac__swap_endian_uint16(n);
53279     }
53280     return n;
53281 }
53282 static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n)
53283 {
53284     if (drflac__is_little_endian()) {
53285         return drflac__swap_endian_uint32(n);
53286     }
53287     return n;
53288 }
53289 static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n)
53290 {
53291     if (drflac__is_little_endian()) {
53292         return drflac__swap_endian_uint64(n);
53293     }
53294     return n;
53295 }
53296 static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n)
53297 {
53298     if (!drflac__is_little_endian()) {
53299         return drflac__swap_endian_uint32(n);
53300     }
53301     return n;
53302 }
53303 static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n)
53304 {
53305     drflac_uint32 result = 0;
53306     result |= (n & 0x7F000000) >> 3;
53307     result |= (n & 0x007F0000) >> 2;
53308     result |= (n & 0x00007F00) >> 1;
53309     result |= (n & 0x0000007F) >> 0;
53310     return result;
53311 }
53312 static drflac_uint8 drflac__crc8_table[] = {
53313     0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
53314     0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
53315     0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
53316     0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
53317     0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
53318     0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
53319     0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
53320     0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
53321     0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
53322     0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
53323     0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
53324     0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
53325     0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
53326     0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
53327     0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
53328     0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
53329 };
53330 static drflac_uint16 drflac__crc16_table[] = {
53331     0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
53332     0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
53333     0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
53334     0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
53335     0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
53336     0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
53337     0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
53338     0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
53339     0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
53340     0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
53341     0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
53342     0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
53343     0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
53344     0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
53345     0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
53346     0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
53347     0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
53348     0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
53349     0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
53350     0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
53351     0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
53352     0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
53353     0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
53354     0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
53355     0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
53356     0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
53357     0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
53358     0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
53359     0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
53360     0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
53361     0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
53362     0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
53363 };
53364 static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data)
53365 {
53366     return drflac__crc8_table[crc ^ data];
53367 }
53368 static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count)
53369 {
53370 #ifdef DR_FLAC_NO_CRC
53371     (void)crc;
53372     (void)data;
53373     (void)count;
53374     return 0;
53375 #else
53376 #if 0
53377     drflac_uint8 p = 0x07;
53378     for (int i = count-1; i >= 0; --i) {
53379         drflac_uint8 bit = (data & (1 << i)) >> i;
53380         if (crc & 0x80) {
53381             crc = ((crc << 1) | bit) ^ p;
53382         } else {
53383             crc = ((crc << 1) | bit);
53384         }
53385     }
53386     return crc;
53387 #else
53388     drflac_uint32 wholeBytes;
53389     drflac_uint32 leftoverBits;
53390     drflac_uint64 leftoverDataMask;
53391     static drflac_uint64 leftoverDataMaskTable[8] = {
53392         0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
53393     };
53394     DRFLAC_ASSERT(count <= 32);
53395     wholeBytes = count >> 3;
53396     leftoverBits = count - (wholeBytes*8);
53397     leftoverDataMask = leftoverDataMaskTable[leftoverBits];
53398     switch (wholeBytes) {
53399         case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
53400         case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
53401         case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
53402         case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
53403         case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]);
53404     }
53405     return crc;
53406 #endif
53407 #endif
53408 }
53409 static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data)
53410 {
53411     return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data];
53412 }
53413 static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data)
53414 {
53415 #ifdef DRFLAC_64BIT
53416     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
53417     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
53418     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
53419     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
53420 #endif
53421     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
53422     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
53423     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  8) & 0xFF));
53424     crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  0) & 0xFF));
53425     return crc;
53426 }
53427 static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount)
53428 {
53429     switch (byteCount)
53430     {
53431 #ifdef DRFLAC_64BIT
53432     case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
53433     case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
53434     case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
53435     case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
53436 #endif
53437     case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
53438     case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
53439     case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  8) & 0xFF));
53440     case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  0) & 0xFF));
53441     }
53442     return crc;
53443 }
53444 #if 0
53445 static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count)
53446 {
53447 #ifdef DR_FLAC_NO_CRC
53448     (void)crc;
53449     (void)data;
53450     (void)count;
53451     return 0;
53452 #else
53453 #if 0
53454     drflac_uint16 p = 0x8005;
53455     for (int i = count-1; i >= 0; --i) {
53456         drflac_uint16 bit = (data & (1ULL << i)) >> i;
53457         if (r & 0x8000) {
53458             r = ((r << 1) | bit) ^ p;
53459         } else {
53460             r = ((r << 1) | bit);
53461         }
53462     }
53463     return crc;
53464 #else
53465     drflac_uint32 wholeBytes;
53466     drflac_uint32 leftoverBits;
53467     drflac_uint64 leftoverDataMask;
53468     static drflac_uint64 leftoverDataMaskTable[8] = {
53469         0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
53470     };
53471     DRFLAC_ASSERT(count <= 64);
53472     wholeBytes = count >> 3;
53473     leftoverBits = count & 7;
53474     leftoverDataMask = leftoverDataMaskTable[leftoverBits];
53475     switch (wholeBytes) {
53476         default:
53477         case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
53478         case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
53479         case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
53480         case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
53481         case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
53482     }
53483     return crc;
53484 #endif
53485 #endif
53486 }
53487 static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count)
53488 {
53489 #ifdef DR_FLAC_NO_CRC
53490     (void)crc;
53491     (void)data;
53492     (void)count;
53493     return 0;
53494 #else
53495     drflac_uint32 wholeBytes;
53496     drflac_uint32 leftoverBits;
53497     drflac_uint64 leftoverDataMask;
53498     static drflac_uint64 leftoverDataMaskTable[8] = {
53499         0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
53500     };
53501     DRFLAC_ASSERT(count <= 64);
53502     wholeBytes = count >> 3;
53503     leftoverBits = count & 7;
53504     leftoverDataMask = leftoverDataMaskTable[leftoverBits];
53505     switch (wholeBytes) {
53506         default:
53507         case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits)));
53508         case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits)));
53509         case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits)));
53510         case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits)));
53511         case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000      ) << leftoverBits)) >> (24 + leftoverBits)));
53512         case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000      ) << leftoverBits)) >> (16 + leftoverBits)));
53513         case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00      ) << leftoverBits)) >> ( 8 + leftoverBits)));
53514         case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF      ) << leftoverBits)) >> ( 0 + leftoverBits)));
53515         case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
53516     }
53517     return crc;
53518 #endif
53519 }
53520 static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count)
53521 {
53522 #ifdef DRFLAC_64BIT
53523     return drflac_crc16__64bit(crc, data, count);
53524 #else
53525     return drflac_crc16__32bit(crc, data, count);
53526 #endif
53527 }
53528 #endif
53529 #ifdef DRFLAC_64BIT
53530 #define drflac__be2host__cache_line drflac__be2host_64
53531 #else
53532 #define drflac__be2host__cache_line drflac__be2host_32
53533 #endif
53534 #define DRFLAC_CACHE_L1_SIZE_BYTES(bs)                      (sizeof((bs)->cache))
53535 #define DRFLAC_CACHE_L1_SIZE_BITS(bs)                       (sizeof((bs)->cache)*8)
53536 #define DRFLAC_CACHE_L1_BITS_REMAINING(bs)                  (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits)
53537 #define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)           (~((~(drflac_cache_t)0) >> (_bitCount)))
53538 #define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount)      (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount))
53539 #define DRFLAC_CACHE_L1_SELECT(bs, _bitCount)               (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount))
53540 #define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount)     (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >>  DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)))
53541 #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)))
53542 #define DRFLAC_CACHE_L2_SIZE_BYTES(bs)                      (sizeof((bs)->cacheL2))
53543 #define DRFLAC_CACHE_L2_LINE_COUNT(bs)                      (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
53544 #define DRFLAC_CACHE_L2_LINES_REMAINING(bs)                 (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
53545 #ifndef DR_FLAC_NO_CRC
53546 static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs)
53547 {
53548     bs->crc16 = 0;
53549     bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
53550 }
53551 static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs)
53552 {
53553     if (bs->crc16CacheIgnoredBytes == 0) {
53554         bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache);
53555     } else {
53556         bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes);
53557         bs->crc16CacheIgnoredBytes = 0;
53558     }
53559 }
53560 static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs)
53561 {
53562     DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0);
53563     if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) {
53564         drflac__update_crc16(bs);
53565     } else {
53566         bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes);
53567         bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
53568     }
53569     return bs->crc16;
53570 }
53571 #endif
53572 static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
53573 {
53574     size_t bytesRead;
53575     size_t alignedL1LineCount;
53576     if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
53577         bs->cache = bs->cacheL2[bs->nextL2Line++];
53578         return DRFLAC_TRUE;
53579     }
53580     if (bs->unalignedByteCount > 0) {
53581         return DRFLAC_FALSE;
53582     }
53583     bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs));
53584     bs->nextL2Line = 0;
53585     if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) {
53586         bs->cache = bs->cacheL2[bs->nextL2Line++];
53587         return DRFLAC_TRUE;
53588     }
53589     alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
53590     bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs));
53591     if (bs->unalignedByteCount > 0) {
53592         bs->unalignedCache = bs->cacheL2[alignedL1LineCount];
53593     }
53594     if (alignedL1LineCount > 0) {
53595         size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount;
53596         size_t i;
53597         for (i = alignedL1LineCount; i > 0; --i) {
53598             bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1];
53599         }
53600         bs->nextL2Line = (drflac_uint32)offset;
53601         bs->cache = bs->cacheL2[bs->nextL2Line++];
53602         return DRFLAC_TRUE;
53603     } else {
53604         bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs);
53605         return DRFLAC_FALSE;
53606     }
53607 }
53608 static drflac_bool32 drflac__reload_cache(drflac_bs* bs)
53609 {
53610     size_t bytesRead;
53611 #ifndef DR_FLAC_NO_CRC
53612     drflac__update_crc16(bs);
53613 #endif
53614     if (drflac__reload_l1_cache_from_l2(bs)) {
53615         bs->cache = drflac__be2host__cache_line(bs->cache);
53616         bs->consumedBits = 0;
53617 #ifndef DR_FLAC_NO_CRC
53618         bs->crc16Cache = bs->cache;
53619 #endif
53620         return DRFLAC_TRUE;
53621     }
53622     bytesRead = bs->unalignedByteCount;
53623     if (bytesRead == 0) {
53624         bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
53625         return DRFLAC_FALSE;
53626     }
53627     DRFLAC_ASSERT(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs));
53628     bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8;
53629     bs->cache = drflac__be2host__cache_line(bs->unalignedCache);
53630     bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs));
53631     bs->unalignedByteCount = 0;
53632 #ifndef DR_FLAC_NO_CRC
53633     bs->crc16Cache = bs->cache >> bs->consumedBits;
53634     bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
53635 #endif
53636     return DRFLAC_TRUE;
53637 }
53638 static void drflac__reset_cache(drflac_bs* bs)
53639 {
53640     bs->nextL2Line   = DRFLAC_CACHE_L2_LINE_COUNT(bs);
53641     bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
53642     bs->cache = 0;
53643     bs->unalignedByteCount = 0;
53644     bs->unalignedCache = 0;
53645 #ifndef DR_FLAC_NO_CRC
53646     bs->crc16Cache = 0;
53647     bs->crc16CacheIgnoredBytes = 0;
53648 #endif
53649 }
53650 static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut)
53651 {
53652     DRFLAC_ASSERT(bs != NULL);
53653     DRFLAC_ASSERT(pResultOut != NULL);
53654     DRFLAC_ASSERT(bitCount > 0);
53655     DRFLAC_ASSERT(bitCount <= 32);
53656     if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
53657         if (!drflac__reload_cache(bs)) {
53658             return DRFLAC_FALSE;
53659         }
53660     }
53661     if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
53662 #ifdef DRFLAC_64BIT
53663         *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
53664         bs->consumedBits += bitCount;
53665         bs->cache <<= bitCount;
53666 #else
53667         if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
53668             *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
53669             bs->consumedBits += bitCount;
53670             bs->cache <<= bitCount;
53671         } else {
53672             *pResultOut = (drflac_uint32)bs->cache;
53673             bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
53674             bs->cache = 0;
53675         }
53676 #endif
53677         return DRFLAC_TRUE;
53678     } else {
53679         drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs);
53680         drflac_uint32 bitCountLo = bitCount - bitCountHi;
53681         drflac_uint32 resultHi;
53682         DRFLAC_ASSERT(bitCountHi > 0);
53683         DRFLAC_ASSERT(bitCountHi < 32);
53684         resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi);
53685         if (!drflac__reload_cache(bs)) {
53686             return DRFLAC_FALSE;
53687         }
53688         *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo);
53689         bs->consumedBits += bitCountLo;
53690         bs->cache <<= bitCountLo;
53691         return DRFLAC_TRUE;
53692     }
53693 }
53694 static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult)
53695 {
53696     drflac_uint32 result;
53697     DRFLAC_ASSERT(bs != NULL);
53698     DRFLAC_ASSERT(pResult != NULL);
53699     DRFLAC_ASSERT(bitCount > 0);
53700     DRFLAC_ASSERT(bitCount <= 32);
53701     if (!drflac__read_uint32(bs, bitCount, &result)) {
53702         return DRFLAC_FALSE;
53703     }
53704     if (bitCount < 32) {
53705         drflac_uint32 signbit;
53706         signbit = ((result >> (bitCount-1)) & 0x01);
53707         result |= (~signbit + 1) << bitCount;
53708     }
53709     *pResult = (drflac_int32)result;
53710     return DRFLAC_TRUE;
53711 }
53712 #ifdef DRFLAC_64BIT
53713 static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut)
53714 {
53715     drflac_uint32 resultHi;
53716     drflac_uint32 resultLo;
53717     DRFLAC_ASSERT(bitCount <= 64);
53718     DRFLAC_ASSERT(bitCount >  32);
53719     if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) {
53720         return DRFLAC_FALSE;
53721     }
53722     if (!drflac__read_uint32(bs, 32, &resultLo)) {
53723         return DRFLAC_FALSE;
53724     }
53725     *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo);
53726     return DRFLAC_TRUE;
53727 }
53728 #endif
53729 #if 0
53730 static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut)
53731 {
53732     drflac_uint64 result;
53733     drflac_uint64 signbit;
53734     DRFLAC_ASSERT(bitCount <= 64);
53735     if (!drflac__read_uint64(bs, bitCount, &result)) {
53736         return DRFLAC_FALSE;
53737     }
53738     signbit = ((result >> (bitCount-1)) & 0x01);
53739     result |= (~signbit + 1) << bitCount;
53740     *pResultOut = (drflac_int64)result;
53741     return DRFLAC_TRUE;
53742 }
53743 #endif
53744 static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult)
53745 {
53746     drflac_uint32 result;
53747     DRFLAC_ASSERT(bs != NULL);
53748     DRFLAC_ASSERT(pResult != NULL);
53749     DRFLAC_ASSERT(bitCount > 0);
53750     DRFLAC_ASSERT(bitCount <= 16);
53751     if (!drflac__read_uint32(bs, bitCount, &result)) {
53752         return DRFLAC_FALSE;
53753     }
53754     *pResult = (drflac_uint16)result;
53755     return DRFLAC_TRUE;
53756 }
53757 #if 0
53758 static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult)
53759 {
53760     drflac_int32 result;
53761     DRFLAC_ASSERT(bs != NULL);
53762     DRFLAC_ASSERT(pResult != NULL);
53763     DRFLAC_ASSERT(bitCount > 0);
53764     DRFLAC_ASSERT(bitCount <= 16);
53765     if (!drflac__read_int32(bs, bitCount, &result)) {
53766         return DRFLAC_FALSE;
53767     }
53768     *pResult = (drflac_int16)result;
53769     return DRFLAC_TRUE;
53770 }
53771 #endif
53772 static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult)
53773 {
53774     drflac_uint32 result;
53775     DRFLAC_ASSERT(bs != NULL);
53776     DRFLAC_ASSERT(pResult != NULL);
53777     DRFLAC_ASSERT(bitCount > 0);
53778     DRFLAC_ASSERT(bitCount <= 8);
53779     if (!drflac__read_uint32(bs, bitCount, &result)) {
53780         return DRFLAC_FALSE;
53781     }
53782     *pResult = (drflac_uint8)result;
53783     return DRFLAC_TRUE;
53784 }
53785 static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult)
53786 {
53787     drflac_int32 result;
53788     DRFLAC_ASSERT(bs != NULL);
53789     DRFLAC_ASSERT(pResult != NULL);
53790     DRFLAC_ASSERT(bitCount > 0);
53791     DRFLAC_ASSERT(bitCount <= 8);
53792     if (!drflac__read_int32(bs, bitCount, &result)) {
53793         return DRFLAC_FALSE;
53794     }
53795     *pResult = (drflac_int8)result;
53796     return DRFLAC_TRUE;
53797 }
53798 static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
53799 {
53800     if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
53801         bs->consumedBits += (drflac_uint32)bitsToSeek;
53802         bs->cache <<= bitsToSeek;
53803         return DRFLAC_TRUE;
53804     } else {
53805         bitsToSeek       -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
53806         bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
53807         bs->cache         = 0;
53808 #ifdef DRFLAC_64BIT
53809         while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
53810             drflac_uint64 bin;
53811             if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
53812                 return DRFLAC_FALSE;
53813             }
53814             bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
53815         }
53816 #else
53817         while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
53818             drflac_uint32 bin;
53819             if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
53820                 return DRFLAC_FALSE;
53821             }
53822             bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
53823         }
53824 #endif
53825         while (bitsToSeek >= 8) {
53826             drflac_uint8 bin;
53827             if (!drflac__read_uint8(bs, 8, &bin)) {
53828                 return DRFLAC_FALSE;
53829             }
53830             bitsToSeek -= 8;
53831         }
53832         if (bitsToSeek > 0) {
53833             drflac_uint8 bin;
53834             if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) {
53835                 return DRFLAC_FALSE;
53836             }
53837             bitsToSeek = 0;
53838         }
53839         DRFLAC_ASSERT(bitsToSeek == 0);
53840         return DRFLAC_TRUE;
53841     }
53842 }
53843 static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs)
53844 {
53845     DRFLAC_ASSERT(bs != NULL);
53846     if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
53847         return DRFLAC_FALSE;
53848     }
53849     for (;;) {
53850         drflac_uint8 hi;
53851 #ifndef DR_FLAC_NO_CRC
53852         drflac__reset_crc16(bs);
53853 #endif
53854         if (!drflac__read_uint8(bs, 8, &hi)) {
53855             return DRFLAC_FALSE;
53856         }
53857         if (hi == 0xFF) {
53858             drflac_uint8 lo;
53859             if (!drflac__read_uint8(bs, 6, &lo)) {
53860                 return DRFLAC_FALSE;
53861             }
53862             if (lo == 0x3E) {
53863                 return DRFLAC_TRUE;
53864             } else {
53865                 if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
53866                     return DRFLAC_FALSE;
53867                 }
53868             }
53869         }
53870     }
53871 }
53872 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
53873 #define DRFLAC_IMPLEMENT_CLZ_LZCNT
53874 #endif
53875 #if  defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__)
53876 #define DRFLAC_IMPLEMENT_CLZ_MSVC
53877 #endif
53878 #if  defined(__WATCOMC__) && defined(__386__)
53879 #define DRFLAC_IMPLEMENT_CLZ_WATCOM
53880 #endif
53881 static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x)
53882 {
53883     drflac_uint32 n;
53884     static drflac_uint32 clz_table_4[] = {
53885         0,
53886         4,
53887         3, 3,
53888         2, 2, 2, 2,
53889         1, 1, 1, 1, 1, 1, 1, 1
53890     };
53891     if (x == 0) {
53892         return sizeof(x)*8;
53893     }
53894     n = clz_table_4[x >> (sizeof(x)*8 - 4)];
53895     if (n == 0) {
53896 #ifdef DRFLAC_64BIT
53897         if ((x & ((drflac_uint64)0xFFFFFFFF << 32)) == 0) { n  = 32; x <<= 32; }
53898         if ((x & ((drflac_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; }
53899         if ((x & ((drflac_uint64)0xFF000000 << 32)) == 0) { n += 8;  x <<= 8;  }
53900         if ((x & ((drflac_uint64)0xF0000000 << 32)) == 0) { n += 4;  x <<= 4;  }
53901 #else
53902         if ((x & 0xFFFF0000) == 0) { n  = 16; x <<= 16; }
53903         if ((x & 0xFF000000) == 0) { n += 8;  x <<= 8;  }
53904         if ((x & 0xF0000000) == 0) { n += 4;  x <<= 4;  }
53905 #endif
53906         n += clz_table_4[x >> (sizeof(x)*8 - 4)];
53907     }
53908     return n - 1;
53909 }
53910 #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
53911 static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void)
53912 {
53913 #if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
53914     return DRFLAC_TRUE;
53915 #else
53916     #ifdef DRFLAC_HAS_LZCNT_INTRINSIC
53917         return drflac__gIsLZCNTSupported;
53918     #else
53919         return DRFLAC_FALSE;
53920     #endif
53921 #endif
53922 }
53923 static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
53924 {
53925 #if defined(_MSC_VER)
53926     #ifdef DRFLAC_64BIT
53927         return (drflac_uint32)__lzcnt64(x);
53928     #else
53929         return (drflac_uint32)__lzcnt(x);
53930     #endif
53931 #else
53932     #if defined(__GNUC__) || defined(__clang__)
53933         #if defined(DRFLAC_X64)
53934             {
53935                 drflac_uint64 r;
53936                 __asm__ __volatile__ (
53937                     "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
53938                 );
53939                 return (drflac_uint32)r;
53940             }
53941         #elif defined(DRFLAC_X86)
53942             {
53943                 drflac_uint32 r;
53944                 __asm__ __volatile__ (
53945                     "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
53946                 );
53947                 return r;
53948             }
53949         #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(DRFLAC_64BIT)
53950             {
53951                 unsigned int r;
53952                 __asm__ __volatile__ (
53953                 #if defined(DRFLAC_64BIT)
53954                     "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x)
53955                 #else
53956                     "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x)
53957                 #endif
53958                 );
53959                 return r;
53960             }
53961         #else
53962             if (x == 0) {
53963                 return sizeof(x)*8;
53964             }
53965             #ifdef DRFLAC_64BIT
53966                 return (drflac_uint32)__builtin_clzll((drflac_uint64)x);
53967             #else
53968                 return (drflac_uint32)__builtin_clzl((drflac_uint32)x);
53969             #endif
53970         #endif
53971     #else
53972         #error "This compiler does not support the lzcnt intrinsic."
53973     #endif
53974 #endif
53975 }
53976 #endif
53977 #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
53978 #include <intrin.h>
53979 static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x)
53980 {
53981     drflac_uint32 n;
53982     if (x == 0) {
53983         return sizeof(x)*8;
53984     }
53985 #ifdef DRFLAC_64BIT
53986     _BitScanReverse64((unsigned long*)&n, x);
53987 #else
53988     _BitScanReverse((unsigned long*)&n, x);
53989 #endif
53990     return sizeof(x)*8 - n - 1;
53991 }
53992 #endif
53993 #ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM
53994 static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32);
53995 #pragma aux drflac__clz_watcom = \
53996     "bsr eax, eax" \
53997     "xor eax, 31" \
53998     parm [eax] nomemory \
53999     value [eax] \
54000     modify exact [eax] nomemory;
54001 #endif
54002 static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x)
54003 {
54004 #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
54005     if (drflac__is_lzcnt_supported()) {
54006         return drflac__clz_lzcnt(x);
54007     } else
54008 #endif
54009     {
54010 #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
54011         return drflac__clz_msvc(x);
54012 #elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM)
54013         return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x);
54014 #else
54015         return drflac__clz_software(x);
54016 #endif
54017     }
54018 }
54019 static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
54020 {
54021     drflac_uint32 zeroCounter = 0;
54022     drflac_uint32 setBitOffsetPlus1;
54023     while (bs->cache == 0) {
54024         zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
54025         if (!drflac__reload_cache(bs)) {
54026             return DRFLAC_FALSE;
54027         }
54028     }
54029     setBitOffsetPlus1 = drflac__clz(bs->cache);
54030     setBitOffsetPlus1 += 1;
54031     bs->consumedBits += setBitOffsetPlus1;
54032     bs->cache <<= setBitOffsetPlus1;
54033     *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1;
54034     return DRFLAC_TRUE;
54035 }
54036 static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart)
54037 {
54038     DRFLAC_ASSERT(bs != NULL);
54039     DRFLAC_ASSERT(offsetFromStart > 0);
54040     if (offsetFromStart > 0x7FFFFFFF) {
54041         drflac_uint64 bytesRemaining = offsetFromStart;
54042         if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
54043             return DRFLAC_FALSE;
54044         }
54045         bytesRemaining -= 0x7FFFFFFF;
54046         while (bytesRemaining > 0x7FFFFFFF) {
54047             if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
54048                 return DRFLAC_FALSE;
54049             }
54050             bytesRemaining -= 0x7FFFFFFF;
54051         }
54052         if (bytesRemaining > 0) {
54053             if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
54054                 return DRFLAC_FALSE;
54055             }
54056         }
54057     } else {
54058         if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
54059             return DRFLAC_FALSE;
54060         }
54061     }
54062     drflac__reset_cache(bs);
54063     return DRFLAC_TRUE;
54064 }
54065 static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut)
54066 {
54067     drflac_uint8 crc;
54068     drflac_uint64 result;
54069     drflac_uint8 utf8[7] = {0};
54070     int byteCount;
54071     int i;
54072     DRFLAC_ASSERT(bs != NULL);
54073     DRFLAC_ASSERT(pNumberOut != NULL);
54074     DRFLAC_ASSERT(pCRCOut != NULL);
54075     crc = *pCRCOut;
54076     if (!drflac__read_uint8(bs, 8, utf8)) {
54077         *pNumberOut = 0;
54078         return DRFLAC_AT_END;
54079     }
54080     crc = drflac_crc8(crc, utf8[0], 8);
54081     if ((utf8[0] & 0x80) == 0) {
54082         *pNumberOut = utf8[0];
54083         *pCRCOut = crc;
54084         return DRFLAC_SUCCESS;
54085     }
54086     if ((utf8[0] & 0xE0) == 0xC0) {
54087         byteCount = 2;
54088     } else if ((utf8[0] & 0xF0) == 0xE0) {
54089         byteCount = 3;
54090     } else if ((utf8[0] & 0xF8) == 0xF0) {
54091         byteCount = 4;
54092     } else if ((utf8[0] & 0xFC) == 0xF8) {
54093         byteCount = 5;
54094     } else if ((utf8[0] & 0xFE) == 0xFC) {
54095         byteCount = 6;
54096     } else if ((utf8[0] & 0xFF) == 0xFE) {
54097         byteCount = 7;
54098     } else {
54099         *pNumberOut = 0;
54100         return DRFLAC_CRC_MISMATCH;
54101     }
54102     DRFLAC_ASSERT(byteCount > 1);
54103     result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1)));
54104     for (i = 1; i < byteCount; ++i) {
54105         if (!drflac__read_uint8(bs, 8, utf8 + i)) {
54106             *pNumberOut = 0;
54107             return DRFLAC_AT_END;
54108         }
54109         crc = drflac_crc8(crc, utf8[i], 8);
54110         result = (result << 6) | (utf8[i] & 0x3F);
54111     }
54112     *pNumberOut = result;
54113     *pCRCOut = crc;
54114     return DRFLAC_SUCCESS;
54115 }
54116 static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
54117 {
54118     drflac_int32 prediction = 0;
54119     DRFLAC_ASSERT(order <= 32);
54120     switch (order)
54121     {
54122     case 32: prediction += coefficients[31] * pDecodedSamples[-32];
54123     case 31: prediction += coefficients[30] * pDecodedSamples[-31];
54124     case 30: prediction += coefficients[29] * pDecodedSamples[-30];
54125     case 29: prediction += coefficients[28] * pDecodedSamples[-29];
54126     case 28: prediction += coefficients[27] * pDecodedSamples[-28];
54127     case 27: prediction += coefficients[26] * pDecodedSamples[-27];
54128     case 26: prediction += coefficients[25] * pDecodedSamples[-26];
54129     case 25: prediction += coefficients[24] * pDecodedSamples[-25];
54130     case 24: prediction += coefficients[23] * pDecodedSamples[-24];
54131     case 23: prediction += coefficients[22] * pDecodedSamples[-23];
54132     case 22: prediction += coefficients[21] * pDecodedSamples[-22];
54133     case 21: prediction += coefficients[20] * pDecodedSamples[-21];
54134     case 20: prediction += coefficients[19] * pDecodedSamples[-20];
54135     case 19: prediction += coefficients[18] * pDecodedSamples[-19];
54136     case 18: prediction += coefficients[17] * pDecodedSamples[-18];
54137     case 17: prediction += coefficients[16] * pDecodedSamples[-17];
54138     case 16: prediction += coefficients[15] * pDecodedSamples[-16];
54139     case 15: prediction += coefficients[14] * pDecodedSamples[-15];
54140     case 14: prediction += coefficients[13] * pDecodedSamples[-14];
54141     case 13: prediction += coefficients[12] * pDecodedSamples[-13];
54142     case 12: prediction += coefficients[11] * pDecodedSamples[-12];
54143     case 11: prediction += coefficients[10] * pDecodedSamples[-11];
54144     case 10: prediction += coefficients[ 9] * pDecodedSamples[-10];
54145     case  9: prediction += coefficients[ 8] * pDecodedSamples[- 9];
54146     case  8: prediction += coefficients[ 7] * pDecodedSamples[- 8];
54147     case  7: prediction += coefficients[ 6] * pDecodedSamples[- 7];
54148     case  6: prediction += coefficients[ 5] * pDecodedSamples[- 6];
54149     case  5: prediction += coefficients[ 4] * pDecodedSamples[- 5];
54150     case  4: prediction += coefficients[ 3] * pDecodedSamples[- 4];
54151     case  3: prediction += coefficients[ 2] * pDecodedSamples[- 3];
54152     case  2: prediction += coefficients[ 1] * pDecodedSamples[- 2];
54153     case  1: prediction += coefficients[ 0] * pDecodedSamples[- 1];
54154     }
54155     return (drflac_int32)(prediction >> shift);
54156 }
54157 static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
54158 {
54159     drflac_int64 prediction;
54160     DRFLAC_ASSERT(order <= 32);
54161 #ifndef DRFLAC_64BIT
54162     if (order == 8)
54163     {
54164         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54165         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
54166         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
54167         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
54168         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
54169         prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
54170         prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
54171         prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
54172     }
54173     else if (order == 7)
54174     {
54175         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54176         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
54177         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
54178         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
54179         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
54180         prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
54181         prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
54182     }
54183     else if (order == 3)
54184     {
54185         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54186         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
54187         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
54188     }
54189     else if (order == 6)
54190     {
54191         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54192         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
54193         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
54194         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
54195         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
54196         prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
54197     }
54198     else if (order == 5)
54199     {
54200         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54201         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
54202         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
54203         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
54204         prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
54205     }
54206     else if (order == 4)
54207     {
54208         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54209         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
54210         prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
54211         prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
54212     }
54213     else if (order == 12)
54214     {
54215         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
54216         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
54217         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
54218         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
54219         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
54220         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
54221         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
54222         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
54223         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
54224         prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
54225         prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
54226         prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
54227     }
54228     else if (order == 2)
54229     {
54230         prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54231         prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
54232     }
54233     else if (order == 1)
54234     {
54235         prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
54236     }
54237     else if (order == 10)
54238     {
54239         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
54240         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
54241         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
54242         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
54243         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
54244         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
54245         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
54246         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
54247         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
54248         prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
54249     }
54250     else if (order == 9)
54251     {
54252         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
54253         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
54254         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
54255         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
54256         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
54257         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
54258         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
54259         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
54260         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
54261     }
54262     else if (order == 11)
54263     {
54264         prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
54265         prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
54266         prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
54267         prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
54268         prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
54269         prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
54270         prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
54271         prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
54272         prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
54273         prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
54274         prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
54275     }
54276     else
54277     {
54278         int j;
54279         prediction = 0;
54280         for (j = 0; j < (int)order; ++j) {
54281             prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1];
54282         }
54283     }
54284 #endif
54285 #ifdef DRFLAC_64BIT
54286     prediction = 0;
54287     switch (order)
54288     {
54289     case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32];
54290     case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31];
54291     case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30];
54292     case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29];
54293     case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28];
54294     case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27];
54295     case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26];
54296     case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25];
54297     case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24];
54298     case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23];
54299     case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22];
54300     case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21];
54301     case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20];
54302     case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19];
54303     case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18];
54304     case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17];
54305     case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16];
54306     case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15];
54307     case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14];
54308     case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13];
54309     case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
54310     case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
54311     case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10];
54312     case  9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9];
54313     case  8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8];
54314     case  7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7];
54315     case  6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6];
54316     case  5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5];
54317     case  4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4];
54318     case  3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3];
54319     case  2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2];
54320     case  1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1];
54321     }
54322 #endif
54323     return (drflac_int32)(prediction >> shift);
54324 }
54325 #if 0
54326 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)
54327 {
54328     drflac_uint32 i;
54329     DRFLAC_ASSERT(bs != NULL);
54330     DRFLAC_ASSERT(pSamplesOut != NULL);
54331     for (i = 0; i < count; ++i) {
54332         drflac_uint32 zeroCounter = 0;
54333         for (;;) {
54334             drflac_uint8 bit;
54335             if (!drflac__read_uint8(bs, 1, &bit)) {
54336                 return DRFLAC_FALSE;
54337             }
54338             if (bit == 0) {
54339                 zeroCounter += 1;
54340             } else {
54341                 break;
54342             }
54343         }
54344         drflac_uint32 decodedRice;
54345         if (riceParam > 0) {
54346             if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
54347                 return DRFLAC_FALSE;
54348             }
54349         } else {
54350             decodedRice = 0;
54351         }
54352         decodedRice |= (zeroCounter << riceParam);
54353         if ((decodedRice & 0x01)) {
54354             decodedRice = ~(decodedRice >> 1);
54355         } else {
54356             decodedRice =  (decodedRice >> 1);
54357         }
54358         if (bitsPerSample+shift >= 32) {
54359             pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
54360         } else {
54361             pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
54362         }
54363     }
54364     return DRFLAC_TRUE;
54365 }
54366 #endif
54367 #if 0
54368 static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
54369 {
54370     drflac_uint32 zeroCounter = 0;
54371     drflac_uint32 decodedRice;
54372     for (;;) {
54373         drflac_uint8 bit;
54374         if (!drflac__read_uint8(bs, 1, &bit)) {
54375             return DRFLAC_FALSE;
54376         }
54377         if (bit == 0) {
54378             zeroCounter += 1;
54379         } else {
54380             break;
54381         }
54382     }
54383     if (riceParam > 0) {
54384         if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
54385             return DRFLAC_FALSE;
54386         }
54387     } else {
54388         decodedRice = 0;
54389     }
54390     *pZeroCounterOut = zeroCounter;
54391     *pRiceParamPartOut = decodedRice;
54392     return DRFLAC_TRUE;
54393 }
54394 #endif
54395 #if 0
54396 static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
54397 {
54398     drflac_cache_t riceParamMask;
54399     drflac_uint32 zeroCounter;
54400     drflac_uint32 setBitOffsetPlus1;
54401     drflac_uint32 riceParamPart;
54402     drflac_uint32 riceLength;
54403     DRFLAC_ASSERT(riceParam > 0);
54404     riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam);
54405     zeroCounter = 0;
54406     while (bs->cache == 0) {
54407         zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
54408         if (!drflac__reload_cache(bs)) {
54409             return DRFLAC_FALSE;
54410         }
54411     }
54412     setBitOffsetPlus1 = drflac__clz(bs->cache);
54413     zeroCounter += setBitOffsetPlus1;
54414     setBitOffsetPlus1 += 1;
54415     riceLength = setBitOffsetPlus1 + riceParam;
54416     if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
54417         riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength));
54418         bs->consumedBits += riceLength;
54419         bs->cache <<= riceLength;
54420     } else {
54421         drflac_uint32 bitCountLo;
54422         drflac_cache_t resultHi;
54423         bs->consumedBits += riceLength;
54424         bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1);
54425         bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs);
54426         resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam);
54427         if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
54428 #ifndef DR_FLAC_NO_CRC
54429             drflac__update_crc16(bs);
54430 #endif
54431             bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
54432             bs->consumedBits = 0;
54433 #ifndef DR_FLAC_NO_CRC
54434             bs->crc16Cache = bs->cache;
54435 #endif
54436         } else {
54437             if (!drflac__reload_cache(bs)) {
54438                 return DRFLAC_FALSE;
54439             }
54440         }
54441         riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo));
54442         bs->consumedBits += bitCountLo;
54443         bs->cache <<= bitCountLo;
54444     }
54445     pZeroCounterOut[0] = zeroCounter;
54446     pRiceParamPartOut[0] = riceParamPart;
54447     return DRFLAC_TRUE;
54448 }
54449 #endif
54450 static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
54451 {
54452     drflac_uint32  riceParamPlus1 = riceParam + 1;
54453     drflac_uint32  riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1);
54454     drflac_uint32  riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
54455     drflac_cache_t bs_cache = bs->cache;
54456     drflac_uint32  bs_consumedBits = bs->consumedBits;
54457     drflac_uint32  lzcount = drflac__clz(bs_cache);
54458     if (lzcount < sizeof(bs_cache)*8) {
54459         pZeroCounterOut[0] = lzcount;
54460     extract_rice_param_part:
54461         bs_cache       <<= lzcount;
54462         bs_consumedBits += lzcount;
54463         if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
54464             pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
54465             bs_cache       <<= riceParamPlus1;
54466             bs_consumedBits += riceParamPlus1;
54467         } else {
54468             drflac_uint32 riceParamPartHi;
54469             drflac_uint32 riceParamPartLo;
54470             drflac_uint32 riceParamPartLoBitCount;
54471             riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
54472             riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
54473             DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
54474             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
54475             #ifndef DR_FLAC_NO_CRC
54476                 drflac__update_crc16(bs);
54477             #endif
54478                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
54479                 bs_consumedBits = riceParamPartLoBitCount;
54480             #ifndef DR_FLAC_NO_CRC
54481                 bs->crc16Cache = bs_cache;
54482             #endif
54483             } else {
54484                 if (!drflac__reload_cache(bs)) {
54485                     return DRFLAC_FALSE;
54486                 }
54487                 bs_cache = bs->cache;
54488                 bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
54489             }
54490             riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount)));
54491             pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo;
54492             bs_cache <<= riceParamPartLoBitCount;
54493         }
54494     } else {
54495         drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits);
54496         for (;;) {
54497             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
54498             #ifndef DR_FLAC_NO_CRC
54499                 drflac__update_crc16(bs);
54500             #endif
54501                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
54502                 bs_consumedBits = 0;
54503             #ifndef DR_FLAC_NO_CRC
54504                 bs->crc16Cache = bs_cache;
54505             #endif
54506             } else {
54507                 if (!drflac__reload_cache(bs)) {
54508                     return DRFLAC_FALSE;
54509                 }
54510                 bs_cache = bs->cache;
54511                 bs_consumedBits = bs->consumedBits;
54512             }
54513             lzcount = drflac__clz(bs_cache);
54514             zeroCounter += lzcount;
54515             if (lzcount < sizeof(bs_cache)*8) {
54516                 break;
54517             }
54518         }
54519         pZeroCounterOut[0] = zeroCounter;
54520         goto extract_rice_param_part;
54521     }
54522     bs->cache = bs_cache;
54523     bs->consumedBits = bs_consumedBits;
54524     return DRFLAC_TRUE;
54525 }
54526 static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam)
54527 {
54528     drflac_uint32  riceParamPlus1 = riceParam + 1;
54529     drflac_uint32  riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
54530     drflac_cache_t bs_cache = bs->cache;
54531     drflac_uint32  bs_consumedBits = bs->consumedBits;
54532     drflac_uint32  lzcount = drflac__clz(bs_cache);
54533     if (lzcount < sizeof(bs_cache)*8) {
54534     extract_rice_param_part:
54535         bs_cache       <<= lzcount;
54536         bs_consumedBits += lzcount;
54537         if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
54538             bs_cache       <<= riceParamPlus1;
54539             bs_consumedBits += riceParamPlus1;
54540         } else {
54541             drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
54542             DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
54543             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
54544             #ifndef DR_FLAC_NO_CRC
54545                 drflac__update_crc16(bs);
54546             #endif
54547                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
54548                 bs_consumedBits = riceParamPartLoBitCount;
54549             #ifndef DR_FLAC_NO_CRC
54550                 bs->crc16Cache = bs_cache;
54551             #endif
54552             } else {
54553                 if (!drflac__reload_cache(bs)) {
54554                     return DRFLAC_FALSE;
54555                 }
54556                 bs_cache = bs->cache;
54557                 bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
54558             }
54559             bs_cache <<= riceParamPartLoBitCount;
54560         }
54561     } else {
54562         for (;;) {
54563             if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
54564             #ifndef DR_FLAC_NO_CRC
54565                 drflac__update_crc16(bs);
54566             #endif
54567                 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
54568                 bs_consumedBits = 0;
54569             #ifndef DR_FLAC_NO_CRC
54570                 bs->crc16Cache = bs_cache;
54571             #endif
54572             } else {
54573                 if (!drflac__reload_cache(bs)) {
54574                     return DRFLAC_FALSE;
54575                 }
54576                 bs_cache = bs->cache;
54577                 bs_consumedBits = bs->consumedBits;
54578             }
54579             lzcount = drflac__clz(bs_cache);
54580             if (lzcount < sizeof(bs_cache)*8) {
54581                 break;
54582             }
54583         }
54584         goto extract_rice_param_part;
54585     }
54586     bs->cache = bs_cache;
54587     bs->consumedBits = bs_consumedBits;
54588     return DRFLAC_TRUE;
54589 }
54590 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)
54591 {
54592     drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
54593     drflac_uint32 zeroCountPart0;
54594     drflac_uint32 riceParamPart0;
54595     drflac_uint32 riceParamMask;
54596     drflac_uint32 i;
54597     DRFLAC_ASSERT(bs != NULL);
54598     DRFLAC_ASSERT(pSamplesOut != NULL);
54599     (void)bitsPerSample;
54600     (void)order;
54601     (void)shift;
54602     (void)coefficients;
54603     riceParamMask  = (drflac_uint32)~((~0UL) << riceParam);
54604     i = 0;
54605     while (i < count) {
54606         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
54607             return DRFLAC_FALSE;
54608         }
54609         riceParamPart0 &= riceParamMask;
54610         riceParamPart0 |= (zeroCountPart0 << riceParam);
54611         riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
54612         pSamplesOut[i] = riceParamPart0;
54613         i += 1;
54614     }
54615     return DRFLAC_TRUE;
54616 }
54617 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)
54618 {
54619     drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
54620     drflac_uint32 zeroCountPart0 = 0;
54621     drflac_uint32 zeroCountPart1 = 0;
54622     drflac_uint32 zeroCountPart2 = 0;
54623     drflac_uint32 zeroCountPart3 = 0;
54624     drflac_uint32 riceParamPart0 = 0;
54625     drflac_uint32 riceParamPart1 = 0;
54626     drflac_uint32 riceParamPart2 = 0;
54627     drflac_uint32 riceParamPart3 = 0;
54628     drflac_uint32 riceParamMask;
54629     const drflac_int32* pSamplesOutEnd;
54630     drflac_uint32 i;
54631     DRFLAC_ASSERT(bs != NULL);
54632     DRFLAC_ASSERT(pSamplesOut != NULL);
54633     if (order == 0) {
54634         return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
54635     }
54636     riceParamMask  = (drflac_uint32)~((~0UL) << riceParam);
54637     pSamplesOutEnd = pSamplesOut + (count & ~3);
54638     if (bitsPerSample+shift > 32) {
54639         while (pSamplesOut < pSamplesOutEnd) {
54640             if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
54641                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
54642                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
54643                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
54644                 return DRFLAC_FALSE;
54645             }
54646             riceParamPart0 &= riceParamMask;
54647             riceParamPart1 &= riceParamMask;
54648             riceParamPart2 &= riceParamMask;
54649             riceParamPart3 &= riceParamMask;
54650             riceParamPart0 |= (zeroCountPart0 << riceParam);
54651             riceParamPart1 |= (zeroCountPart1 << riceParam);
54652             riceParamPart2 |= (zeroCountPart2 << riceParam);
54653             riceParamPart3 |= (zeroCountPart3 << riceParam);
54654             riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
54655             riceParamPart1  = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
54656             riceParamPart2  = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
54657             riceParamPart3  = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
54658             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0);
54659             pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1);
54660             pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2);
54661             pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3);
54662             pSamplesOut += 4;
54663         }
54664     } else {
54665         while (pSamplesOut < pSamplesOutEnd) {
54666             if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
54667                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
54668                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
54669                 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
54670                 return DRFLAC_FALSE;
54671             }
54672             riceParamPart0 &= riceParamMask;
54673             riceParamPart1 &= riceParamMask;
54674             riceParamPart2 &= riceParamMask;
54675             riceParamPart3 &= riceParamMask;
54676             riceParamPart0 |= (zeroCountPart0 << riceParam);
54677             riceParamPart1 |= (zeroCountPart1 << riceParam);
54678             riceParamPart2 |= (zeroCountPart2 << riceParam);
54679             riceParamPart3 |= (zeroCountPart3 << riceParam);
54680             riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
54681             riceParamPart1  = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
54682             riceParamPart2  = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
54683             riceParamPart3  = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
54684             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0);
54685             pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1);
54686             pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2);
54687             pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3);
54688             pSamplesOut += 4;
54689         }
54690     }
54691     i = (count & ~3);
54692     while (i < count) {
54693         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
54694             return DRFLAC_FALSE;
54695         }
54696         riceParamPart0 &= riceParamMask;
54697         riceParamPart0 |= (zeroCountPart0 << riceParam);
54698         riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
54699         if (bitsPerSample+shift > 32) {
54700             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0);
54701         } else {
54702             pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0);
54703         }
54704         i += 1;
54705         pSamplesOut += 1;
54706     }
54707     return DRFLAC_TRUE;
54708 }
54709 #if defined(DRFLAC_SUPPORT_SSE2)
54710 static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b)
54711 {
54712     __m128i r;
54713     r = _mm_packs_epi32(a, b);
54714     r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0));
54715     r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
54716     r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
54717     return r;
54718 }
54719 #endif
54720 #if defined(DRFLAC_SUPPORT_SSE41)
54721 static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a)
54722 {
54723     return _mm_xor_si128(a, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()));
54724 }
54725 static DRFLAC_INLINE __m128i drflac__mm_hadd_epi32(__m128i x)
54726 {
54727     __m128i x64 = _mm_add_epi32(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
54728     __m128i x32 = _mm_shufflelo_epi16(x64, _MM_SHUFFLE(1, 0, 3, 2));
54729     return _mm_add_epi32(x64, x32);
54730 }
54731 static DRFLAC_INLINE __m128i drflac__mm_hadd_epi64(__m128i x)
54732 {
54733     return _mm_add_epi64(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
54734 }
54735 static DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count)
54736 {
54737     __m128i lo = _mm_srli_epi64(x, count);
54738     __m128i hi = _mm_srai_epi32(x, count);
54739     hi = _mm_and_si128(hi, _mm_set_epi32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0));
54740     return _mm_or_si128(lo, hi);
54741 }
54742 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)
54743 {
54744     int i;
54745     drflac_uint32 riceParamMask;
54746     drflac_int32* pDecodedSamples    = pSamplesOut;
54747     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
54748     drflac_uint32 zeroCountParts0 = 0;
54749     drflac_uint32 zeroCountParts1 = 0;
54750     drflac_uint32 zeroCountParts2 = 0;
54751     drflac_uint32 zeroCountParts3 = 0;
54752     drflac_uint32 riceParamParts0 = 0;
54753     drflac_uint32 riceParamParts1 = 0;
54754     drflac_uint32 riceParamParts2 = 0;
54755     drflac_uint32 riceParamParts3 = 0;
54756     __m128i coefficients128_0;
54757     __m128i coefficients128_4;
54758     __m128i coefficients128_8;
54759     __m128i samples128_0;
54760     __m128i samples128_4;
54761     __m128i samples128_8;
54762     __m128i riceParamMask128;
54763     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
54764     riceParamMask    = (drflac_uint32)~((~0UL) << riceParam);
54765     riceParamMask128 = _mm_set1_epi32(riceParamMask);
54766     coefficients128_0 = _mm_setzero_si128();
54767     coefficients128_4 = _mm_setzero_si128();
54768     coefficients128_8 = _mm_setzero_si128();
54769     samples128_0 = _mm_setzero_si128();
54770     samples128_4 = _mm_setzero_si128();
54771     samples128_8 = _mm_setzero_si128();
54772 #if 1
54773     {
54774         int runningOrder = order;
54775         if (runningOrder >= 4) {
54776             coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
54777             samples128_0      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 4));
54778             runningOrder -= 4;
54779         } else {
54780             switch (runningOrder) {
54781                 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;
54782                 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;
54783                 case 1: coefficients128_0 = _mm_set_epi32(0, 0,               0,               coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0,               0,               0); break;
54784             }
54785             runningOrder = 0;
54786         }
54787         if (runningOrder >= 4) {
54788             coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
54789             samples128_4      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 8));
54790             runningOrder -= 4;
54791         } else {
54792             switch (runningOrder) {
54793                 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;
54794                 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;
54795                 case 1: coefficients128_4 = _mm_set_epi32(0, 0,               0,               coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0,               0,               0); break;
54796             }
54797             runningOrder = 0;
54798         }
54799         if (runningOrder == 4) {
54800             coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
54801             samples128_8      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 12));
54802             runningOrder -= 4;
54803         } else {
54804             switch (runningOrder) {
54805                 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;
54806                 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;
54807                 case 1: coefficients128_8 = _mm_set_epi32(0, 0,                0,               coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0,                0,                0); break;
54808             }
54809             runningOrder = 0;
54810         }
54811         coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
54812         coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
54813         coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
54814     }
54815 #else
54816     switch (order)
54817     {
54818     case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
54819     case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
54820     case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
54821     case 9:  ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
54822     case 8:  ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
54823     case 7:  ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
54824     case 6:  ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
54825     case 5:  ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
54826     case 4:  ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
54827     case 3:  ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
54828     case 2:  ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
54829     case 1:  ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
54830     }
54831 #endif
54832     while (pDecodedSamples < pDecodedSamplesEnd) {
54833         __m128i prediction128;
54834         __m128i zeroCountPart128;
54835         __m128i riceParamPart128;
54836         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
54837             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
54838             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
54839             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
54840             return DRFLAC_FALSE;
54841         }
54842         zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
54843         riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
54844         riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
54845         riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
54846         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)));
54847         if (order <= 4) {
54848             for (i = 0; i < 4; i += 1) {
54849                 prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0);
54850                 prediction128 = drflac__mm_hadd_epi32(prediction128);
54851                 prediction128 = _mm_srai_epi32(prediction128, shift);
54852                 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
54853                 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
54854                 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
54855             }
54856         } else if (order <= 8) {
54857             for (i = 0; i < 4; i += 1) {
54858                 prediction128 =                              _mm_mullo_epi32(coefficients128_4, samples128_4);
54859                 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
54860                 prediction128 = drflac__mm_hadd_epi32(prediction128);
54861                 prediction128 = _mm_srai_epi32(prediction128, shift);
54862                 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
54863                 samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
54864                 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
54865                 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
54866             }
54867         } else {
54868             for (i = 0; i < 4; i += 1) {
54869                 prediction128 =                              _mm_mullo_epi32(coefficients128_8, samples128_8);
54870                 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_4, samples128_4));
54871                 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
54872                 prediction128 = drflac__mm_hadd_epi32(prediction128);
54873                 prediction128 = _mm_srai_epi32(prediction128, shift);
54874                 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
54875                 samples128_8 = _mm_alignr_epi8(samples128_4,  samples128_8, 4);
54876                 samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
54877                 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
54878                 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
54879             }
54880         }
54881         _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
54882         pDecodedSamples += 4;
54883     }
54884     i = (count & ~3);
54885     while (i < (int)count) {
54886         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
54887             return DRFLAC_FALSE;
54888         }
54889         riceParamParts0 &= riceParamMask;
54890         riceParamParts0 |= (zeroCountParts0 << riceParam);
54891         riceParamParts0  = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
54892         pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
54893         i += 1;
54894         pDecodedSamples += 1;
54895     }
54896     return DRFLAC_TRUE;
54897 }
54898 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)
54899 {
54900     int i;
54901     drflac_uint32 riceParamMask;
54902     drflac_int32* pDecodedSamples    = pSamplesOut;
54903     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
54904     drflac_uint32 zeroCountParts0 = 0;
54905     drflac_uint32 zeroCountParts1 = 0;
54906     drflac_uint32 zeroCountParts2 = 0;
54907     drflac_uint32 zeroCountParts3 = 0;
54908     drflac_uint32 riceParamParts0 = 0;
54909     drflac_uint32 riceParamParts1 = 0;
54910     drflac_uint32 riceParamParts2 = 0;
54911     drflac_uint32 riceParamParts3 = 0;
54912     __m128i coefficients128_0;
54913     __m128i coefficients128_4;
54914     __m128i coefficients128_8;
54915     __m128i samples128_0;
54916     __m128i samples128_4;
54917     __m128i samples128_8;
54918     __m128i prediction128;
54919     __m128i riceParamMask128;
54920     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
54921     DRFLAC_ASSERT(order <= 12);
54922     riceParamMask    = (drflac_uint32)~((~0UL) << riceParam);
54923     riceParamMask128 = _mm_set1_epi32(riceParamMask);
54924     prediction128 = _mm_setzero_si128();
54925     coefficients128_0  = _mm_setzero_si128();
54926     coefficients128_4  = _mm_setzero_si128();
54927     coefficients128_8  = _mm_setzero_si128();
54928     samples128_0  = _mm_setzero_si128();
54929     samples128_4  = _mm_setzero_si128();
54930     samples128_8  = _mm_setzero_si128();
54931 #if 1
54932     {
54933         int runningOrder = order;
54934         if (runningOrder >= 4) {
54935             coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
54936             samples128_0      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 4));
54937             runningOrder -= 4;
54938         } else {
54939             switch (runningOrder) {
54940                 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;
54941                 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;
54942                 case 1: coefficients128_0 = _mm_set_epi32(0, 0,               0,               coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0,               0,               0); break;
54943             }
54944             runningOrder = 0;
54945         }
54946         if (runningOrder >= 4) {
54947             coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
54948             samples128_4      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 8));
54949             runningOrder -= 4;
54950         } else {
54951             switch (runningOrder) {
54952                 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;
54953                 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;
54954                 case 1: coefficients128_4 = _mm_set_epi32(0, 0,               0,               coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0,               0,               0); break;
54955             }
54956             runningOrder = 0;
54957         }
54958         if (runningOrder == 4) {
54959             coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
54960             samples128_8      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 12));
54961             runningOrder -= 4;
54962         } else {
54963             switch (runningOrder) {
54964                 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;
54965                 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;
54966                 case 1: coefficients128_8 = _mm_set_epi32(0, 0,                0,               coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0,                0,                0); break;
54967             }
54968             runningOrder = 0;
54969         }
54970         coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
54971         coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
54972         coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
54973     }
54974 #else
54975     switch (order)
54976     {
54977     case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
54978     case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
54979     case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
54980     case 9:  ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
54981     case 8:  ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
54982     case 7:  ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
54983     case 6:  ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
54984     case 5:  ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
54985     case 4:  ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
54986     case 3:  ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
54987     case 2:  ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
54988     case 1:  ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
54989     }
54990 #endif
54991     while (pDecodedSamples < pDecodedSamplesEnd) {
54992         __m128i zeroCountPart128;
54993         __m128i riceParamPart128;
54994         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
54995             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
54996             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
54997             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
54998             return DRFLAC_FALSE;
54999         }
55000         zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
55001         riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
55002         riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
55003         riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
55004         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)));
55005         for (i = 0; i < 4; i += 1) {
55006             prediction128 = _mm_xor_si128(prediction128, prediction128);
55007             switch (order)
55008             {
55009             case 12:
55010             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))));
55011             case 10:
55012             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))));
55013             case  8:
55014             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))));
55015             case  6:
55016             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))));
55017             case  4:
55018             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))));
55019             case  2:
55020             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))));
55021             }
55022             prediction128 = drflac__mm_hadd_epi64(prediction128);
55023             prediction128 = drflac__mm_srai_epi64(prediction128, shift);
55024             prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
55025             samples128_8 = _mm_alignr_epi8(samples128_4,  samples128_8, 4);
55026             samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
55027             samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
55028             riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
55029         }
55030         _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
55031         pDecodedSamples += 4;
55032     }
55033     i = (count & ~3);
55034     while (i < (int)count) {
55035         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
55036             return DRFLAC_FALSE;
55037         }
55038         riceParamParts0 &= riceParamMask;
55039         riceParamParts0 |= (zeroCountParts0 << riceParam);
55040         riceParamParts0  = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
55041         pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
55042         i += 1;
55043         pDecodedSamples += 1;
55044     }
55045     return DRFLAC_TRUE;
55046 }
55047 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)
55048 {
55049     DRFLAC_ASSERT(bs != NULL);
55050     DRFLAC_ASSERT(pSamplesOut != NULL);
55051     if (order > 0 && order <= 12) {
55052         if (bitsPerSample+shift > 32) {
55053             return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
55054         } else {
55055             return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
55056         }
55057     } else {
55058         return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
55059     }
55060 }
55061 #endif
55062 #if defined(DRFLAC_SUPPORT_NEON)
55063 static DRFLAC_INLINE void drflac__vst2q_s32(drflac_int32* p, int32x4x2_t x)
55064 {
55065     vst1q_s32(p+0, x.val[0]);
55066     vst1q_s32(p+4, x.val[1]);
55067 }
55068 static DRFLAC_INLINE void drflac__vst2q_u32(drflac_uint32* p, uint32x4x2_t x)
55069 {
55070     vst1q_u32(p+0, x.val[0]);
55071     vst1q_u32(p+4, x.val[1]);
55072 }
55073 static DRFLAC_INLINE void drflac__vst2q_f32(float* p, float32x4x2_t x)
55074 {
55075     vst1q_f32(p+0, x.val[0]);
55076     vst1q_f32(p+4, x.val[1]);
55077 }
55078 static DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x)
55079 {
55080     vst1q_s16(p, vcombine_s16(x.val[0], x.val[1]));
55081 }
55082 static DRFLAC_INLINE void drflac__vst2q_u16(drflac_uint16* p, uint16x4x2_t x)
55083 {
55084     vst1q_u16(p, vcombine_u16(x.val[0], x.val[1]));
55085 }
55086 static DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0)
55087 {
55088     drflac_int32 x[4];
55089     x[3] = x3;
55090     x[2] = x2;
55091     x[1] = x1;
55092     x[0] = x0;
55093     return vld1q_s32(x);
55094 }
55095 static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b)
55096 {
55097     return vextq_s32(b, a, 1);
55098 }
55099 static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b)
55100 {
55101     return vextq_u32(b, a, 1);
55102 }
55103 static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x)
55104 {
55105     int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x));
55106     return vpadd_s32(r, r);
55107 }
55108 static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x)
55109 {
55110     return vadd_s64(vget_high_s64(x), vget_low_s64(x));
55111 }
55112 static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x)
55113 {
55114     return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x)));
55115 }
55116 static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x)
55117 {
55118     return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF));
55119 }
55120 static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x)
55121 {
55122     return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF));
55123 }
55124 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)
55125 {
55126     int i;
55127     drflac_uint32 riceParamMask;
55128     drflac_int32* pDecodedSamples    = pSamplesOut;
55129     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
55130     drflac_uint32 zeroCountParts[4];
55131     drflac_uint32 riceParamParts[4];
55132     int32x4_t coefficients128_0;
55133     int32x4_t coefficients128_4;
55134     int32x4_t coefficients128_8;
55135     int32x4_t samples128_0;
55136     int32x4_t samples128_4;
55137     int32x4_t samples128_8;
55138     uint32x4_t riceParamMask128;
55139     int32x4_t riceParam128;
55140     int32x2_t shift64;
55141     uint32x4_t one128;
55142     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
55143     riceParamMask    = ~((~0UL) << riceParam);
55144     riceParamMask128 = vdupq_n_u32(riceParamMask);
55145     riceParam128 = vdupq_n_s32(riceParam);
55146     shift64 = vdup_n_s32(-shift);
55147     one128 = vdupq_n_u32(1);
55148     {
55149         int runningOrder = order;
55150         drflac_int32 tempC[4] = {0, 0, 0, 0};
55151         drflac_int32 tempS[4] = {0, 0, 0, 0};
55152         if (runningOrder >= 4) {
55153             coefficients128_0 = vld1q_s32(coefficients + 0);
55154             samples128_0      = vld1q_s32(pSamplesOut  - 4);
55155             runningOrder -= 4;
55156         } else {
55157             switch (runningOrder) {
55158                 case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3];
55159                 case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2];
55160                 case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1];
55161             }
55162             coefficients128_0 = vld1q_s32(tempC);
55163             samples128_0      = vld1q_s32(tempS);
55164             runningOrder = 0;
55165         }
55166         if (runningOrder >= 4) {
55167             coefficients128_4 = vld1q_s32(coefficients + 4);
55168             samples128_4      = vld1q_s32(pSamplesOut  - 8);
55169             runningOrder -= 4;
55170         } else {
55171             switch (runningOrder) {
55172                 case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7];
55173                 case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6];
55174                 case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5];
55175             }
55176             coefficients128_4 = vld1q_s32(tempC);
55177             samples128_4      = vld1q_s32(tempS);
55178             runningOrder = 0;
55179         }
55180         if (runningOrder == 4) {
55181             coefficients128_8 = vld1q_s32(coefficients + 8);
55182             samples128_8      = vld1q_s32(pSamplesOut  - 12);
55183             runningOrder -= 4;
55184         } else {
55185             switch (runningOrder) {
55186                 case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11];
55187                 case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10];
55188                 case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9];
55189             }
55190             coefficients128_8 = vld1q_s32(tempC);
55191             samples128_8      = vld1q_s32(tempS);
55192             runningOrder = 0;
55193         }
55194         coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
55195         coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
55196         coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
55197     }
55198     while (pDecodedSamples < pDecodedSamplesEnd) {
55199         int32x4_t prediction128;
55200         int32x2_t prediction64;
55201         uint32x4_t zeroCountPart128;
55202         uint32x4_t riceParamPart128;
55203         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
55204             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
55205             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
55206             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
55207             return DRFLAC_FALSE;
55208         }
55209         zeroCountPart128 = vld1q_u32(zeroCountParts);
55210         riceParamPart128 = vld1q_u32(riceParamParts);
55211         riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
55212         riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
55213         riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
55214         if (order <= 4) {
55215             for (i = 0; i < 4; i += 1) {
55216                 prediction128 = vmulq_s32(coefficients128_0, samples128_0);
55217                 prediction64 = drflac__vhaddq_s32(prediction128);
55218                 prediction64 = vshl_s32(prediction64, shift64);
55219                 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
55220                 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
55221                 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
55222             }
55223         } else if (order <= 8) {
55224             for (i = 0; i < 4; i += 1) {
55225                 prediction128 =                vmulq_s32(coefficients128_4, samples128_4);
55226                 prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
55227                 prediction64 = drflac__vhaddq_s32(prediction128);
55228                 prediction64 = vshl_s32(prediction64, shift64);
55229                 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
55230                 samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
55231                 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
55232                 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
55233             }
55234         } else {
55235             for (i = 0; i < 4; i += 1) {
55236                 prediction128 =                vmulq_s32(coefficients128_8, samples128_8);
55237                 prediction128 = vmlaq_s32(prediction128, coefficients128_4, samples128_4);
55238                 prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
55239                 prediction64 = drflac__vhaddq_s32(prediction128);
55240                 prediction64 = vshl_s32(prediction64, shift64);
55241                 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
55242                 samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
55243                 samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
55244                 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
55245                 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
55246             }
55247         }
55248         vst1q_s32(pDecodedSamples, samples128_0);
55249         pDecodedSamples += 4;
55250     }
55251     i = (count & ~3);
55252     while (i < (int)count) {
55253         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
55254             return DRFLAC_FALSE;
55255         }
55256         riceParamParts[0] &= riceParamMask;
55257         riceParamParts[0] |= (zeroCountParts[0] << riceParam);
55258         riceParamParts[0]  = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
55259         pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
55260         i += 1;
55261         pDecodedSamples += 1;
55262     }
55263     return DRFLAC_TRUE;
55264 }
55265 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)
55266 {
55267     int i;
55268     drflac_uint32 riceParamMask;
55269     drflac_int32* pDecodedSamples    = pSamplesOut;
55270     drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
55271     drflac_uint32 zeroCountParts[4];
55272     drflac_uint32 riceParamParts[4];
55273     int32x4_t coefficients128_0;
55274     int32x4_t coefficients128_4;
55275     int32x4_t coefficients128_8;
55276     int32x4_t samples128_0;
55277     int32x4_t samples128_4;
55278     int32x4_t samples128_8;
55279     uint32x4_t riceParamMask128;
55280     int32x4_t riceParam128;
55281     int64x1_t shift64;
55282     uint32x4_t one128;
55283     const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
55284     riceParamMask    = ~((~0UL) << riceParam);
55285     riceParamMask128 = vdupq_n_u32(riceParamMask);
55286     riceParam128 = vdupq_n_s32(riceParam);
55287     shift64 = vdup_n_s64(-shift);
55288     one128 = vdupq_n_u32(1);
55289     {
55290         int runningOrder = order;
55291         drflac_int32 tempC[4] = {0, 0, 0, 0};
55292         drflac_int32 tempS[4] = {0, 0, 0, 0};
55293         if (runningOrder >= 4) {
55294             coefficients128_0 = vld1q_s32(coefficients + 0);
55295             samples128_0      = vld1q_s32(pSamplesOut  - 4);
55296             runningOrder -= 4;
55297         } else {
55298             switch (runningOrder) {
55299                 case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3];
55300                 case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2];
55301                 case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1];
55302             }
55303             coefficients128_0 = vld1q_s32(tempC);
55304             samples128_0      = vld1q_s32(tempS);
55305             runningOrder = 0;
55306         }
55307         if (runningOrder >= 4) {
55308             coefficients128_4 = vld1q_s32(coefficients + 4);
55309             samples128_4      = vld1q_s32(pSamplesOut  - 8);
55310             runningOrder -= 4;
55311         } else {
55312             switch (runningOrder) {
55313                 case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7];
55314                 case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6];
55315                 case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5];
55316             }
55317             coefficients128_4 = vld1q_s32(tempC);
55318             samples128_4      = vld1q_s32(tempS);
55319             runningOrder = 0;
55320         }
55321         if (runningOrder == 4) {
55322             coefficients128_8 = vld1q_s32(coefficients + 8);
55323             samples128_8      = vld1q_s32(pSamplesOut  - 12);
55324             runningOrder -= 4;
55325         } else {
55326             switch (runningOrder) {
55327                 case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11];
55328                 case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10];
55329                 case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9];
55330             }
55331             coefficients128_8 = vld1q_s32(tempC);
55332             samples128_8      = vld1q_s32(tempS);
55333             runningOrder = 0;
55334         }
55335         coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
55336         coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
55337         coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
55338     }
55339     while (pDecodedSamples < pDecodedSamplesEnd) {
55340         int64x2_t prediction128;
55341         uint32x4_t zeroCountPart128;
55342         uint32x4_t riceParamPart128;
55343         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
55344             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
55345             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
55346             !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
55347             return DRFLAC_FALSE;
55348         }
55349         zeroCountPart128 = vld1q_u32(zeroCountParts);
55350         riceParamPart128 = vld1q_u32(riceParamParts);
55351         riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
55352         riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
55353         riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
55354         for (i = 0; i < 4; i += 1) {
55355             int64x1_t prediction64;
55356             prediction128 = veorq_s64(prediction128, prediction128);
55357             switch (order)
55358             {
55359             case 12:
55360             case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8)));
55361             case 10:
55362             case  9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8)));
55363             case  8:
55364             case  7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4)));
55365             case  6:
55366             case  5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4)));
55367             case  4:
55368             case  3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0)));
55369             case  2:
55370             case  1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0)));
55371             }
55372             prediction64 = drflac__vhaddq_s64(prediction128);
55373             prediction64 = vshl_s64(prediction64, shift64);
55374             prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0)));
55375             samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
55376             samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
55377             samples128_0 = drflac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0);
55378             riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
55379         }
55380         vst1q_s32(pDecodedSamples, samples128_0);
55381         pDecodedSamples += 4;
55382     }
55383     i = (count & ~3);
55384     while (i < (int)count) {
55385         if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
55386             return DRFLAC_FALSE;
55387         }
55388         riceParamParts[0] &= riceParamMask;
55389         riceParamParts[0] |= (zeroCountParts[0] << riceParam);
55390         riceParamParts[0]  = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
55391         pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
55392         i += 1;
55393         pDecodedSamples += 1;
55394     }
55395     return DRFLAC_TRUE;
55396 }
55397 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)
55398 {
55399     DRFLAC_ASSERT(bs != NULL);
55400     DRFLAC_ASSERT(pSamplesOut != NULL);
55401     if (order > 0 && order <= 12) {
55402         if (bitsPerSample+shift > 32) {
55403             return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
55404         } else {
55405             return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
55406         }
55407     } else {
55408         return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
55409     }
55410 }
55411 #endif
55412 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)
55413 {
55414 #if defined(DRFLAC_SUPPORT_SSE41)
55415     if (drflac__gIsSSE41Supported) {
55416         return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
55417     } else
55418 #elif defined(DRFLAC_SUPPORT_NEON)
55419     if (drflac__gIsNEONSupported) {
55420         return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
55421     } else
55422 #endif
55423     {
55424     #if 0
55425         return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
55426     #else
55427         return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
55428     #endif
55429     }
55430 }
55431 static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam)
55432 {
55433     drflac_uint32 i;
55434     DRFLAC_ASSERT(bs != NULL);
55435     for (i = 0; i < count; ++i) {
55436         if (!drflac__seek_rice_parts(bs, riceParam)) {
55437             return DRFLAC_FALSE;
55438         }
55439     }
55440     return DRFLAC_TRUE;
55441 }
55442 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)
55443 {
55444     drflac_uint32 i;
55445     DRFLAC_ASSERT(bs != NULL);
55446     DRFLAC_ASSERT(unencodedBitsPerSample <= 31);
55447     DRFLAC_ASSERT(pSamplesOut != NULL);
55448     for (i = 0; i < count; ++i) {
55449         if (unencodedBitsPerSample > 0) {
55450             if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) {
55451                 return DRFLAC_FALSE;
55452             }
55453         } else {
55454             pSamplesOut[i] = 0;
55455         }
55456         if (bitsPerSample >= 24) {
55457             pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
55458         } else {
55459             pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
55460         }
55461     }
55462     return DRFLAC_TRUE;
55463 }
55464 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)
55465 {
55466     drflac_uint8 residualMethod;
55467     drflac_uint8 partitionOrder;
55468     drflac_uint32 samplesInPartition;
55469     drflac_uint32 partitionsRemaining;
55470     DRFLAC_ASSERT(bs != NULL);
55471     DRFLAC_ASSERT(blockSize != 0);
55472     DRFLAC_ASSERT(pDecodedSamples != NULL);
55473     if (!drflac__read_uint8(bs, 2, &residualMethod)) {
55474         return DRFLAC_FALSE;
55475     }
55476     if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
55477         return DRFLAC_FALSE;
55478     }
55479     pDecodedSamples += order;
55480     if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
55481         return DRFLAC_FALSE;
55482     }
55483     if (partitionOrder > 8) {
55484         return DRFLAC_FALSE;
55485     }
55486     if ((blockSize / (1 << partitionOrder)) < order) {
55487         return DRFLAC_FALSE;
55488     }
55489     samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
55490     partitionsRemaining = (1 << partitionOrder);
55491     for (;;) {
55492         drflac_uint8 riceParam = 0;
55493         if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
55494             if (!drflac__read_uint8(bs, 4, &riceParam)) {
55495                 return DRFLAC_FALSE;
55496             }
55497             if (riceParam == 15) {
55498                 riceParam = 0xFF;
55499             }
55500         } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
55501             if (!drflac__read_uint8(bs, 5, &riceParam)) {
55502                 return DRFLAC_FALSE;
55503             }
55504             if (riceParam == 31) {
55505                 riceParam = 0xFF;
55506             }
55507         }
55508         if (riceParam != 0xFF) {
55509             if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
55510                 return DRFLAC_FALSE;
55511             }
55512         } else {
55513             drflac_uint8 unencodedBitsPerSample = 0;
55514             if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
55515                 return DRFLAC_FALSE;
55516             }
55517             if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) {
55518                 return DRFLAC_FALSE;
55519             }
55520         }
55521         pDecodedSamples += samplesInPartition;
55522         if (partitionsRemaining == 1) {
55523             break;
55524         }
55525         partitionsRemaining -= 1;
55526         if (partitionOrder != 0) {
55527             samplesInPartition = blockSize / (1 << partitionOrder);
55528         }
55529     }
55530     return DRFLAC_TRUE;
55531 }
55532 static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order)
55533 {
55534     drflac_uint8 residualMethod;
55535     drflac_uint8 partitionOrder;
55536     drflac_uint32 samplesInPartition;
55537     drflac_uint32 partitionsRemaining;
55538     DRFLAC_ASSERT(bs != NULL);
55539     DRFLAC_ASSERT(blockSize != 0);
55540     if (!drflac__read_uint8(bs, 2, &residualMethod)) {
55541         return DRFLAC_FALSE;
55542     }
55543     if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
55544         return DRFLAC_FALSE;
55545     }
55546     if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
55547         return DRFLAC_FALSE;
55548     }
55549     if (partitionOrder > 8) {
55550         return DRFLAC_FALSE;
55551     }
55552     if ((blockSize / (1 << partitionOrder)) <= order) {
55553         return DRFLAC_FALSE;
55554     }
55555     samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
55556     partitionsRemaining = (1 << partitionOrder);
55557     for (;;)
55558     {
55559         drflac_uint8 riceParam = 0;
55560         if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
55561             if (!drflac__read_uint8(bs, 4, &riceParam)) {
55562                 return DRFLAC_FALSE;
55563             }
55564             if (riceParam == 15) {
55565                 riceParam = 0xFF;
55566             }
55567         } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
55568             if (!drflac__read_uint8(bs, 5, &riceParam)) {
55569                 return DRFLAC_FALSE;
55570             }
55571             if (riceParam == 31) {
55572                 riceParam = 0xFF;
55573             }
55574         }
55575         if (riceParam != 0xFF) {
55576             if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) {
55577                 return DRFLAC_FALSE;
55578             }
55579         } else {
55580             drflac_uint8 unencodedBitsPerSample = 0;
55581             if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
55582                 return DRFLAC_FALSE;
55583             }
55584             if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) {
55585                 return DRFLAC_FALSE;
55586             }
55587         }
55588         if (partitionsRemaining == 1) {
55589             break;
55590         }
55591         partitionsRemaining -= 1;
55592         samplesInPartition = blockSize / (1 << partitionOrder);
55593     }
55594     return DRFLAC_TRUE;
55595 }
55596 static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
55597 {
55598     drflac_uint32 i;
55599     drflac_int32 sample;
55600     if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
55601         return DRFLAC_FALSE;
55602     }
55603     for (i = 0; i < blockSize; ++i) {
55604         pDecodedSamples[i] = sample;
55605     }
55606     return DRFLAC_TRUE;
55607 }
55608 static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
55609 {
55610     drflac_uint32 i;
55611     for (i = 0; i < blockSize; ++i) {
55612         drflac_int32 sample;
55613         if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
55614             return DRFLAC_FALSE;
55615         }
55616         pDecodedSamples[i] = sample;
55617     }
55618     return DRFLAC_TRUE;
55619 }
55620 static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
55621 {
55622     drflac_uint32 i;
55623     static drflac_int32 lpcCoefficientsTable[5][4] = {
55624         {0,  0, 0,  0},
55625         {1,  0, 0,  0},
55626         {2, -1, 0,  0},
55627         {3, -3, 1,  0},
55628         {4, -6, 4, -1}
55629     };
55630     for (i = 0; i < lpcOrder; ++i) {
55631         drflac_int32 sample;
55632         if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
55633             return DRFLAC_FALSE;
55634         }
55635         pDecodedSamples[i] = sample;
55636     }
55637     if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) {
55638         return DRFLAC_FALSE;
55639     }
55640     return DRFLAC_TRUE;
55641 }
55642 static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
55643 {
55644     drflac_uint8 i;
55645     drflac_uint8 lpcPrecision;
55646     drflac_int8 lpcShift;
55647     drflac_int32 coefficients[32];
55648     for (i = 0; i < lpcOrder; ++i) {
55649         drflac_int32 sample;
55650         if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
55651             return DRFLAC_FALSE;
55652         }
55653         pDecodedSamples[i] = sample;
55654     }
55655     if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
55656         return DRFLAC_FALSE;
55657     }
55658     if (lpcPrecision == 15) {
55659         return DRFLAC_FALSE;
55660     }
55661     lpcPrecision += 1;
55662     if (!drflac__read_int8(bs, 5, &lpcShift)) {
55663         return DRFLAC_FALSE;
55664     }
55665     if (lpcShift < 0) {
55666         return DRFLAC_FALSE;
55667     }
55668     DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients));
55669     for (i = 0; i < lpcOrder; ++i) {
55670         if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) {
55671             return DRFLAC_FALSE;
55672         }
55673     }
55674     if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) {
55675         return DRFLAC_FALSE;
55676     }
55677     return DRFLAC_TRUE;
55678 }
55679 static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header)
55680 {
55681     const drflac_uint32 sampleRateTable[12]  = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
55682     const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1};
55683     DRFLAC_ASSERT(bs != NULL);
55684     DRFLAC_ASSERT(header != NULL);
55685     for (;;) {
55686         drflac_uint8 crc8 = 0xCE;
55687         drflac_uint8 reserved = 0;
55688         drflac_uint8 blockingStrategy = 0;
55689         drflac_uint8 blockSize = 0;
55690         drflac_uint8 sampleRate = 0;
55691         drflac_uint8 channelAssignment = 0;
55692         drflac_uint8 bitsPerSample = 0;
55693         drflac_bool32 isVariableBlockSize;
55694         if (!drflac__find_and_seek_to_next_sync_code(bs)) {
55695             return DRFLAC_FALSE;
55696         }
55697         if (!drflac__read_uint8(bs, 1, &reserved)) {
55698             return DRFLAC_FALSE;
55699         }
55700         if (reserved == 1) {
55701             continue;
55702         }
55703         crc8 = drflac_crc8(crc8, reserved, 1);
55704         if (!drflac__read_uint8(bs, 1, &blockingStrategy)) {
55705             return DRFLAC_FALSE;
55706         }
55707         crc8 = drflac_crc8(crc8, blockingStrategy, 1);
55708         if (!drflac__read_uint8(bs, 4, &blockSize)) {
55709             return DRFLAC_FALSE;
55710         }
55711         if (blockSize == 0) {
55712             continue;
55713         }
55714         crc8 = drflac_crc8(crc8, blockSize, 4);
55715         if (!drflac__read_uint8(bs, 4, &sampleRate)) {
55716             return DRFLAC_FALSE;
55717         }
55718         crc8 = drflac_crc8(crc8, sampleRate, 4);
55719         if (!drflac__read_uint8(bs, 4, &channelAssignment)) {
55720             return DRFLAC_FALSE;
55721         }
55722         if (channelAssignment > 10) {
55723             continue;
55724         }
55725         crc8 = drflac_crc8(crc8, channelAssignment, 4);
55726         if (!drflac__read_uint8(bs, 3, &bitsPerSample)) {
55727             return DRFLAC_FALSE;
55728         }
55729         if (bitsPerSample == 3 || bitsPerSample == 7) {
55730             continue;
55731         }
55732         crc8 = drflac_crc8(crc8, bitsPerSample, 3);
55733         if (!drflac__read_uint8(bs, 1, &reserved)) {
55734             return DRFLAC_FALSE;
55735         }
55736         if (reserved == 1) {
55737             continue;
55738         }
55739         crc8 = drflac_crc8(crc8, reserved, 1);
55740         isVariableBlockSize = blockingStrategy == 1;
55741         if (isVariableBlockSize) {
55742             drflac_uint64 pcmFrameNumber;
55743             drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8);
55744             if (result != DRFLAC_SUCCESS) {
55745                 if (result == DRFLAC_AT_END) {
55746                     return DRFLAC_FALSE;
55747                 } else {
55748                     continue;
55749                 }
55750             }
55751             header->flacFrameNumber  = 0;
55752             header->pcmFrameNumber = pcmFrameNumber;
55753         } else {
55754             drflac_uint64 flacFrameNumber = 0;
55755             drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8);
55756             if (result != DRFLAC_SUCCESS) {
55757                 if (result == DRFLAC_AT_END) {
55758                     return DRFLAC_FALSE;
55759                 } else {
55760                     continue;
55761                 }
55762             }
55763             header->flacFrameNumber  = (drflac_uint32)flacFrameNumber;
55764             header->pcmFrameNumber = 0;
55765         }
55766         DRFLAC_ASSERT(blockSize > 0);
55767         if (blockSize == 1) {
55768             header->blockSizeInPCMFrames = 192;
55769         } else if (blockSize <= 5) {
55770             DRFLAC_ASSERT(blockSize >= 2);
55771             header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2));
55772         } else if (blockSize == 6) {
55773             if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) {
55774                 return DRFLAC_FALSE;
55775             }
55776             crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8);
55777             header->blockSizeInPCMFrames += 1;
55778         } else if (blockSize == 7) {
55779             if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) {
55780                 return DRFLAC_FALSE;
55781             }
55782             crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16);
55783             header->blockSizeInPCMFrames += 1;
55784         } else {
55785             DRFLAC_ASSERT(blockSize >= 8);
55786             header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8));
55787         }
55788         if (sampleRate <= 11) {
55789             header->sampleRate = sampleRateTable[sampleRate];
55790         } else if (sampleRate == 12) {
55791             if (!drflac__read_uint32(bs, 8, &header->sampleRate)) {
55792                 return DRFLAC_FALSE;
55793             }
55794             crc8 = drflac_crc8(crc8, header->sampleRate, 8);
55795             header->sampleRate *= 1000;
55796         } else if (sampleRate == 13) {
55797             if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
55798                 return DRFLAC_FALSE;
55799             }
55800             crc8 = drflac_crc8(crc8, header->sampleRate, 16);
55801         } else if (sampleRate == 14) {
55802             if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
55803                 return DRFLAC_FALSE;
55804             }
55805             crc8 = drflac_crc8(crc8, header->sampleRate, 16);
55806             header->sampleRate *= 10;
55807         } else {
55808             continue;
55809         }
55810         header->channelAssignment = channelAssignment;
55811         header->bitsPerSample = bitsPerSampleTable[bitsPerSample];
55812         if (header->bitsPerSample == 0) {
55813             header->bitsPerSample = streaminfoBitsPerSample;
55814         }
55815         if (!drflac__read_uint8(bs, 8, &header->crc8)) {
55816             return DRFLAC_FALSE;
55817         }
55818 #ifndef DR_FLAC_NO_CRC
55819         if (header->crc8 != crc8) {
55820             continue;
55821         }
55822 #endif
55823         return DRFLAC_TRUE;
55824     }
55825 }
55826 static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
55827 {
55828     drflac_uint8 header;
55829     int type;
55830     if (!drflac__read_uint8(bs, 8, &header)) {
55831         return DRFLAC_FALSE;
55832     }
55833     if ((header & 0x80) != 0) {
55834         return DRFLAC_FALSE;
55835     }
55836     type = (header & 0x7E) >> 1;
55837     if (type == 0) {
55838         pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
55839     } else if (type == 1) {
55840         pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM;
55841     } else {
55842         if ((type & 0x20) != 0) {
55843             pSubframe->subframeType = DRFLAC_SUBFRAME_LPC;
55844             pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1;
55845         } else if ((type & 0x08) != 0) {
55846             pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED;
55847             pSubframe->lpcOrder = (drflac_uint8)(type & 0x07);
55848             if (pSubframe->lpcOrder > 4) {
55849                 pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
55850                 pSubframe->lpcOrder = 0;
55851             }
55852         } else {
55853             pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
55854         }
55855     }
55856     if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) {
55857         return DRFLAC_FALSE;
55858     }
55859     pSubframe->wastedBitsPerSample = 0;
55860     if ((header & 0x01) == 1) {
55861         unsigned int wastedBitsPerSample;
55862         if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) {
55863             return DRFLAC_FALSE;
55864         }
55865         pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1;
55866     }
55867     return DRFLAC_TRUE;
55868 }
55869 static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut)
55870 {
55871     drflac_subframe* pSubframe;
55872     drflac_uint32 subframeBitsPerSample;
55873     DRFLAC_ASSERT(bs != NULL);
55874     DRFLAC_ASSERT(frame != NULL);
55875     pSubframe = frame->subframes + subframeIndex;
55876     if (!drflac__read_subframe_header(bs, pSubframe)) {
55877         return DRFLAC_FALSE;
55878     }
55879     subframeBitsPerSample = frame->header.bitsPerSample;
55880     if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
55881         subframeBitsPerSample += 1;
55882     } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
55883         subframeBitsPerSample += 1;
55884     }
55885     if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
55886         return DRFLAC_FALSE;
55887     }
55888     subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
55889     pSubframe->pSamplesS32 = pDecodedSamplesOut;
55890     switch (pSubframe->subframeType)
55891     {
55892         case DRFLAC_SUBFRAME_CONSTANT:
55893         {
55894             drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
55895         } break;
55896         case DRFLAC_SUBFRAME_VERBATIM:
55897         {
55898             drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
55899         } break;
55900         case DRFLAC_SUBFRAME_FIXED:
55901         {
55902             drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
55903         } break;
55904         case DRFLAC_SUBFRAME_LPC:
55905         {
55906             drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
55907         } break;
55908         default: return DRFLAC_FALSE;
55909     }
55910     return DRFLAC_TRUE;
55911 }
55912 static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
55913 {
55914     drflac_subframe* pSubframe;
55915     drflac_uint32 subframeBitsPerSample;
55916     DRFLAC_ASSERT(bs != NULL);
55917     DRFLAC_ASSERT(frame != NULL);
55918     pSubframe = frame->subframes + subframeIndex;
55919     if (!drflac__read_subframe_header(bs, pSubframe)) {
55920         return DRFLAC_FALSE;
55921     }
55922     subframeBitsPerSample = frame->header.bitsPerSample;
55923     if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
55924         subframeBitsPerSample += 1;
55925     } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
55926         subframeBitsPerSample += 1;
55927     }
55928     if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
55929         return DRFLAC_FALSE;
55930     }
55931     subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
55932     pSubframe->pSamplesS32 = NULL;
55933     switch (pSubframe->subframeType)
55934     {
55935         case DRFLAC_SUBFRAME_CONSTANT:
55936         {
55937             if (!drflac__seek_bits(bs, subframeBitsPerSample)) {
55938                 return DRFLAC_FALSE;
55939             }
55940         } break;
55941         case DRFLAC_SUBFRAME_VERBATIM:
55942         {
55943             unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample;
55944             if (!drflac__seek_bits(bs, bitsToSeek)) {
55945                 return DRFLAC_FALSE;
55946             }
55947         } break;
55948         case DRFLAC_SUBFRAME_FIXED:
55949         {
55950             unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
55951             if (!drflac__seek_bits(bs, bitsToSeek)) {
55952                 return DRFLAC_FALSE;
55953             }
55954             if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
55955                 return DRFLAC_FALSE;
55956             }
55957         } break;
55958         case DRFLAC_SUBFRAME_LPC:
55959         {
55960             drflac_uint8 lpcPrecision;
55961             unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
55962             if (!drflac__seek_bits(bs, bitsToSeek)) {
55963                 return DRFLAC_FALSE;
55964             }
55965             if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
55966                 return DRFLAC_FALSE;
55967             }
55968             if (lpcPrecision == 15) {
55969                 return DRFLAC_FALSE;
55970             }
55971             lpcPrecision += 1;
55972             bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5;
55973             if (!drflac__seek_bits(bs, bitsToSeek)) {
55974                 return DRFLAC_FALSE;
55975             }
55976             if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
55977                 return DRFLAC_FALSE;
55978             }
55979         } break;
55980         default: return DRFLAC_FALSE;
55981     }
55982     return DRFLAC_TRUE;
55983 }
55984 static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment)
55985 {
55986     drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2};
55987     DRFLAC_ASSERT(channelAssignment <= 10);
55988     return lookup[channelAssignment];
55989 }
55990 static drflac_result drflac__decode_flac_frame(drflac* pFlac)
55991 {
55992     int channelCount;
55993     int i;
55994     drflac_uint8 paddingSizeInBits;
55995     drflac_uint16 desiredCRC16;
55996 #ifndef DR_FLAC_NO_CRC
55997     drflac_uint16 actualCRC16;
55998 #endif
55999     DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes));
56000     if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) {
56001         return DRFLAC_ERROR;
56002     }
56003     channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
56004     if (channelCount != (int)pFlac->channels) {
56005         return DRFLAC_ERROR;
56006     }
56007     for (i = 0; i < channelCount; ++i) {
56008         if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) {
56009             return DRFLAC_ERROR;
56010         }
56011     }
56012     paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7);
56013     if (paddingSizeInBits > 0) {
56014         drflac_uint8 padding = 0;
56015         if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) {
56016             return DRFLAC_AT_END;
56017         }
56018     }
56019 #ifndef DR_FLAC_NO_CRC
56020     actualCRC16 = drflac__flush_crc16(&pFlac->bs);
56021 #endif
56022     if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
56023         return DRFLAC_AT_END;
56024     }
56025 #ifndef DR_FLAC_NO_CRC
56026     if (actualCRC16 != desiredCRC16) {
56027         return DRFLAC_CRC_MISMATCH;
56028     }
56029 #endif
56030     pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
56031     return DRFLAC_SUCCESS;
56032 }
56033 static drflac_result drflac__seek_flac_frame(drflac* pFlac)
56034 {
56035     int channelCount;
56036     int i;
56037     drflac_uint16 desiredCRC16;
56038 #ifndef DR_FLAC_NO_CRC
56039     drflac_uint16 actualCRC16;
56040 #endif
56041     channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
56042     for (i = 0; i < channelCount; ++i) {
56043         if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) {
56044             return DRFLAC_ERROR;
56045         }
56046     }
56047     if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) {
56048         return DRFLAC_ERROR;
56049     }
56050 #ifndef DR_FLAC_NO_CRC
56051     actualCRC16 = drflac__flush_crc16(&pFlac->bs);
56052 #endif
56053     if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
56054         return DRFLAC_AT_END;
56055     }
56056 #ifndef DR_FLAC_NO_CRC
56057     if (actualCRC16 != desiredCRC16) {
56058         return DRFLAC_CRC_MISMATCH;
56059     }
56060 #endif
56061     return DRFLAC_SUCCESS;
56062 }
56063 static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac)
56064 {
56065     DRFLAC_ASSERT(pFlac != NULL);
56066     for (;;) {
56067         drflac_result result;
56068         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56069             return DRFLAC_FALSE;
56070         }
56071         result = drflac__decode_flac_frame(pFlac);
56072         if (result != DRFLAC_SUCCESS) {
56073             if (result == DRFLAC_CRC_MISMATCH) {
56074                 continue;
56075             } else {
56076                 return DRFLAC_FALSE;
56077             }
56078         }
56079         return DRFLAC_TRUE;
56080     }
56081 }
56082 static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame)
56083 {
56084     drflac_uint64 firstPCMFrame;
56085     drflac_uint64 lastPCMFrame;
56086     DRFLAC_ASSERT(pFlac != NULL);
56087     firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber;
56088     if (firstPCMFrame == 0) {
56089         firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames;
56090     }
56091     lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
56092     if (lastPCMFrame > 0) {
56093         lastPCMFrame -= 1;
56094     }
56095     if (pFirstPCMFrame) {
56096         *pFirstPCMFrame = firstPCMFrame;
56097     }
56098     if (pLastPCMFrame) {
56099         *pLastPCMFrame = lastPCMFrame;
56100     }
56101 }
56102 static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac)
56103 {
56104     drflac_bool32 result;
56105     DRFLAC_ASSERT(pFlac != NULL);
56106     result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes);
56107     DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
56108     pFlac->currentPCMFrame = 0;
56109     return result;
56110 }
56111 static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac)
56112 {
56113     DRFLAC_ASSERT(pFlac != NULL);
56114     return drflac__seek_flac_frame(pFlac);
56115 }
56116 static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek)
56117 {
56118     drflac_uint64 pcmFramesRead = 0;
56119     while (pcmFramesToSeek > 0) {
56120         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
56121             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
56122                 break;
56123             }
56124         } else {
56125             if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) {
56126                 pcmFramesRead   += pcmFramesToSeek;
56127                 pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek;
56128                 pcmFramesToSeek  = 0;
56129             } else {
56130                 pcmFramesRead   += pFlac->currentFLACFrame.pcmFramesRemaining;
56131                 pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining;
56132                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
56133             }
56134         }
56135     }
56136     pFlac->currentPCMFrame += pcmFramesRead;
56137     return pcmFramesRead;
56138 }
56139 static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex)
56140 {
56141     drflac_bool32 isMidFrame = DRFLAC_FALSE;
56142     drflac_uint64 runningPCMFrameCount;
56143     DRFLAC_ASSERT(pFlac != NULL);
56144     if (pcmFrameIndex >= pFlac->currentPCMFrame) {
56145         runningPCMFrameCount = pFlac->currentPCMFrame;
56146         if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
56147             if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56148                 return DRFLAC_FALSE;
56149             }
56150         } else {
56151             isMidFrame = DRFLAC_TRUE;
56152         }
56153     } else {
56154         runningPCMFrameCount = 0;
56155         if (!drflac__seek_to_first_frame(pFlac)) {
56156             return DRFLAC_FALSE;
56157         }
56158         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56159             return DRFLAC_FALSE;
56160         }
56161     }
56162     for (;;) {
56163         drflac_uint64 pcmFrameCountInThisFLACFrame;
56164         drflac_uint64 firstPCMFrameInFLACFrame = 0;
56165         drflac_uint64 lastPCMFrameInFLACFrame = 0;
56166         drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
56167         pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
56168         if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
56169             drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
56170             if (!isMidFrame) {
56171                 drflac_result result = drflac__decode_flac_frame(pFlac);
56172                 if (result == DRFLAC_SUCCESS) {
56173                     return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
56174                 } else {
56175                     if (result == DRFLAC_CRC_MISMATCH) {
56176                         goto next_iteration;
56177                     } else {
56178                         return DRFLAC_FALSE;
56179                     }
56180                 }
56181             } else {
56182                 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
56183             }
56184         } else {
56185             if (!isMidFrame) {
56186                 drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
56187                 if (result == DRFLAC_SUCCESS) {
56188                     runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
56189                 } else {
56190                     if (result == DRFLAC_CRC_MISMATCH) {
56191                         goto next_iteration;
56192                     } else {
56193                         return DRFLAC_FALSE;
56194                     }
56195                 }
56196             } else {
56197                 runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
56198                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
56199                 isMidFrame = DRFLAC_FALSE;
56200             }
56201             if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
56202                 return DRFLAC_TRUE;
56203             }
56204         }
56205     next_iteration:
56206         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56207             return DRFLAC_FALSE;
56208         }
56209     }
56210 }
56211 #if !defined(DR_FLAC_NO_CRC)
56212 #define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f
56213 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)
56214 {
56215     DRFLAC_ASSERT(pFlac != NULL);
56216     DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL);
56217     DRFLAC_ASSERT(targetByte >= rangeLo);
56218     DRFLAC_ASSERT(targetByte <= rangeHi);
56219     *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes;
56220     for (;;) {
56221         drflac_uint64 lastTargetByte = targetByte;
56222         if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) {
56223             if (targetByte == 0) {
56224                 drflac__seek_to_first_frame(pFlac);
56225                 return DRFLAC_FALSE;
56226             }
56227             targetByte = rangeLo + ((rangeHi - rangeLo)/2);
56228             rangeHi = targetByte;
56229         } else {
56230             DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
56231 #if 1
56232             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
56233                 targetByte = rangeLo + ((rangeHi - rangeLo)/2);
56234                 rangeHi = targetByte;
56235             } else {
56236                 break;
56237             }
56238 #else
56239             if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56240                 targetByte = rangeLo + ((rangeHi - rangeLo)/2);
56241                 rangeHi = targetByte;
56242             } else {
56243                 break;
56244             }
56245 #endif
56246         }
56247         if(targetByte == lastTargetByte) {
56248             return DRFLAC_FALSE;
56249         }
56250     }
56251     drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
56252     DRFLAC_ASSERT(targetByte <= rangeHi);
56253     *pLastSuccessfulSeekOffset = targetByte;
56254     return DRFLAC_TRUE;
56255 }
56256 static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset)
56257 {
56258 #if 0
56259     if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) {
56260         if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) {
56261             return DRFLAC_FALSE;
56262         }
56263     }
56264 #endif
56265     return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset;
56266 }
56267 static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi)
56268 {
56269     drflac_uint64 targetByte;
56270     drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount;
56271     drflac_uint64 pcmRangeHi = 0;
56272     drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1;
56273     drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo;
56274     drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
56275     targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO);
56276     if (targetByte > byteRangeHi) {
56277         targetByte = byteRangeHi;
56278     }
56279     for (;;) {
56280         if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) {
56281             drflac_uint64 newPCMRangeLo;
56282             drflac_uint64 newPCMRangeHi;
56283             drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi);
56284             if (pcmRangeLo == newPCMRangeLo) {
56285                 if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) {
56286                     break;
56287                 }
56288                 if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
56289                     return DRFLAC_TRUE;
56290                 } else {
56291                     break;
56292                 }
56293             }
56294             pcmRangeLo = newPCMRangeLo;
56295             pcmRangeHi = newPCMRangeHi;
56296             if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) {
56297                 if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) {
56298                     return DRFLAC_TRUE;
56299                 } else {
56300                     break;
56301                 }
56302             } else {
56303                 const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
56304                 if (pcmRangeLo > pcmFrameIndex) {
56305                     byteRangeHi = lastSuccessfulSeekOffset;
56306                     if (byteRangeLo > byteRangeHi) {
56307                         byteRangeLo = byteRangeHi;
56308                     }
56309                     targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2);
56310                     if (targetByte < byteRangeLo) {
56311                         targetByte = byteRangeLo;
56312                     }
56313                 } else  {
56314                     if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) {
56315                         if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
56316                             return DRFLAC_TRUE;
56317                         } else {
56318                             break;
56319                         }
56320                     } else {
56321                         byteRangeLo = lastSuccessfulSeekOffset;
56322                         if (byteRangeHi < byteRangeLo) {
56323                             byteRangeHi = byteRangeLo;
56324                         }
56325                         targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
56326                         if (targetByte > byteRangeHi) {
56327                             targetByte = byteRangeHi;
56328                         }
56329                         if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) {
56330                             closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset;
56331                         }
56332                     }
56333                 }
56334             }
56335         } else {
56336             break;
56337         }
56338     }
56339     drflac__seek_to_first_frame(pFlac);
56340     return DRFLAC_FALSE;
56341 }
56342 static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex)
56343 {
56344     drflac_uint64 byteRangeLo;
56345     drflac_uint64 byteRangeHi;
56346     drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
56347     if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) {
56348         return DRFLAC_FALSE;
56349     }
56350     if (pcmFrameIndex < seekForwardThreshold) {
56351         return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex;
56352     }
56353     byteRangeLo = pFlac->firstFLACFramePosInBytes;
56354     byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
56355     return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi);
56356 }
56357 #endif
56358 static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex)
56359 {
56360     drflac_uint32 iClosestSeekpoint = 0;
56361     drflac_bool32 isMidFrame = DRFLAC_FALSE;
56362     drflac_uint64 runningPCMFrameCount;
56363     drflac_uint32 iSeekpoint;
56364     DRFLAC_ASSERT(pFlac != NULL);
56365     if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
56366         return DRFLAC_FALSE;
56367     }
56368     for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
56369         if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
56370             break;
56371         }
56372         iClosestSeekpoint = iSeekpoint;
56373     }
56374     if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) {
56375         return DRFLAC_FALSE;
56376     }
56377     if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) {
56378         return DRFLAC_FALSE;
56379     }
56380 #if !defined(DR_FLAC_NO_CRC)
56381     if (pFlac->totalPCMFrameCount > 0) {
56382         drflac_uint64 byteRangeLo;
56383         drflac_uint64 byteRangeHi;
56384         byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
56385         byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset;
56386         if (iClosestSeekpoint < pFlac->seekpointCount-1) {
56387             drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1;
56388             if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) {
56389                 return DRFLAC_FALSE;
56390             }
56391             if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) {
56392                 byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1;
56393             }
56394         }
56395         if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
56396             if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56397                 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
56398                 if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) {
56399                     return DRFLAC_TRUE;
56400                 }
56401             }
56402         }
56403     }
56404 #endif
56405     if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) {
56406         runningPCMFrameCount = pFlac->currentPCMFrame;
56407         if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
56408             if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56409                 return DRFLAC_FALSE;
56410             }
56411         } else {
56412             isMidFrame = DRFLAC_TRUE;
56413         }
56414     } else {
56415         runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame;
56416         if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
56417             return DRFLAC_FALSE;
56418         }
56419         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56420             return DRFLAC_FALSE;
56421         }
56422     }
56423     for (;;) {
56424         drflac_uint64 pcmFrameCountInThisFLACFrame;
56425         drflac_uint64 firstPCMFrameInFLACFrame = 0;
56426         drflac_uint64 lastPCMFrameInFLACFrame = 0;
56427         drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
56428         pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
56429         if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
56430             drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
56431             if (!isMidFrame) {
56432                 drflac_result result = drflac__decode_flac_frame(pFlac);
56433                 if (result == DRFLAC_SUCCESS) {
56434                     return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
56435                 } else {
56436                     if (result == DRFLAC_CRC_MISMATCH) {
56437                         goto next_iteration;
56438                     } else {
56439                         return DRFLAC_FALSE;
56440                     }
56441                 }
56442             } else {
56443                 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
56444             }
56445         } else {
56446             if (!isMidFrame) {
56447                 drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
56448                 if (result == DRFLAC_SUCCESS) {
56449                     runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
56450                 } else {
56451                     if (result == DRFLAC_CRC_MISMATCH) {
56452                         goto next_iteration;
56453                     } else {
56454                         return DRFLAC_FALSE;
56455                     }
56456                 }
56457             } else {
56458                 runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
56459                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
56460                 isMidFrame = DRFLAC_FALSE;
56461             }
56462             if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
56463                 return DRFLAC_TRUE;
56464             }
56465         }
56466     next_iteration:
56467         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
56468             return DRFLAC_FALSE;
56469         }
56470     }
56471 }
56472 #ifndef DR_FLAC_NO_OGG
56473 typedef struct
56474 {
56475     drflac_uint8 capturePattern[4];
56476     drflac_uint8 structureVersion;
56477     drflac_uint8 headerType;
56478     drflac_uint64 granulePosition;
56479     drflac_uint32 serialNumber;
56480     drflac_uint32 sequenceNumber;
56481     drflac_uint32 checksum;
56482     drflac_uint8 segmentCount;
56483     drflac_uint8 segmentTable[255];
56484 } drflac_ogg_page_header;
56485 #endif
56486 typedef struct
56487 {
56488     drflac_read_proc onRead;
56489     drflac_seek_proc onSeek;
56490     drflac_meta_proc onMeta;
56491     drflac_container container;
56492     void* pUserData;
56493     void* pUserDataMD;
56494     drflac_uint32 sampleRate;
56495     drflac_uint8  channels;
56496     drflac_uint8  bitsPerSample;
56497     drflac_uint64 totalPCMFrameCount;
56498     drflac_uint16 maxBlockSizeInPCMFrames;
56499     drflac_uint64 runningFilePos;
56500     drflac_bool32 hasStreamInfoBlock;
56501     drflac_bool32 hasMetadataBlocks;
56502     drflac_bs bs;
56503     drflac_frame_header firstFrameHeader;
56504 #ifndef DR_FLAC_NO_OGG
56505     drflac_uint32 oggSerial;
56506     drflac_uint64 oggFirstBytePos;
56507     drflac_ogg_page_header oggBosHeader;
56508 #endif
56509 } drflac_init_info;
56510 static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
56511 {
56512     blockHeader = drflac__be2host_32(blockHeader);
56513     *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31);
56514     *blockType   = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24);
56515     *blockSize   =                (blockHeader & 0x00FFFFFFUL);
56516 }
56517 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)
56518 {
56519     drflac_uint32 blockHeader;
56520     *blockSize = 0;
56521     if (onRead(pUserData, &blockHeader, 4) != 4) {
56522         return DRFLAC_FALSE;
56523     }
56524     drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
56525     return DRFLAC_TRUE;
56526 }
56527 static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
56528 {
56529     drflac_uint32 blockSizes;
56530     drflac_uint64 frameSizes = 0;
56531     drflac_uint64 importantProps;
56532     drflac_uint8 md5[16];
56533     if (onRead(pUserData, &blockSizes, 4) != 4) {
56534         return DRFLAC_FALSE;
56535     }
56536     if (onRead(pUserData, &frameSizes, 6) != 6) {
56537         return DRFLAC_FALSE;
56538     }
56539     if (onRead(pUserData, &importantProps, 8) != 8) {
56540         return DRFLAC_FALSE;
56541     }
56542     if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
56543         return DRFLAC_FALSE;
56544     }
56545     blockSizes     = drflac__be2host_32(blockSizes);
56546     frameSizes     = drflac__be2host_64(frameSizes);
56547     importantProps = drflac__be2host_64(importantProps);
56548     pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16);
56549     pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF);
56550     pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes     &  (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40);
56551     pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes     &  (((drflac_uint64)0x00FFFFFF << 16) <<  0)) >> 16);
56552     pStreamInfo->sampleRate              = (drflac_uint32)((importantProps &  (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44);
56553     pStreamInfo->channels                = (drflac_uint8 )((importantProps &  (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1;
56554     pStreamInfo->bitsPerSample           = (drflac_uint8 )((importantProps &  (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1;
56555     pStreamInfo->totalPCMFrameCount      =                ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF)));
56556     DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5));
56557     return DRFLAC_TRUE;
56558 }
56559 static void* drflac__malloc_default(size_t sz, void* pUserData)
56560 {
56561     (void)pUserData;
56562     return DRFLAC_MALLOC(sz);
56563 }
56564 static void* drflac__realloc_default(void* p, size_t sz, void* pUserData)
56565 {
56566     (void)pUserData;
56567     return DRFLAC_REALLOC(p, sz);
56568 }
56569 static void drflac__free_default(void* p, void* pUserData)
56570 {
56571     (void)pUserData;
56572     DRFLAC_FREE(p);
56573 }
56574 static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks)
56575 {
56576     if (pAllocationCallbacks == NULL) {
56577         return NULL;
56578     }
56579     if (pAllocationCallbacks->onMalloc != NULL) {
56580         return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
56581     }
56582     if (pAllocationCallbacks->onRealloc != NULL) {
56583         return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
56584     }
56585     return NULL;
56586 }
56587 static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks)
56588 {
56589     if (pAllocationCallbacks == NULL) {
56590         return NULL;
56591     }
56592     if (pAllocationCallbacks->onRealloc != NULL) {
56593         return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
56594     }
56595     if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
56596         void* p2;
56597         p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
56598         if (p2 == NULL) {
56599             return NULL;
56600         }
56601         if (p != NULL) {
56602             DRFLAC_COPY_MEMORY(p2, p, szOld);
56603             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
56604         }
56605         return p2;
56606     }
56607     return NULL;
56608 }
56609 static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
56610 {
56611     if (p == NULL || pAllocationCallbacks == NULL) {
56612         return;
56613     }
56614     if (pAllocationCallbacks->onFree != NULL) {
56615         pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
56616     }
56617 }
56618 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)
56619 {
56620     drflac_uint64 runningFilePos = 42;
56621     drflac_uint64 seektablePos   = 0;
56622     drflac_uint32 seektableSize  = 0;
56623     for (;;) {
56624         drflac_metadata metadata;
56625         drflac_uint8 isLastBlock = 0;
56626         drflac_uint8 blockType;
56627         drflac_uint32 blockSize;
56628         if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
56629             return DRFLAC_FALSE;
56630         }
56631         runningFilePos += 4;
56632         metadata.type = blockType;
56633         metadata.pRawData = NULL;
56634         metadata.rawDataSize = 0;
56635         switch (blockType)
56636         {
56637             case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION:
56638             {
56639                 if (blockSize < 4) {
56640                     return DRFLAC_FALSE;
56641                 }
56642                 if (onMeta) {
56643                     void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
56644                     if (pRawData == NULL) {
56645                         return DRFLAC_FALSE;
56646                     }
56647                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
56648                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56649                         return DRFLAC_FALSE;
56650                     }
56651                     metadata.pRawData = pRawData;
56652                     metadata.rawDataSize = blockSize;
56653                     metadata.data.application.id       = drflac__be2host_32(*(drflac_uint32*)pRawData);
56654                     metadata.data.application.pData    = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32));
56655                     metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32);
56656                     onMeta(pUserDataMD, &metadata);
56657                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56658                 }
56659             } break;
56660             case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE:
56661             {
56662                 seektablePos  = runningFilePos;
56663                 seektableSize = blockSize;
56664                 if (onMeta) {
56665                     drflac_uint32 iSeekpoint;
56666                     void* pRawData;
56667                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
56668                     if (pRawData == NULL) {
56669                         return DRFLAC_FALSE;
56670                     }
56671                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
56672                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56673                         return DRFLAC_FALSE;
56674                     }
56675                     metadata.pRawData = pRawData;
56676                     metadata.rawDataSize = blockSize;
56677                     metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint);
56678                     metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
56679                     for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) {
56680                         drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
56681                         pSeekpoint->firstPCMFrame   = drflac__be2host_64(pSeekpoint->firstPCMFrame);
56682                         pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset);
56683                         pSeekpoint->pcmFrameCount   = drflac__be2host_16(pSeekpoint->pcmFrameCount);
56684                     }
56685                     onMeta(pUserDataMD, &metadata);
56686                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56687                 }
56688             } break;
56689             case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT:
56690             {
56691                 if (blockSize < 8) {
56692                     return DRFLAC_FALSE;
56693                 }
56694                 if (onMeta) {
56695                     void* pRawData;
56696                     const char* pRunningData;
56697                     const char* pRunningDataEnd;
56698                     drflac_uint32 i;
56699                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
56700                     if (pRawData == NULL) {
56701                         return DRFLAC_FALSE;
56702                     }
56703                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
56704                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56705                         return DRFLAC_FALSE;
56706                     }
56707                     metadata.pRawData = pRawData;
56708                     metadata.rawDataSize = blockSize;
56709                     pRunningData    = (const char*)pRawData;
56710                     pRunningDataEnd = (const char*)pRawData + blockSize;
56711                     metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56712                     if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) {
56713                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56714                         return DRFLAC_FALSE;
56715                     }
56716                     metadata.data.vorbis_comment.vendor       = pRunningData;                                            pRunningData += metadata.data.vorbis_comment.vendorLength;
56717                     metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56718                     if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) {
56719                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56720                         return DRFLAC_FALSE;
56721                     }
56722                     metadata.data.vorbis_comment.pComments    = pRunningData;
56723                     for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) {
56724                         drflac_uint32 commentLength;
56725                         if (pRunningDataEnd - pRunningData < 4) {
56726                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56727                             return DRFLAC_FALSE;
56728                         }
56729                         commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56730                         if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) {
56731                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56732                             return DRFLAC_FALSE;
56733                         }
56734                         pRunningData += commentLength;
56735                     }
56736                     onMeta(pUserDataMD, &metadata);
56737                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56738                 }
56739             } break;
56740             case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET:
56741             {
56742                 if (blockSize < 396) {
56743                     return DRFLAC_FALSE;
56744                 }
56745                 if (onMeta) {
56746                     void* pRawData;
56747                     const char* pRunningData;
56748                     const char* pRunningDataEnd;
56749                     drflac_uint8 iTrack;
56750                     drflac_uint8 iIndex;
56751                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
56752                     if (pRawData == NULL) {
56753                         return DRFLAC_FALSE;
56754                     }
56755                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
56756                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56757                         return DRFLAC_FALSE;
56758                     }
56759                     metadata.pRawData = pRawData;
56760                     metadata.rawDataSize = blockSize;
56761                     pRunningData    = (const char*)pRawData;
56762                     pRunningDataEnd = (const char*)pRawData + blockSize;
56763                     DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128);                              pRunningData += 128;
56764                     metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8;
56765                     metadata.data.cuesheet.isCD              = (pRunningData[0] & 0x80) != 0;                           pRunningData += 259;
56766                     metadata.data.cuesheet.trackCount        = pRunningData[0];                                         pRunningData += 1;
56767                     metadata.data.cuesheet.pTrackData        = pRunningData;
56768                     for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
56769                         drflac_uint8 indexCount;
56770                         drflac_uint32 indexPointSize;
56771                         if (pRunningDataEnd - pRunningData < 36) {
56772                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56773                             return DRFLAC_FALSE;
56774                         }
56775                         pRunningData += 35;
56776                         indexCount = pRunningData[0]; pRunningData += 1;
56777                         indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index);
56778                         if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) {
56779                             drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56780                             return DRFLAC_FALSE;
56781                         }
56782                         for (iIndex = 0; iIndex < indexCount; ++iIndex) {
56783                             drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData;
56784                             pRunningData += sizeof(drflac_cuesheet_track_index);
56785                             pTrack->offset = drflac__be2host_64(pTrack->offset);
56786                         }
56787                     }
56788                     onMeta(pUserDataMD, &metadata);
56789                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56790                 }
56791             } break;
56792             case DRFLAC_METADATA_BLOCK_TYPE_PICTURE:
56793             {
56794                 if (blockSize < 32) {
56795                     return DRFLAC_FALSE;
56796                 }
56797                 if (onMeta) {
56798                     void* pRawData;
56799                     const char* pRunningData;
56800                     const char* pRunningDataEnd;
56801                     pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
56802                     if (pRawData == NULL) {
56803                         return DRFLAC_FALSE;
56804                     }
56805                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
56806                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56807                         return DRFLAC_FALSE;
56808                     }
56809                     metadata.pRawData = pRawData;
56810                     metadata.rawDataSize = blockSize;
56811                     pRunningData    = (const char*)pRawData;
56812                     pRunningDataEnd = (const char*)pRawData + blockSize;
56813                     metadata.data.picture.type       = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56814                     metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56815                     if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) {
56816                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56817                         return DRFLAC_FALSE;
56818                     }
56819                     metadata.data.picture.mime              = pRunningData;                                            pRunningData += metadata.data.picture.mimeLength;
56820                     metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56821                     if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) {
56822                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56823                         return DRFLAC_FALSE;
56824                     }
56825                     metadata.data.picture.description     = pRunningData;                                            pRunningData += metadata.data.picture.descriptionLength;
56826                     metadata.data.picture.width           = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56827                     metadata.data.picture.height          = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56828                     metadata.data.picture.colorDepth      = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56829                     metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56830                     metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
56831                     metadata.data.picture.pPictureData    = (const drflac_uint8*)pRunningData;
56832                     if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) {
56833                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56834                         return DRFLAC_FALSE;
56835                     }
56836                     onMeta(pUserDataMD, &metadata);
56837                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56838                 }
56839             } break;
56840             case DRFLAC_METADATA_BLOCK_TYPE_PADDING:
56841             {
56842                 if (onMeta) {
56843                     metadata.data.padding.unused = 0;
56844                     if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
56845                         isLastBlock = DRFLAC_TRUE;
56846                     } else {
56847                         onMeta(pUserDataMD, &metadata);
56848                     }
56849                 }
56850             } break;
56851             case DRFLAC_METADATA_BLOCK_TYPE_INVALID:
56852             {
56853                 if (onMeta) {
56854                     if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
56855                         isLastBlock = DRFLAC_TRUE;
56856                     }
56857                 }
56858             } break;
56859             default:
56860             {
56861                 if (onMeta) {
56862                     void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
56863                     if (pRawData == NULL) {
56864                         return DRFLAC_FALSE;
56865                     }
56866                     if (onRead(pUserData, pRawData, blockSize) != blockSize) {
56867                         drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56868                         return DRFLAC_FALSE;
56869                     }
56870                     metadata.pRawData = pRawData;
56871                     metadata.rawDataSize = blockSize;
56872                     onMeta(pUserDataMD, &metadata);
56873                     drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
56874                 }
56875             } break;
56876         }
56877         if (onMeta == NULL && blockSize > 0) {
56878             if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
56879                 isLastBlock = DRFLAC_TRUE;
56880             }
56881         }
56882         runningFilePos += blockSize;
56883         if (isLastBlock) {
56884             break;
56885         }
56886     }
56887     *pSeektablePos = seektablePos;
56888     *pSeektableSize = seektableSize;
56889     *pFirstFramePos = runningFilePos;
56890     return DRFLAC_TRUE;
56891 }
56892 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)
56893 {
56894     drflac_uint8 isLastBlock;
56895     drflac_uint8 blockType;
56896     drflac_uint32 blockSize;
56897     (void)onSeek;
56898     pInit->container = drflac_container_native;
56899     if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
56900         return DRFLAC_FALSE;
56901     }
56902     if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
56903         if (!relaxed) {
56904             return DRFLAC_FALSE;
56905         } else {
56906             pInit->hasStreamInfoBlock = DRFLAC_FALSE;
56907             pInit->hasMetadataBlocks  = DRFLAC_FALSE;
56908             if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) {
56909                 return DRFLAC_FALSE;
56910             }
56911             if (pInit->firstFrameHeader.bitsPerSample == 0) {
56912                 return DRFLAC_FALSE;
56913             }
56914             pInit->sampleRate              = pInit->firstFrameHeader.sampleRate;
56915             pInit->channels                = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment);
56916             pInit->bitsPerSample           = pInit->firstFrameHeader.bitsPerSample;
56917             pInit->maxBlockSizeInPCMFrames = 65535;
56918             return DRFLAC_TRUE;
56919         }
56920     } else {
56921         drflac_streaminfo streaminfo;
56922         if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
56923             return DRFLAC_FALSE;
56924         }
56925         pInit->hasStreamInfoBlock      = DRFLAC_TRUE;
56926         pInit->sampleRate              = streaminfo.sampleRate;
56927         pInit->channels                = streaminfo.channels;
56928         pInit->bitsPerSample           = streaminfo.bitsPerSample;
56929         pInit->totalPCMFrameCount      = streaminfo.totalPCMFrameCount;
56930         pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;
56931         pInit->hasMetadataBlocks       = !isLastBlock;
56932         if (onMeta) {
56933             drflac_metadata metadata;
56934             metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
56935             metadata.pRawData = NULL;
56936             metadata.rawDataSize = 0;
56937             metadata.data.streaminfo = streaminfo;
56938             onMeta(pUserDataMD, &metadata);
56939         }
56940         return DRFLAC_TRUE;
56941     }
56942 }
56943 #ifndef DR_FLAC_NO_OGG
56944 #define DRFLAC_OGG_MAX_PAGE_SIZE            65307
56945 #define DRFLAC_OGG_CAPTURE_PATTERN_CRC32    1605413199
56946 typedef enum
56947 {
56948     drflac_ogg_recover_on_crc_mismatch,
56949     drflac_ogg_fail_on_crc_mismatch
56950 } drflac_ogg_crc_mismatch_recovery;
56951 #ifndef DR_FLAC_NO_CRC
56952 static drflac_uint32 drflac__crc32_table[] = {
56953     0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
56954     0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
56955     0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
56956     0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
56957     0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
56958     0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
56959     0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
56960     0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
56961     0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
56962     0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
56963     0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
56964     0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
56965     0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
56966     0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
56967     0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L,
56968     0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL,
56969     0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL,
56970     0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L,
56971     0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
56972     0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL,
56973     0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL,
56974     0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L,
56975     0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L,
56976     0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
56977     0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL,
56978     0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L,
56979     0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L,
56980     0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL,
56981     0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
56982     0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L,
56983     0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L,
56984     0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL,
56985     0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L,
56986     0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
56987     0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL,
56988     0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L,
56989     0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L,
56990     0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL,
56991     0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
56992     0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L,
56993     0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L,
56994     0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL,
56995     0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL,
56996     0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
56997     0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L,
56998     0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL,
56999     0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL,
57000     0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L,
57001     0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
57002     0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL,
57003     0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L,
57004     0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L,
57005     0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L,
57006     0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
57007     0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L,
57008     0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L,
57009     0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L,
57010     0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL,
57011     0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
57012     0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L,
57013     0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L,
57014     0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL,
57015     0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L,
57016     0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
57017 };
57018 #endif
57019 static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data)
57020 {
57021 #ifndef DR_FLAC_NO_CRC
57022     return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data];
57023 #else
57024     (void)data;
57025     return crc32;
57026 #endif
57027 }
57028 #if 0
57029 static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data)
57030 {
57031     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF));
57032     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF));
57033     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >>  8) & 0xFF));
57034     crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >>  0) & 0xFF));
57035     return crc32;
57036 }
57037 static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data)
57038 {
57039     crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF));
57040     crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >>  0) & 0xFFFFFFFF));
57041     return crc32;
57042 }
57043 #endif
57044 static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize)
57045 {
57046     drflac_uint32 i;
57047     for (i = 0; i < dataSize; ++i) {
57048         crc32 = drflac_crc32_byte(crc32, pData[i]);
57049     }
57050     return crc32;
57051 }
57052 static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4])
57053 {
57054     return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
57055 }
57056 static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader)
57057 {
57058     return 27 + pHeader->segmentCount;
57059 }
57060 static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader)
57061 {
57062     drflac_uint32 pageBodySize = 0;
57063     int i;
57064     for (i = 0; i < pHeader->segmentCount; ++i) {
57065         pageBodySize += pHeader->segmentTable[i];
57066     }
57067     return pageBodySize;
57068 }
57069 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)
57070 {
57071     drflac_uint8 data[23];
57072     drflac_uint32 i;
57073     DRFLAC_ASSERT(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32);
57074     if (onRead(pUserData, data, 23) != 23) {
57075         return DRFLAC_AT_END;
57076     }
57077     *pBytesRead += 23;
57078     pHeader->capturePattern[0] = 'O';
57079     pHeader->capturePattern[1] = 'g';
57080     pHeader->capturePattern[2] = 'g';
57081     pHeader->capturePattern[3] = 'S';
57082     pHeader->structureVersion = data[0];
57083     pHeader->headerType       = data[1];
57084     DRFLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8);
57085     DRFLAC_COPY_MEMORY(&pHeader->serialNumber,    &data[10], 4);
57086     DRFLAC_COPY_MEMORY(&pHeader->sequenceNumber,  &data[14], 4);
57087     DRFLAC_COPY_MEMORY(&pHeader->checksum,        &data[18], 4);
57088     pHeader->segmentCount     = data[22];
57089     data[18] = 0;
57090     data[19] = 0;
57091     data[20] = 0;
57092     data[21] = 0;
57093     for (i = 0; i < 23; ++i) {
57094         *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]);
57095     }
57096     if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) {
57097         return DRFLAC_AT_END;
57098     }
57099     *pBytesRead += pHeader->segmentCount;
57100     for (i = 0; i < pHeader->segmentCount; ++i) {
57101         *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]);
57102     }
57103     return DRFLAC_SUCCESS;
57104 }
57105 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)
57106 {
57107     drflac_uint8 id[4];
57108     *pBytesRead = 0;
57109     if (onRead(pUserData, id, 4) != 4) {
57110         return DRFLAC_AT_END;
57111     }
57112     *pBytesRead += 4;
57113     for (;;) {
57114         if (drflac_ogg__is_capture_pattern(id)) {
57115             drflac_result result;
57116             *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
57117             result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32);
57118             if (result == DRFLAC_SUCCESS) {
57119                 return DRFLAC_SUCCESS;
57120             } else {
57121                 if (result == DRFLAC_CRC_MISMATCH) {
57122                     continue;
57123                 } else {
57124                     return result;
57125                 }
57126             }
57127         } else {
57128             id[0] = id[1];
57129             id[1] = id[2];
57130             id[2] = id[3];
57131             if (onRead(pUserData, &id[3], 1) != 1) {
57132                 return DRFLAC_AT_END;
57133             }
57134             *pBytesRead += 1;
57135         }
57136     }
57137 }
57138 typedef struct
57139 {
57140     drflac_read_proc onRead;
57141     drflac_seek_proc onSeek;
57142     void* pUserData;
57143     drflac_uint64 currentBytePos;
57144     drflac_uint64 firstBytePos;
57145     drflac_uint32 serialNumber;
57146     drflac_ogg_page_header bosPageHeader;
57147     drflac_ogg_page_header currentPageHeader;
57148     drflac_uint32 bytesRemainingInPage;
57149     drflac_uint32 pageDataSize;
57150     drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE];
57151 } drflac_oggbs;
57152 static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead)
57153 {
57154     size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead);
57155     oggbs->currentBytePos += bytesActuallyRead;
57156     return bytesActuallyRead;
57157 }
57158 static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
57159 {
57160     if (origin == drflac_seek_origin_start) {
57161         if (offset <= 0x7FFFFFFF) {
57162             if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
57163                 return DRFLAC_FALSE;
57164             }
57165             oggbs->currentBytePos = offset;
57166             return DRFLAC_TRUE;
57167         } else {
57168             if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
57169                 return DRFLAC_FALSE;
57170             }
57171             oggbs->currentBytePos = offset;
57172             return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
57173         }
57174     } else {
57175         while (offset > 0x7FFFFFFF) {
57176             if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
57177                 return DRFLAC_FALSE;
57178             }
57179             oggbs->currentBytePos += 0x7FFFFFFF;
57180             offset -= 0x7FFFFFFF;
57181         }
57182         if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) {
57183             return DRFLAC_FALSE;
57184         }
57185         oggbs->currentBytePos += offset;
57186         return DRFLAC_TRUE;
57187     }
57188 }
57189 static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod)
57190 {
57191     drflac_ogg_page_header header;
57192     for (;;) {
57193         drflac_uint32 crc32 = 0;
57194         drflac_uint32 bytesRead;
57195         drflac_uint32 pageBodySize;
57196 #ifndef DR_FLAC_NO_CRC
57197         drflac_uint32 actualCRC32;
57198 #endif
57199         if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
57200             return DRFLAC_FALSE;
57201         }
57202         oggbs->currentBytePos += bytesRead;
57203         pageBodySize = drflac_ogg__get_page_body_size(&header);
57204         if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) {
57205             continue;
57206         }
57207         if (header.serialNumber != oggbs->serialNumber) {
57208             if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) {
57209                 return DRFLAC_FALSE;
57210             }
57211             continue;
57212         }
57213         if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) {
57214             return DRFLAC_FALSE;
57215         }
57216         oggbs->pageDataSize = pageBodySize;
57217 #ifndef DR_FLAC_NO_CRC
57218         actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize);
57219         if (actualCRC32 != header.checksum) {
57220             if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) {
57221                 continue;
57222             } else {
57223                 drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch);
57224                 return DRFLAC_FALSE;
57225             }
57226         }
57227 #else
57228         (void)recoveryMethod;
57229 #endif
57230         oggbs->currentPageHeader = header;
57231         oggbs->bytesRemainingInPage = pageBodySize;
57232         return DRFLAC_TRUE;
57233     }
57234 }
57235 #if 0
57236 static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg)
57237 {
57238     drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage;
57239     drflac_uint8 iSeg = 0;
57240     drflac_uint32 iByte = 0;
57241     while (iByte < bytesConsumedInPage) {
57242         drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
57243         if (iByte + segmentSize > bytesConsumedInPage) {
57244             break;
57245         } else {
57246             iSeg += 1;
57247             iByte += segmentSize;
57248         }
57249     }
57250     *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte);
57251     return iSeg;
57252 }
57253 static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
57254 {
57255     for (;;) {
57256         drflac_bool32 atEndOfPage = DRFLAC_FALSE;
57257         drflac_uint8 bytesRemainingInSeg;
57258         drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
57259         drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg;
57260         for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) {
57261             drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
57262             if (segmentSize < 255) {
57263                 if (iSeg == oggbs->currentPageHeader.segmentCount-1) {
57264                     atEndOfPage = DRFLAC_TRUE;
57265                 }
57266                 break;
57267             }
57268             bytesToEndOfPacketOrPage += segmentSize;
57269         }
57270         drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
57271         oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
57272         if (atEndOfPage) {
57273             if (!drflac_oggbs__goto_next_page(oggbs)) {
57274                 return DRFLAC_FALSE;
57275             }
57276             if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
57277                 return DRFLAC_TRUE;
57278             }
57279         } else {
57280             return DRFLAC_TRUE;
57281         }
57282     }
57283 }
57284 static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
57285 {
57286     return drflac_oggbs__seek_to_next_packet(oggbs);
57287 }
57288 #endif
57289 static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead)
57290 {
57291     drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
57292     drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut;
57293     size_t bytesRead = 0;
57294     DRFLAC_ASSERT(oggbs != NULL);
57295     DRFLAC_ASSERT(pRunningBufferOut != NULL);
57296     while (bytesRead < bytesToRead) {
57297         size_t bytesRemainingToRead = bytesToRead - bytesRead;
57298         if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) {
57299             DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead);
57300             bytesRead += bytesRemainingToRead;
57301             oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead;
57302             break;
57303         }
57304         if (oggbs->bytesRemainingInPage > 0) {
57305             DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage);
57306             bytesRead += oggbs->bytesRemainingInPage;
57307             pRunningBufferOut += oggbs->bytesRemainingInPage;
57308             oggbs->bytesRemainingInPage = 0;
57309         }
57310         DRFLAC_ASSERT(bytesRemainingToRead > 0);
57311         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
57312             break;
57313         }
57314     }
57315     return bytesRead;
57316 }
57317 static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
57318 {
57319     drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
57320     int bytesSeeked = 0;
57321     DRFLAC_ASSERT(oggbs != NULL);
57322     DRFLAC_ASSERT(offset >= 0);
57323     if (origin == drflac_seek_origin_start) {
57324         if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
57325             return DRFLAC_FALSE;
57326         }
57327         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
57328             return DRFLAC_FALSE;
57329         }
57330         return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
57331     }
57332     DRFLAC_ASSERT(origin == drflac_seek_origin_current);
57333     while (bytesSeeked < offset) {
57334         int bytesRemainingToSeek = offset - bytesSeeked;
57335         DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
57336         if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
57337             bytesSeeked += bytesRemainingToSeek;
57338             (void)bytesSeeked;
57339             oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
57340             break;
57341         }
57342         if (oggbs->bytesRemainingInPage > 0) {
57343             bytesSeeked += (int)oggbs->bytesRemainingInPage;
57344             oggbs->bytesRemainingInPage = 0;
57345         }
57346         DRFLAC_ASSERT(bytesRemainingToSeek > 0);
57347         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
57348             return DRFLAC_FALSE;
57349         }
57350     }
57351     return DRFLAC_TRUE;
57352 }
57353 static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
57354 {
57355     drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
57356     drflac_uint64 originalBytePos;
57357     drflac_uint64 runningGranulePosition;
57358     drflac_uint64 runningFrameBytePos;
57359     drflac_uint64 runningPCMFrameCount;
57360     DRFLAC_ASSERT(oggbs != NULL);
57361     originalBytePos = oggbs->currentBytePos;
57362     if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) {
57363         return DRFLAC_FALSE;
57364     }
57365     oggbs->bytesRemainingInPage = 0;
57366     runningGranulePosition = 0;
57367     for (;;) {
57368         if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
57369             drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
57370             return DRFLAC_FALSE;
57371         }
57372         runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize;
57373         if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) {
57374             break;
57375         }
57376         if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
57377             if (oggbs->currentPageHeader.segmentTable[0] >= 2) {
57378                 drflac_uint8 firstBytesInPage[2];
57379                 firstBytesInPage[0] = oggbs->pageData[0];
57380                 firstBytesInPage[1] = oggbs->pageData[1];
57381                 if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) {
57382                     runningGranulePosition = oggbs->currentPageHeader.granulePosition;
57383                 }
57384                 continue;
57385             }
57386         }
57387     }
57388     if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
57389         return DRFLAC_FALSE;
57390     }
57391     if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
57392         return DRFLAC_FALSE;
57393     }
57394     runningPCMFrameCount = runningGranulePosition;
57395     for (;;) {
57396         drflac_uint64 firstPCMFrameInFLACFrame = 0;
57397         drflac_uint64 lastPCMFrameInFLACFrame = 0;
57398         drflac_uint64 pcmFrameCountInThisFrame;
57399         if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
57400             return DRFLAC_FALSE;
57401         }
57402         drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
57403         pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
57404         if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) {
57405             drflac_result result = drflac__decode_flac_frame(pFlac);
57406             if (result == DRFLAC_SUCCESS) {
57407                 pFlac->currentPCMFrame = pcmFrameIndex;
57408                 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
57409                 return DRFLAC_TRUE;
57410             } else {
57411                 return DRFLAC_FALSE;
57412             }
57413         }
57414         if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) {
57415             drflac_result result = drflac__decode_flac_frame(pFlac);
57416             if (result == DRFLAC_SUCCESS) {
57417                 drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount);
57418                 if (pcmFramesToDecode == 0) {
57419                     return DRFLAC_TRUE;
57420                 }
57421                 pFlac->currentPCMFrame = runningPCMFrameCount;
57422                 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
57423             } else {
57424                 if (result == DRFLAC_CRC_MISMATCH) {
57425                     continue;
57426                 } else {
57427                     return DRFLAC_FALSE;
57428                 }
57429             }
57430         } else {
57431             drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
57432             if (result == DRFLAC_SUCCESS) {
57433                 runningPCMFrameCount += pcmFrameCountInThisFrame;
57434             } else {
57435                 if (result == DRFLAC_CRC_MISMATCH) {
57436                     continue;
57437                 } else {
57438                     return DRFLAC_FALSE;
57439                 }
57440             }
57441         }
57442     }
57443 }
57444 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)
57445 {
57446     drflac_ogg_page_header header;
57447     drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
57448     drflac_uint32 bytesRead = 0;
57449     (void)relaxed;
57450     pInit->container = drflac_container_ogg;
57451     pInit->oggFirstBytePos = 0;
57452     if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
57453         return DRFLAC_FALSE;
57454     }
57455     pInit->runningFilePos += bytesRead;
57456     for (;;) {
57457         int pageBodySize;
57458         if ((header.headerType & 0x02) == 0) {
57459             return DRFLAC_FALSE;
57460         }
57461         pageBodySize = drflac_ogg__get_page_body_size(&header);
57462         if (pageBodySize == 51) {
57463             drflac_uint32 bytesRemainingInPage = pageBodySize;
57464             drflac_uint8 packetType;
57465             if (onRead(pUserData, &packetType, 1) != 1) {
57466                 return DRFLAC_FALSE;
57467             }
57468             bytesRemainingInPage -= 1;
57469             if (packetType == 0x7F) {
57470                 drflac_uint8 sig[4];
57471                 if (onRead(pUserData, sig, 4) != 4) {
57472                     return DRFLAC_FALSE;
57473                 }
57474                 bytesRemainingInPage -= 4;
57475                 if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') {
57476                     drflac_uint8 mappingVersion[2];
57477                     if (onRead(pUserData, mappingVersion, 2) != 2) {
57478                         return DRFLAC_FALSE;
57479                     }
57480                     if (mappingVersion[0] != 1) {
57481                         return DRFLAC_FALSE;
57482                     }
57483                     if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
57484                         return DRFLAC_FALSE;
57485                     }
57486                     if (onRead(pUserData, sig, 4) != 4) {
57487                         return DRFLAC_FALSE;
57488                     }
57489                     if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') {
57490                         drflac_streaminfo streaminfo;
57491                         drflac_uint8 isLastBlock;
57492                         drflac_uint8 blockType;
57493                         drflac_uint32 blockSize;
57494                         if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
57495                             return DRFLAC_FALSE;
57496                         }
57497                         if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
57498                             return DRFLAC_FALSE;
57499                         }
57500                         if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
57501                             pInit->hasStreamInfoBlock      = DRFLAC_TRUE;
57502                             pInit->sampleRate              = streaminfo.sampleRate;
57503                             pInit->channels                = streaminfo.channels;
57504                             pInit->bitsPerSample           = streaminfo.bitsPerSample;
57505                             pInit->totalPCMFrameCount      = streaminfo.totalPCMFrameCount;
57506                             pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;
57507                             pInit->hasMetadataBlocks       = !isLastBlock;
57508                             if (onMeta) {
57509                                 drflac_metadata metadata;
57510                                 metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
57511                                 metadata.pRawData = NULL;
57512                                 metadata.rawDataSize = 0;
57513                                 metadata.data.streaminfo = streaminfo;
57514                                 onMeta(pUserDataMD, &metadata);
57515                             }
57516                             pInit->runningFilePos  += pageBodySize;
57517                             pInit->oggFirstBytePos  = pInit->runningFilePos - 79;
57518                             pInit->oggSerial        = header.serialNumber;
57519                             pInit->oggBosHeader     = header;
57520                             break;
57521                         } else {
57522                             return DRFLAC_FALSE;
57523                         }
57524                     } else {
57525                         return DRFLAC_FALSE;
57526                     }
57527                 } else {
57528                     if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
57529                         return DRFLAC_FALSE;
57530                     }
57531                 }
57532             } else {
57533                 if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
57534                     return DRFLAC_FALSE;
57535                 }
57536             }
57537         } else {
57538             if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
57539                 return DRFLAC_FALSE;
57540             }
57541         }
57542         pInit->runningFilePos += pageBodySize;
57543         if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
57544             return DRFLAC_FALSE;
57545         }
57546         pInit->runningFilePos += bytesRead;
57547     }
57548     pInit->hasMetadataBlocks = DRFLAC_TRUE;
57549     return DRFLAC_TRUE;
57550 }
57551 #endif
57552 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)
57553 {
57554     drflac_bool32 relaxed;
57555     drflac_uint8 id[4];
57556     if (pInit == NULL || onRead == NULL || onSeek == NULL) {
57557         return DRFLAC_FALSE;
57558     }
57559     DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
57560     pInit->onRead       = onRead;
57561     pInit->onSeek       = onSeek;
57562     pInit->onMeta       = onMeta;
57563     pInit->container    = container;
57564     pInit->pUserData    = pUserData;
57565     pInit->pUserDataMD  = pUserDataMD;
57566     pInit->bs.onRead    = onRead;
57567     pInit->bs.onSeek    = onSeek;
57568     pInit->bs.pUserData = pUserData;
57569     drflac__reset_cache(&pInit->bs);
57570     relaxed = container != drflac_container_unknown;
57571     for (;;) {
57572         if (onRead(pUserData, id, 4) != 4) {
57573             return DRFLAC_FALSE;
57574         }
57575         pInit->runningFilePos += 4;
57576         if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') {
57577             drflac_uint8 header[6];
57578             drflac_uint8 flags;
57579             drflac_uint32 headerSize;
57580             if (onRead(pUserData, header, 6) != 6) {
57581                 return DRFLAC_FALSE;
57582             }
57583             pInit->runningFilePos += 6;
57584             flags = header[1];
57585             DRFLAC_COPY_MEMORY(&headerSize, header+2, 4);
57586             headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize));
57587             if (flags & 0x10) {
57588                 headerSize += 10;
57589             }
57590             if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
57591                 return DRFLAC_FALSE;
57592             }
57593             pInit->runningFilePos += headerSize;
57594         } else {
57595             break;
57596         }
57597     }
57598     if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') {
57599         return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
57600     }
57601 #ifndef DR_FLAC_NO_OGG
57602     if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') {
57603         return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
57604     }
57605 #endif
57606     if (relaxed) {
57607         if (container == drflac_container_native) {
57608             return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
57609         }
57610 #ifndef DR_FLAC_NO_OGG
57611         if (container == drflac_container_ogg) {
57612             return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
57613         }
57614 #endif
57615     }
57616     return DRFLAC_FALSE;
57617 }
57618 static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
57619 {
57620     DRFLAC_ASSERT(pFlac != NULL);
57621     DRFLAC_ASSERT(pInit != NULL);
57622     DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac));
57623     pFlac->bs                      = pInit->bs;
57624     pFlac->onMeta                  = pInit->onMeta;
57625     pFlac->pUserDataMD             = pInit->pUserDataMD;
57626     pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames;
57627     pFlac->sampleRate              = pInit->sampleRate;
57628     pFlac->channels                = (drflac_uint8)pInit->channels;
57629     pFlac->bitsPerSample           = (drflac_uint8)pInit->bitsPerSample;
57630     pFlac->totalPCMFrameCount      = pInit->totalPCMFrameCount;
57631     pFlac->container               = pInit->container;
57632 }
57633 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)
57634 {
57635     drflac_init_info init;
57636     drflac_uint32 allocationSize;
57637     drflac_uint32 wholeSIMDVectorCountPerChannel;
57638     drflac_uint32 decodedSamplesAllocationSize;
57639 #ifndef DR_FLAC_NO_OGG
57640     drflac_oggbs oggbs;
57641 #endif
57642     drflac_uint64 firstFramePos;
57643     drflac_uint64 seektablePos;
57644     drflac_uint32 seektableSize;
57645     drflac_allocation_callbacks allocationCallbacks;
57646     drflac* pFlac;
57647     drflac__init_cpu_caps();
57648     if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
57649         return NULL;
57650     }
57651     if (pAllocationCallbacks != NULL) {
57652         allocationCallbacks = *pAllocationCallbacks;
57653         if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) {
57654             return NULL;
57655         }
57656     } else {
57657         allocationCallbacks.pUserData = NULL;
57658         allocationCallbacks.onMalloc  = drflac__malloc_default;
57659         allocationCallbacks.onRealloc = drflac__realloc_default;
57660         allocationCallbacks.onFree    = drflac__free_default;
57661     }
57662     allocationSize = sizeof(drflac);
57663     if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) {
57664         wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32)));
57665     } else {
57666         wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1;
57667     }
57668     decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels;
57669     allocationSize += decodedSamplesAllocationSize;
57670     allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE;
57671 #ifndef DR_FLAC_NO_OGG
57672     if (init.container == drflac_container_ogg) {
57673         allocationSize += sizeof(drflac_oggbs);
57674     }
57675     DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs));
57676     if (init.container == drflac_container_ogg) {
57677         oggbs.onRead = onRead;
57678         oggbs.onSeek = onSeek;
57679         oggbs.pUserData = pUserData;
57680         oggbs.currentBytePos = init.oggFirstBytePos;
57681         oggbs.firstBytePos = init.oggFirstBytePos;
57682         oggbs.serialNumber = init.oggSerial;
57683         oggbs.bosPageHeader = init.oggBosHeader;
57684         oggbs.bytesRemainingInPage = 0;
57685     }
57686 #endif
57687     firstFramePos = 42;
57688     seektablePos  = 0;
57689     seektableSize = 0;
57690     if (init.hasMetadataBlocks) {
57691         drflac_read_proc onReadOverride = onRead;
57692         drflac_seek_proc onSeekOverride = onSeek;
57693         void* pUserDataOverride = pUserData;
57694 #ifndef DR_FLAC_NO_OGG
57695         if (init.container == drflac_container_ogg) {
57696             onReadOverride = drflac__on_read_ogg;
57697             onSeekOverride = drflac__on_seek_ogg;
57698             pUserDataOverride = (void*)&oggbs;
57699         }
57700 #endif
57701         if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) {
57702             return NULL;
57703         }
57704         allocationSize += seektableSize;
57705     }
57706     pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
57707     if (pFlac == NULL) {
57708         return NULL;
57709     }
57710     drflac__init_from_info(pFlac, &init);
57711     pFlac->allocationCallbacks = allocationCallbacks;
57712     pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE);
57713 #ifndef DR_FLAC_NO_OGG
57714     if (init.container == drflac_container_ogg) {
57715         drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize);
57716         *pInternalOggbs = oggbs;
57717         pFlac->bs.onRead = drflac__on_read_ogg;
57718         pFlac->bs.onSeek = drflac__on_seek_ogg;
57719         pFlac->bs.pUserData = (void*)pInternalOggbs;
57720         pFlac->_oggbs = (void*)pInternalOggbs;
57721     }
57722 #endif
57723     pFlac->firstFLACFramePosInBytes = firstFramePos;
57724 #ifndef DR_FLAC_NO_OGG
57725     if (init.container == drflac_container_ogg)
57726     {
57727         pFlac->pSeekpoints = NULL;
57728         pFlac->seekpointCount = 0;
57729     }
57730     else
57731 #endif
57732     {
57733         if (seektablePos != 0) {
57734             pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints);
57735             pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize);
57736             DRFLAC_ASSERT(pFlac->bs.onSeek != NULL);
57737             DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
57738             if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
57739                 if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) {
57740                     drflac_uint32 iSeekpoint;
57741                     for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
57742                         pFlac->pSeekpoints[iSeekpoint].firstPCMFrame   = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame);
57743                         pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset);
57744                         pFlac->pSeekpoints[iSeekpoint].pcmFrameCount   = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount);
57745                     }
57746                 } else {
57747                     pFlac->pSeekpoints = NULL;
57748                     pFlac->seekpointCount = 0;
57749                 }
57750                 if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
57751                     drflac__free_from_callbacks(pFlac, &allocationCallbacks);
57752                     return NULL;
57753                 }
57754             } else {
57755                 pFlac->pSeekpoints = NULL;
57756                 pFlac->seekpointCount = 0;
57757             }
57758         }
57759     }
57760     if (!init.hasStreamInfoBlock) {
57761         pFlac->currentFLACFrame.header = init.firstFrameHeader;
57762         for (;;) {
57763             drflac_result result = drflac__decode_flac_frame(pFlac);
57764             if (result == DRFLAC_SUCCESS) {
57765                 break;
57766             } else {
57767                 if (result == DRFLAC_CRC_MISMATCH) {
57768                     if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
57769                         drflac__free_from_callbacks(pFlac, &allocationCallbacks);
57770                         return NULL;
57771                     }
57772                     continue;
57773                 } else {
57774                     drflac__free_from_callbacks(pFlac, &allocationCallbacks);
57775                     return NULL;
57776                 }
57777             }
57778         }
57779     }
57780     return pFlac;
57781 }
57782 #ifndef DR_FLAC_NO_STDIO
57783 #include <stdio.h>
57784 #include <wchar.h>
57785 #include <errno.h>
57786 static drflac_result drflac_result_from_errno(int e)
57787 {
57788     switch (e)
57789     {
57790         case 0: return DRFLAC_SUCCESS;
57791     #ifdef EPERM
57792         case EPERM: return DRFLAC_INVALID_OPERATION;
57793     #endif
57794     #ifdef ENOENT
57795         case ENOENT: return DRFLAC_DOES_NOT_EXIST;
57796     #endif
57797     #ifdef ESRCH
57798         case ESRCH: return DRFLAC_DOES_NOT_EXIST;
57799     #endif
57800     #ifdef EINTR
57801         case EINTR: return DRFLAC_INTERRUPT;
57802     #endif
57803     #ifdef EIO
57804         case EIO: return DRFLAC_IO_ERROR;
57805     #endif
57806     #ifdef ENXIO
57807         case ENXIO: return DRFLAC_DOES_NOT_EXIST;
57808     #endif
57809     #ifdef E2BIG
57810         case E2BIG: return DRFLAC_INVALID_ARGS;
57811     #endif
57812     #ifdef ENOEXEC
57813         case ENOEXEC: return DRFLAC_INVALID_FILE;
57814     #endif
57815     #ifdef EBADF
57816         case EBADF: return DRFLAC_INVALID_FILE;
57817     #endif
57818     #ifdef ECHILD
57819         case ECHILD: return DRFLAC_ERROR;
57820     #endif
57821     #ifdef EAGAIN
57822         case EAGAIN: return DRFLAC_UNAVAILABLE;
57823     #endif
57824     #ifdef ENOMEM
57825         case ENOMEM: return DRFLAC_OUT_OF_MEMORY;
57826     #endif
57827     #ifdef EACCES
57828         case EACCES: return DRFLAC_ACCESS_DENIED;
57829     #endif
57830     #ifdef EFAULT
57831         case EFAULT: return DRFLAC_BAD_ADDRESS;
57832     #endif
57833     #ifdef ENOTBLK
57834         case ENOTBLK: return DRFLAC_ERROR;
57835     #endif
57836     #ifdef EBUSY
57837         case EBUSY: return DRFLAC_BUSY;
57838     #endif
57839     #ifdef EEXIST
57840         case EEXIST: return DRFLAC_ALREADY_EXISTS;
57841     #endif
57842     #ifdef EXDEV
57843         case EXDEV: return DRFLAC_ERROR;
57844     #endif
57845     #ifdef ENODEV
57846         case ENODEV: return DRFLAC_DOES_NOT_EXIST;
57847     #endif
57848     #ifdef ENOTDIR
57849         case ENOTDIR: return DRFLAC_NOT_DIRECTORY;
57850     #endif
57851     #ifdef EISDIR
57852         case EISDIR: return DRFLAC_IS_DIRECTORY;
57853     #endif
57854     #ifdef EINVAL
57855         case EINVAL: return DRFLAC_INVALID_ARGS;
57856     #endif
57857     #ifdef ENFILE
57858         case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
57859     #endif
57860     #ifdef EMFILE
57861         case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
57862     #endif
57863     #ifdef ENOTTY
57864         case ENOTTY: return DRFLAC_INVALID_OPERATION;
57865     #endif
57866     #ifdef ETXTBSY
57867         case ETXTBSY: return DRFLAC_BUSY;
57868     #endif
57869     #ifdef EFBIG
57870         case EFBIG: return DRFLAC_TOO_BIG;
57871     #endif
57872     #ifdef ENOSPC
57873         case ENOSPC: return DRFLAC_NO_SPACE;
57874     #endif
57875     #ifdef ESPIPE
57876         case ESPIPE: return DRFLAC_BAD_SEEK;
57877     #endif
57878     #ifdef EROFS
57879         case EROFS: return DRFLAC_ACCESS_DENIED;
57880     #endif
57881     #ifdef EMLINK
57882         case EMLINK: return DRFLAC_TOO_MANY_LINKS;
57883     #endif
57884     #ifdef EPIPE
57885         case EPIPE: return DRFLAC_BAD_PIPE;
57886     #endif
57887     #ifdef EDOM
57888         case EDOM: return DRFLAC_OUT_OF_RANGE;
57889     #endif
57890     #ifdef ERANGE
57891         case ERANGE: return DRFLAC_OUT_OF_RANGE;
57892     #endif
57893     #ifdef EDEADLK
57894         case EDEADLK: return DRFLAC_DEADLOCK;
57895     #endif
57896     #ifdef ENAMETOOLONG
57897         case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG;
57898     #endif
57899     #ifdef ENOLCK
57900         case ENOLCK: return DRFLAC_ERROR;
57901     #endif
57902     #ifdef ENOSYS
57903         case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
57904     #endif
57905     #ifdef ENOTEMPTY
57906         case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
57907     #endif
57908     #ifdef ELOOP
57909         case ELOOP: return DRFLAC_TOO_MANY_LINKS;
57910     #endif
57911     #ifdef ENOMSG
57912         case ENOMSG: return DRFLAC_NO_MESSAGE;
57913     #endif
57914     #ifdef EIDRM
57915         case EIDRM: return DRFLAC_ERROR;
57916     #endif
57917     #ifdef ECHRNG
57918         case ECHRNG: return DRFLAC_ERROR;
57919     #endif
57920     #ifdef EL2NSYNC
57921         case EL2NSYNC: return DRFLAC_ERROR;
57922     #endif
57923     #ifdef EL3HLT
57924         case EL3HLT: return DRFLAC_ERROR;
57925     #endif
57926     #ifdef EL3RST
57927         case EL3RST: return DRFLAC_ERROR;
57928     #endif
57929     #ifdef ELNRNG
57930         case ELNRNG: return DRFLAC_OUT_OF_RANGE;
57931     #endif
57932     #ifdef EUNATCH
57933         case EUNATCH: return DRFLAC_ERROR;
57934     #endif
57935     #ifdef ENOCSI
57936         case ENOCSI: return DRFLAC_ERROR;
57937     #endif
57938     #ifdef EL2HLT
57939         case EL2HLT: return DRFLAC_ERROR;
57940     #endif
57941     #ifdef EBADE
57942         case EBADE: return DRFLAC_ERROR;
57943     #endif
57944     #ifdef EBADR
57945         case EBADR: return DRFLAC_ERROR;
57946     #endif
57947     #ifdef EXFULL
57948         case EXFULL: return DRFLAC_ERROR;
57949     #endif
57950     #ifdef ENOANO
57951         case ENOANO: return DRFLAC_ERROR;
57952     #endif
57953     #ifdef EBADRQC
57954         case EBADRQC: return DRFLAC_ERROR;
57955     #endif
57956     #ifdef EBADSLT
57957         case EBADSLT: return DRFLAC_ERROR;
57958     #endif
57959     #ifdef EBFONT
57960         case EBFONT: return DRFLAC_INVALID_FILE;
57961     #endif
57962     #ifdef ENOSTR
57963         case ENOSTR: return DRFLAC_ERROR;
57964     #endif
57965     #ifdef ENODATA
57966         case ENODATA: return DRFLAC_NO_DATA_AVAILABLE;
57967     #endif
57968     #ifdef ETIME
57969         case ETIME: return DRFLAC_TIMEOUT;
57970     #endif
57971     #ifdef ENOSR
57972         case ENOSR: return DRFLAC_NO_DATA_AVAILABLE;
57973     #endif
57974     #ifdef ENONET
57975         case ENONET: return DRFLAC_NO_NETWORK;
57976     #endif
57977     #ifdef ENOPKG
57978         case ENOPKG: return DRFLAC_ERROR;
57979     #endif
57980     #ifdef EREMOTE
57981         case EREMOTE: return DRFLAC_ERROR;
57982     #endif
57983     #ifdef ENOLINK
57984         case ENOLINK: return DRFLAC_ERROR;
57985     #endif
57986     #ifdef EADV
57987         case EADV: return DRFLAC_ERROR;
57988     #endif
57989     #ifdef ESRMNT
57990         case ESRMNT: return DRFLAC_ERROR;
57991     #endif
57992     #ifdef ECOMM
57993         case ECOMM: return DRFLAC_ERROR;
57994     #endif
57995     #ifdef EPROTO
57996         case EPROTO: return DRFLAC_ERROR;
57997     #endif
57998     #ifdef EMULTIHOP
57999         case EMULTIHOP: return DRFLAC_ERROR;
58000     #endif
58001     #ifdef EDOTDOT
58002         case EDOTDOT: return DRFLAC_ERROR;
58003     #endif
58004     #ifdef EBADMSG
58005         case EBADMSG: return DRFLAC_BAD_MESSAGE;
58006     #endif
58007     #ifdef EOVERFLOW
58008         case EOVERFLOW: return DRFLAC_TOO_BIG;
58009     #endif
58010     #ifdef ENOTUNIQ
58011         case ENOTUNIQ: return DRFLAC_NOT_UNIQUE;
58012     #endif
58013     #ifdef EBADFD
58014         case EBADFD: return DRFLAC_ERROR;
58015     #endif
58016     #ifdef EREMCHG
58017         case EREMCHG: return DRFLAC_ERROR;
58018     #endif
58019     #ifdef ELIBACC
58020         case ELIBACC: return DRFLAC_ACCESS_DENIED;
58021     #endif
58022     #ifdef ELIBBAD
58023         case ELIBBAD: return DRFLAC_INVALID_FILE;
58024     #endif
58025     #ifdef ELIBSCN
58026         case ELIBSCN: return DRFLAC_INVALID_FILE;
58027     #endif
58028     #ifdef ELIBMAX
58029         case ELIBMAX: return DRFLAC_ERROR;
58030     #endif
58031     #ifdef ELIBEXEC
58032         case ELIBEXEC: return DRFLAC_ERROR;
58033     #endif
58034     #ifdef EILSEQ
58035         case EILSEQ: return DRFLAC_INVALID_DATA;
58036     #endif
58037     #ifdef ERESTART
58038         case ERESTART: return DRFLAC_ERROR;
58039     #endif
58040     #ifdef ESTRPIPE
58041         case ESTRPIPE: return DRFLAC_ERROR;
58042     #endif
58043     #ifdef EUSERS
58044         case EUSERS: return DRFLAC_ERROR;
58045     #endif
58046     #ifdef ENOTSOCK
58047         case ENOTSOCK: return DRFLAC_NOT_SOCKET;
58048     #endif
58049     #ifdef EDESTADDRREQ
58050         case EDESTADDRREQ: return DRFLAC_NO_ADDRESS;
58051     #endif
58052     #ifdef EMSGSIZE
58053         case EMSGSIZE: return DRFLAC_TOO_BIG;
58054     #endif
58055     #ifdef EPROTOTYPE
58056         case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL;
58057     #endif
58058     #ifdef ENOPROTOOPT
58059         case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE;
58060     #endif
58061     #ifdef EPROTONOSUPPORT
58062         case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED;
58063     #endif
58064     #ifdef ESOCKTNOSUPPORT
58065         case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED;
58066     #endif
58067     #ifdef EOPNOTSUPP
58068         case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION;
58069     #endif
58070     #ifdef EPFNOSUPPORT
58071         case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED;
58072     #endif
58073     #ifdef EAFNOSUPPORT
58074         case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED;
58075     #endif
58076     #ifdef EADDRINUSE
58077         case EADDRINUSE: return DRFLAC_ALREADY_IN_USE;
58078     #endif
58079     #ifdef EADDRNOTAVAIL
58080         case EADDRNOTAVAIL: return DRFLAC_ERROR;
58081     #endif
58082     #ifdef ENETDOWN
58083         case ENETDOWN: return DRFLAC_NO_NETWORK;
58084     #endif
58085     #ifdef ENETUNREACH
58086         case ENETUNREACH: return DRFLAC_NO_NETWORK;
58087     #endif
58088     #ifdef ENETRESET
58089         case ENETRESET: return DRFLAC_NO_NETWORK;
58090     #endif
58091     #ifdef ECONNABORTED
58092         case ECONNABORTED: return DRFLAC_NO_NETWORK;
58093     #endif
58094     #ifdef ECONNRESET
58095         case ECONNRESET: return DRFLAC_CONNECTION_RESET;
58096     #endif
58097     #ifdef ENOBUFS
58098         case ENOBUFS: return DRFLAC_NO_SPACE;
58099     #endif
58100     #ifdef EISCONN
58101         case EISCONN: return DRFLAC_ALREADY_CONNECTED;
58102     #endif
58103     #ifdef ENOTCONN
58104         case ENOTCONN: return DRFLAC_NOT_CONNECTED;
58105     #endif
58106     #ifdef ESHUTDOWN
58107         case ESHUTDOWN: return DRFLAC_ERROR;
58108     #endif
58109     #ifdef ETOOMANYREFS
58110         case ETOOMANYREFS: return DRFLAC_ERROR;
58111     #endif
58112     #ifdef ETIMEDOUT
58113         case ETIMEDOUT: return DRFLAC_TIMEOUT;
58114     #endif
58115     #ifdef ECONNREFUSED
58116         case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED;
58117     #endif
58118     #ifdef EHOSTDOWN
58119         case EHOSTDOWN: return DRFLAC_NO_HOST;
58120     #endif
58121     #ifdef EHOSTUNREACH
58122         case EHOSTUNREACH: return DRFLAC_NO_HOST;
58123     #endif
58124     #ifdef EALREADY
58125         case EALREADY: return DRFLAC_IN_PROGRESS;
58126     #endif
58127     #ifdef EINPROGRESS
58128         case EINPROGRESS: return DRFLAC_IN_PROGRESS;
58129     #endif
58130     #ifdef ESTALE
58131         case ESTALE: return DRFLAC_INVALID_FILE;
58132     #endif
58133     #ifdef EUCLEAN
58134         case EUCLEAN: return DRFLAC_ERROR;
58135     #endif
58136     #ifdef ENOTNAM
58137         case ENOTNAM: return DRFLAC_ERROR;
58138     #endif
58139     #ifdef ENAVAIL
58140         case ENAVAIL: return DRFLAC_ERROR;
58141     #endif
58142     #ifdef EISNAM
58143         case EISNAM: return DRFLAC_ERROR;
58144     #endif
58145     #ifdef EREMOTEIO
58146         case EREMOTEIO: return DRFLAC_IO_ERROR;
58147     #endif
58148     #ifdef EDQUOT
58149         case EDQUOT: return DRFLAC_NO_SPACE;
58150     #endif
58151     #ifdef ENOMEDIUM
58152         case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST;
58153     #endif
58154     #ifdef EMEDIUMTYPE
58155         case EMEDIUMTYPE: return DRFLAC_ERROR;
58156     #endif
58157     #ifdef ECANCELED
58158         case ECANCELED: return DRFLAC_CANCELLED;
58159     #endif
58160     #ifdef ENOKEY
58161         case ENOKEY: return DRFLAC_ERROR;
58162     #endif
58163     #ifdef EKEYEXPIRED
58164         case EKEYEXPIRED: return DRFLAC_ERROR;
58165     #endif
58166     #ifdef EKEYREVOKED
58167         case EKEYREVOKED: return DRFLAC_ERROR;
58168     #endif
58169     #ifdef EKEYREJECTED
58170         case EKEYREJECTED: return DRFLAC_ERROR;
58171     #endif
58172     #ifdef EOWNERDEAD
58173         case EOWNERDEAD: return DRFLAC_ERROR;
58174     #endif
58175     #ifdef ENOTRECOVERABLE
58176         case ENOTRECOVERABLE: return DRFLAC_ERROR;
58177     #endif
58178     #ifdef ERFKILL
58179         case ERFKILL: return DRFLAC_ERROR;
58180     #endif
58181     #ifdef EHWPOISON
58182         case EHWPOISON: return DRFLAC_ERROR;
58183     #endif
58184         default: return DRFLAC_ERROR;
58185     }
58186 }
58187 static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
58188 {
58189 #if defined(_MSC_VER) && _MSC_VER >= 1400
58190     errno_t err;
58191 #endif
58192     if (ppFile != NULL) {
58193         *ppFile = NULL;
58194     }
58195     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
58196         return DRFLAC_INVALID_ARGS;
58197     }
58198 #if defined(_MSC_VER) && _MSC_VER >= 1400
58199     err = fopen_s(ppFile, pFilePath, pOpenMode);
58200     if (err != 0) {
58201         return drflac_result_from_errno(err);
58202     }
58203 #else
58204 #if defined(_WIN32) || defined(__APPLE__)
58205     *ppFile = fopen(pFilePath, pOpenMode);
58206 #else
58207     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
58208         *ppFile = fopen64(pFilePath, pOpenMode);
58209     #else
58210         *ppFile = fopen(pFilePath, pOpenMode);
58211     #endif
58212 #endif
58213     if (*ppFile == NULL) {
58214         drflac_result result = drflac_result_from_errno(errno);
58215         if (result == DRFLAC_SUCCESS) {
58216             result = DRFLAC_ERROR;
58217         }
58218         return result;
58219     }
58220 #endif
58221     return DRFLAC_SUCCESS;
58222 }
58223 #if defined(_WIN32)
58224     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
58225         #define DRFLAC_HAS_WFOPEN
58226     #endif
58227 #endif
58228 static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks)
58229 {
58230     if (ppFile != NULL) {
58231         *ppFile = NULL;
58232     }
58233     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
58234         return DRFLAC_INVALID_ARGS;
58235     }
58236 #if defined(DRFLAC_HAS_WFOPEN)
58237     {
58238     #if defined(_MSC_VER) && _MSC_VER >= 1400
58239         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
58240         if (err != 0) {
58241             return drflac_result_from_errno(err);
58242         }
58243     #else
58244         *ppFile = _wfopen(pFilePath, pOpenMode);
58245         if (*ppFile == NULL) {
58246             return drflac_result_from_errno(errno);
58247         }
58248     #endif
58249         (void)pAllocationCallbacks;
58250     }
58251 #else
58252     {
58253         mbstate_t mbs;
58254         size_t lenMB;
58255         const wchar_t* pFilePathTemp = pFilePath;
58256         char* pFilePathMB = NULL;
58257         char pOpenModeMB[32] = {0};
58258         DRFLAC_ZERO_OBJECT(&mbs);
58259         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
58260         if (lenMB == (size_t)-1) {
58261             return drflac_result_from_errno(errno);
58262         }
58263         pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
58264         if (pFilePathMB == NULL) {
58265             return DRFLAC_OUT_OF_MEMORY;
58266         }
58267         pFilePathTemp = pFilePath;
58268         DRFLAC_ZERO_OBJECT(&mbs);
58269         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
58270         {
58271             size_t i = 0;
58272             for (;;) {
58273                 if (pOpenMode[i] == 0) {
58274                     pOpenModeMB[i] = '\0';
58275                     break;
58276                 }
58277                 pOpenModeMB[i] = (char)pOpenMode[i];
58278                 i += 1;
58279             }
58280         }
58281         *ppFile = fopen(pFilePathMB, pOpenModeMB);
58282         drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
58283     }
58284     if (*ppFile == NULL) {
58285         return DRFLAC_ERROR;
58286     }
58287 #endif
58288     return DRFLAC_SUCCESS;
58289 }
58290 static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
58291 {
58292     return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
58293 }
58294 static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
58295 {
58296     DRFLAC_ASSERT(offset >= 0);
58297     return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
58298 }
58299 DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
58300 {
58301     drflac* pFlac;
58302     FILE* pFile;
58303     if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
58304         return NULL;
58305     }
58306     pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
58307     if (pFlac == NULL) {
58308         fclose(pFile);
58309         return NULL;
58310     }
58311     return pFlac;
58312 }
58313 DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
58314 {
58315     drflac* pFlac;
58316     FILE* pFile;
58317     if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
58318         return NULL;
58319     }
58320     pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
58321     if (pFlac == NULL) {
58322         fclose(pFile);
58323         return NULL;
58324     }
58325     return pFlac;
58326 }
58327 DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
58328 {
58329     drflac* pFlac;
58330     FILE* pFile;
58331     if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
58332         return NULL;
58333     }
58334     pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
58335     if (pFlac == NULL) {
58336         fclose(pFile);
58337         return pFlac;
58338     }
58339     return pFlac;
58340 }
58341 DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
58342 {
58343     drflac* pFlac;
58344     FILE* pFile;
58345     if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
58346         return NULL;
58347     }
58348     pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
58349     if (pFlac == NULL) {
58350         fclose(pFile);
58351         return pFlac;
58352     }
58353     return pFlac;
58354 }
58355 #endif
58356 static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
58357 {
58358     drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
58359     size_t bytesRemaining;
58360     DRFLAC_ASSERT(memoryStream != NULL);
58361     DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos);
58362     bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos;
58363     if (bytesToRead > bytesRemaining) {
58364         bytesToRead = bytesRemaining;
58365     }
58366     if (bytesToRead > 0) {
58367         DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead);
58368         memoryStream->currentReadPos += bytesToRead;
58369     }
58370     return bytesToRead;
58371 }
58372 static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
58373 {
58374     drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
58375     DRFLAC_ASSERT(memoryStream != NULL);
58376     DRFLAC_ASSERT(offset >= 0);
58377     if (offset > (drflac_int64)memoryStream->dataSize) {
58378         return DRFLAC_FALSE;
58379     }
58380     if (origin == drflac_seek_origin_current) {
58381         if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
58382             memoryStream->currentReadPos += offset;
58383         } else {
58384             return DRFLAC_FALSE;
58385         }
58386     } else {
58387         if ((drflac_uint32)offset <= memoryStream->dataSize) {
58388             memoryStream->currentReadPos = offset;
58389         } else {
58390             return DRFLAC_FALSE;
58391         }
58392     }
58393     return DRFLAC_TRUE;
58394 }
58395 DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks)
58396 {
58397     drflac__memory_stream memoryStream;
58398     drflac* pFlac;
58399     memoryStream.data = (const drflac_uint8*)pData;
58400     memoryStream.dataSize = dataSize;
58401     memoryStream.currentReadPos = 0;
58402     pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
58403     if (pFlac == NULL) {
58404         return NULL;
58405     }
58406     pFlac->memoryStream = memoryStream;
58407 #ifndef DR_FLAC_NO_OGG
58408     if (pFlac->container == drflac_container_ogg)
58409     {
58410         drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
58411         oggbs->pUserData = &pFlac->memoryStream;
58412     }
58413     else
58414 #endif
58415     {
58416         pFlac->bs.pUserData = &pFlac->memoryStream;
58417     }
58418     return pFlac;
58419 }
58420 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)
58421 {
58422     drflac__memory_stream memoryStream;
58423     drflac* pFlac;
58424     memoryStream.data = (const drflac_uint8*)pData;
58425     memoryStream.dataSize = dataSize;
58426     memoryStream.currentReadPos = 0;
58427     pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
58428     if (pFlac == NULL) {
58429         return NULL;
58430     }
58431     pFlac->memoryStream = memoryStream;
58432 #ifndef DR_FLAC_NO_OGG
58433     if (pFlac->container == drflac_container_ogg)
58434     {
58435         drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
58436         oggbs->pUserData = &pFlac->memoryStream;
58437     }
58438     else
58439 #endif
58440     {
58441         pFlac->bs.pUserData = &pFlac->memoryStream;
58442     }
58443     return pFlac;
58444 }
58445 DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
58446 {
58447     return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
58448 }
58449 DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
58450 {
58451     return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
58452 }
58453 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)
58454 {
58455     return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
58456 }
58457 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)
58458 {
58459     return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
58460 }
58461 DRFLAC_API void drflac_close(drflac* pFlac)
58462 {
58463     if (pFlac == NULL) {
58464         return;
58465     }
58466 #ifndef DR_FLAC_NO_STDIO
58467     if (pFlac->bs.onRead == drflac__on_read_stdio) {
58468         fclose((FILE*)pFlac->bs.pUserData);
58469     }
58470 #ifndef DR_FLAC_NO_OGG
58471     if (pFlac->container == drflac_container_ogg) {
58472         drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
58473         DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg);
58474         if (oggbs->onRead == drflac__on_read_stdio) {
58475             fclose((FILE*)oggbs->pUserData);
58476         }
58477     }
58478 #endif
58479 #endif
58480     drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks);
58481 }
58482 #if 0
58483 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)
58484 {
58485     drflac_uint64 i;
58486     for (i = 0; i < frameCount; ++i) {
58487         drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
58488         drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
58489         drflac_uint32 right = left - side;
58490         pOutputSamples[i*2+0] = (drflac_int32)left;
58491         pOutputSamples[i*2+1] = (drflac_int32)right;
58492     }
58493 }
58494 #endif
58495 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)
58496 {
58497     drflac_uint64 i;
58498     drflac_uint64 frameCount4 = frameCount >> 2;
58499     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58500     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58501     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58502     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58503     for (i = 0; i < frameCount4; ++i) {
58504         drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
58505         drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
58506         drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
58507         drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
58508         drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
58509         drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
58510         drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
58511         drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
58512         drflac_uint32 right0 = left0 - side0;
58513         drflac_uint32 right1 = left1 - side1;
58514         drflac_uint32 right2 = left2 - side2;
58515         drflac_uint32 right3 = left3 - side3;
58516         pOutputSamples[i*8+0] = (drflac_int32)left0;
58517         pOutputSamples[i*8+1] = (drflac_int32)right0;
58518         pOutputSamples[i*8+2] = (drflac_int32)left1;
58519         pOutputSamples[i*8+3] = (drflac_int32)right1;
58520         pOutputSamples[i*8+4] = (drflac_int32)left2;
58521         pOutputSamples[i*8+5] = (drflac_int32)right2;
58522         pOutputSamples[i*8+6] = (drflac_int32)left3;
58523         pOutputSamples[i*8+7] = (drflac_int32)right3;
58524     }
58525     for (i = (frameCount4 << 2); i < frameCount; ++i) {
58526         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
58527         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
58528         drflac_uint32 right = left - side;
58529         pOutputSamples[i*2+0] = (drflac_int32)left;
58530         pOutputSamples[i*2+1] = (drflac_int32)right;
58531     }
58532 }
58533 #if defined(DRFLAC_SUPPORT_SSE2)
58534 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)
58535 {
58536     drflac_uint64 i;
58537     drflac_uint64 frameCount4 = frameCount >> 2;
58538     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58539     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58540     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58541     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58542     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
58543     for (i = 0; i < frameCount4; ++i) {
58544         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
58545         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
58546         __m128i right = _mm_sub_epi32(left, side);
58547         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
58548         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
58549     }
58550     for (i = (frameCount4 << 2); i < frameCount; ++i) {
58551         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
58552         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
58553         drflac_uint32 right = left - side;
58554         pOutputSamples[i*2+0] = (drflac_int32)left;
58555         pOutputSamples[i*2+1] = (drflac_int32)right;
58556     }
58557 }
58558 #endif
58559 #if defined(DRFLAC_SUPPORT_NEON)
58560 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)
58561 {
58562     drflac_uint64 i;
58563     drflac_uint64 frameCount4 = frameCount >> 2;
58564     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58565     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58566     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58567     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58568     int32x4_t shift0_4;
58569     int32x4_t shift1_4;
58570     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
58571     shift0_4 = vdupq_n_s32(shift0);
58572     shift1_4 = vdupq_n_s32(shift1);
58573     for (i = 0; i < frameCount4; ++i) {
58574         uint32x4_t left;
58575         uint32x4_t side;
58576         uint32x4_t right;
58577         left  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
58578         side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
58579         right = vsubq_u32(left, side);
58580         drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
58581     }
58582     for (i = (frameCount4 << 2); i < frameCount; ++i) {
58583         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
58584         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
58585         drflac_uint32 right = left - side;
58586         pOutputSamples[i*2+0] = (drflac_int32)left;
58587         pOutputSamples[i*2+1] = (drflac_int32)right;
58588     }
58589 }
58590 #endif
58591 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)
58592 {
58593 #if defined(DRFLAC_SUPPORT_SSE2)
58594     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
58595         drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58596     } else
58597 #elif defined(DRFLAC_SUPPORT_NEON)
58598     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
58599         drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58600     } else
58601 #endif
58602     {
58603 #if 0
58604         drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58605 #else
58606         drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58607 #endif
58608     }
58609 }
58610 #if 0
58611 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)
58612 {
58613     drflac_uint64 i;
58614     for (i = 0; i < frameCount; ++i) {
58615         drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
58616         drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
58617         drflac_uint32 left  = right + side;
58618         pOutputSamples[i*2+0] = (drflac_int32)left;
58619         pOutputSamples[i*2+1] = (drflac_int32)right;
58620     }
58621 }
58622 #endif
58623 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)
58624 {
58625     drflac_uint64 i;
58626     drflac_uint64 frameCount4 = frameCount >> 2;
58627     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58628     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58629     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58630     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58631     for (i = 0; i < frameCount4; ++i) {
58632         drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
58633         drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
58634         drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
58635         drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
58636         drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
58637         drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
58638         drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
58639         drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
58640         drflac_uint32 left0 = right0 + side0;
58641         drflac_uint32 left1 = right1 + side1;
58642         drflac_uint32 left2 = right2 + side2;
58643         drflac_uint32 left3 = right3 + side3;
58644         pOutputSamples[i*8+0] = (drflac_int32)left0;
58645         pOutputSamples[i*8+1] = (drflac_int32)right0;
58646         pOutputSamples[i*8+2] = (drflac_int32)left1;
58647         pOutputSamples[i*8+3] = (drflac_int32)right1;
58648         pOutputSamples[i*8+4] = (drflac_int32)left2;
58649         pOutputSamples[i*8+5] = (drflac_int32)right2;
58650         pOutputSamples[i*8+6] = (drflac_int32)left3;
58651         pOutputSamples[i*8+7] = (drflac_int32)right3;
58652     }
58653     for (i = (frameCount4 << 2); i < frameCount; ++i) {
58654         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
58655         drflac_uint32 right = pInputSamples1U32[i] << shift1;
58656         drflac_uint32 left  = right + side;
58657         pOutputSamples[i*2+0] = (drflac_int32)left;
58658         pOutputSamples[i*2+1] = (drflac_int32)right;
58659     }
58660 }
58661 #if defined(DRFLAC_SUPPORT_SSE2)
58662 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)
58663 {
58664     drflac_uint64 i;
58665     drflac_uint64 frameCount4 = frameCount >> 2;
58666     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58667     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58668     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58669     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58670     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
58671     for (i = 0; i < frameCount4; ++i) {
58672         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
58673         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
58674         __m128i left  = _mm_add_epi32(right, side);
58675         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
58676         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
58677     }
58678     for (i = (frameCount4 << 2); i < frameCount; ++i) {
58679         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
58680         drflac_uint32 right = pInputSamples1U32[i] << shift1;
58681         drflac_uint32 left  = right + side;
58682         pOutputSamples[i*2+0] = (drflac_int32)left;
58683         pOutputSamples[i*2+1] = (drflac_int32)right;
58684     }
58685 }
58686 #endif
58687 #if defined(DRFLAC_SUPPORT_NEON)
58688 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)
58689 {
58690     drflac_uint64 i;
58691     drflac_uint64 frameCount4 = frameCount >> 2;
58692     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58693     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58694     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58695     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58696     int32x4_t shift0_4;
58697     int32x4_t shift1_4;
58698     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
58699     shift0_4 = vdupq_n_s32(shift0);
58700     shift1_4 = vdupq_n_s32(shift1);
58701     for (i = 0; i < frameCount4; ++i) {
58702         uint32x4_t side;
58703         uint32x4_t right;
58704         uint32x4_t left;
58705         side  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
58706         right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
58707         left  = vaddq_u32(right, side);
58708         drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
58709     }
58710     for (i = (frameCount4 << 2); i < frameCount; ++i) {
58711         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
58712         drflac_uint32 right = pInputSamples1U32[i] << shift1;
58713         drflac_uint32 left  = right + side;
58714         pOutputSamples[i*2+0] = (drflac_int32)left;
58715         pOutputSamples[i*2+1] = (drflac_int32)right;
58716     }
58717 }
58718 #endif
58719 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)
58720 {
58721 #if defined(DRFLAC_SUPPORT_SSE2)
58722     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
58723         drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58724     } else
58725 #elif defined(DRFLAC_SUPPORT_NEON)
58726     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
58727         drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58728     } else
58729 #endif
58730     {
58731 #if 0
58732         drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58733 #else
58734         drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58735 #endif
58736     }
58737 }
58738 #if 0
58739 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)
58740 {
58741     for (drflac_uint64 i = 0; i < frameCount; ++i) {
58742         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58743         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58744         mid = (mid << 1) | (side & 0x01);
58745         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
58746         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
58747     }
58748 }
58749 #endif
58750 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)
58751 {
58752     drflac_uint64 i;
58753     drflac_uint64 frameCount4 = frameCount >> 2;
58754     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58755     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58756     drflac_int32 shift = unusedBitsPerSample;
58757     if (shift > 0) {
58758         shift -= 1;
58759         for (i = 0; i < frameCount4; ++i) {
58760             drflac_uint32 temp0L;
58761             drflac_uint32 temp1L;
58762             drflac_uint32 temp2L;
58763             drflac_uint32 temp3L;
58764             drflac_uint32 temp0R;
58765             drflac_uint32 temp1R;
58766             drflac_uint32 temp2R;
58767             drflac_uint32 temp3R;
58768             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58769             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58770             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58771             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58772             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58773             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58774             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58775             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58776             mid0 = (mid0 << 1) | (side0 & 0x01);
58777             mid1 = (mid1 << 1) | (side1 & 0x01);
58778             mid2 = (mid2 << 1) | (side2 & 0x01);
58779             mid3 = (mid3 << 1) | (side3 & 0x01);
58780             temp0L = (mid0 + side0) << shift;
58781             temp1L = (mid1 + side1) << shift;
58782             temp2L = (mid2 + side2) << shift;
58783             temp3L = (mid3 + side3) << shift;
58784             temp0R = (mid0 - side0) << shift;
58785             temp1R = (mid1 - side1) << shift;
58786             temp2R = (mid2 - side2) << shift;
58787             temp3R = (mid3 - side3) << shift;
58788             pOutputSamples[i*8+0] = (drflac_int32)temp0L;
58789             pOutputSamples[i*8+1] = (drflac_int32)temp0R;
58790             pOutputSamples[i*8+2] = (drflac_int32)temp1L;
58791             pOutputSamples[i*8+3] = (drflac_int32)temp1R;
58792             pOutputSamples[i*8+4] = (drflac_int32)temp2L;
58793             pOutputSamples[i*8+5] = (drflac_int32)temp2R;
58794             pOutputSamples[i*8+6] = (drflac_int32)temp3L;
58795             pOutputSamples[i*8+7] = (drflac_int32)temp3R;
58796         }
58797     } else {
58798         for (i = 0; i < frameCount4; ++i) {
58799             drflac_uint32 temp0L;
58800             drflac_uint32 temp1L;
58801             drflac_uint32 temp2L;
58802             drflac_uint32 temp3L;
58803             drflac_uint32 temp0R;
58804             drflac_uint32 temp1R;
58805             drflac_uint32 temp2R;
58806             drflac_uint32 temp3R;
58807             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58808             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58809             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58810             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58811             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58812             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58813             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58814             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58815             mid0 = (mid0 << 1) | (side0 & 0x01);
58816             mid1 = (mid1 << 1) | (side1 & 0x01);
58817             mid2 = (mid2 << 1) | (side2 & 0x01);
58818             mid3 = (mid3 << 1) | (side3 & 0x01);
58819             temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
58820             temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
58821             temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
58822             temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
58823             temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
58824             temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
58825             temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
58826             temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
58827             pOutputSamples[i*8+0] = (drflac_int32)temp0L;
58828             pOutputSamples[i*8+1] = (drflac_int32)temp0R;
58829             pOutputSamples[i*8+2] = (drflac_int32)temp1L;
58830             pOutputSamples[i*8+3] = (drflac_int32)temp1R;
58831             pOutputSamples[i*8+4] = (drflac_int32)temp2L;
58832             pOutputSamples[i*8+5] = (drflac_int32)temp2R;
58833             pOutputSamples[i*8+6] = (drflac_int32)temp3L;
58834             pOutputSamples[i*8+7] = (drflac_int32)temp3R;
58835         }
58836     }
58837     for (i = (frameCount4 << 2); i < frameCount; ++i) {
58838         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58839         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58840         mid = (mid << 1) | (side & 0x01);
58841         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
58842         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
58843     }
58844 }
58845 #if defined(DRFLAC_SUPPORT_SSE2)
58846 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)
58847 {
58848     drflac_uint64 i;
58849     drflac_uint64 frameCount4 = frameCount >> 2;
58850     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58851     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58852     drflac_int32 shift = unusedBitsPerSample;
58853     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
58854     if (shift == 0) {
58855         for (i = 0; i < frameCount4; ++i) {
58856             __m128i mid;
58857             __m128i side;
58858             __m128i left;
58859             __m128i right;
58860             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
58861             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
58862             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
58863             left  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
58864             right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
58865             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
58866             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
58867         }
58868         for (i = (frameCount4 << 2); i < frameCount; ++i) {
58869             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58870             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58871             mid = (mid << 1) | (side & 0x01);
58872             pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
58873             pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
58874         }
58875     } else {
58876         shift -= 1;
58877         for (i = 0; i < frameCount4; ++i) {
58878             __m128i mid;
58879             __m128i side;
58880             __m128i left;
58881             __m128i right;
58882             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
58883             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
58884             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
58885             left  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
58886             right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
58887             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
58888             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
58889         }
58890         for (i = (frameCount4 << 2); i < frameCount; ++i) {
58891             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58892             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58893             mid = (mid << 1) | (side & 0x01);
58894             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
58895             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
58896         }
58897     }
58898 }
58899 #endif
58900 #if defined(DRFLAC_SUPPORT_NEON)
58901 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)
58902 {
58903     drflac_uint64 i;
58904     drflac_uint64 frameCount4 = frameCount >> 2;
58905     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58906     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58907     drflac_int32 shift = unusedBitsPerSample;
58908     int32x4_t  wbpsShift0_4;
58909     int32x4_t  wbpsShift1_4;
58910     uint32x4_t one4;
58911     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
58912     wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
58913     wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
58914     one4         = vdupq_n_u32(1);
58915     if (shift == 0) {
58916         for (i = 0; i < frameCount4; ++i) {
58917             uint32x4_t mid;
58918             uint32x4_t side;
58919             int32x4_t left;
58920             int32x4_t right;
58921             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
58922             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
58923             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
58924             left  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
58925             right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
58926             drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
58927         }
58928         for (i = (frameCount4 << 2); i < frameCount; ++i) {
58929             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58930             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58931             mid = (mid << 1) | (side & 0x01);
58932             pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
58933             pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
58934         }
58935     } else {
58936         int32x4_t shift4;
58937         shift -= 1;
58938         shift4 = vdupq_n_s32(shift);
58939         for (i = 0; i < frameCount4; ++i) {
58940             uint32x4_t mid;
58941             uint32x4_t side;
58942             int32x4_t left;
58943             int32x4_t right;
58944             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
58945             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
58946             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
58947             left  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
58948             right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
58949             drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
58950         }
58951         for (i = (frameCount4 << 2); i < frameCount; ++i) {
58952             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58953             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58954             mid = (mid << 1) | (side & 0x01);
58955             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
58956             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
58957         }
58958     }
58959 }
58960 #endif
58961 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)
58962 {
58963 #if defined(DRFLAC_SUPPORT_SSE2)
58964     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
58965         drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58966     } else
58967 #elif defined(DRFLAC_SUPPORT_NEON)
58968     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
58969         drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58970     } else
58971 #endif
58972     {
58973 #if 0
58974         drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58975 #else
58976         drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
58977 #endif
58978     }
58979 }
58980 #if 0
58981 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)
58982 {
58983     for (drflac_uint64 i = 0; i < frameCount; ++i) {
58984         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample));
58985         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample));
58986     }
58987 }
58988 #endif
58989 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)
58990 {
58991     drflac_uint64 i;
58992     drflac_uint64 frameCount4 = frameCount >> 2;
58993     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
58994     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
58995     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
58996     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
58997     for (i = 0; i < frameCount4; ++i) {
58998         drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
58999         drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
59000         drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
59001         drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
59002         drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
59003         drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
59004         drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
59005         drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
59006         pOutputSamples[i*8+0] = (drflac_int32)tempL0;
59007         pOutputSamples[i*8+1] = (drflac_int32)tempR0;
59008         pOutputSamples[i*8+2] = (drflac_int32)tempL1;
59009         pOutputSamples[i*8+3] = (drflac_int32)tempR1;
59010         pOutputSamples[i*8+4] = (drflac_int32)tempL2;
59011         pOutputSamples[i*8+5] = (drflac_int32)tempR2;
59012         pOutputSamples[i*8+6] = (drflac_int32)tempL3;
59013         pOutputSamples[i*8+7] = (drflac_int32)tempR3;
59014     }
59015     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59016         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
59017         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
59018     }
59019 }
59020 #if defined(DRFLAC_SUPPORT_SSE2)
59021 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)
59022 {
59023     drflac_uint64 i;
59024     drflac_uint64 frameCount4 = frameCount >> 2;
59025     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59026     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59027     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59028     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59029     for (i = 0; i < frameCount4; ++i) {
59030         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
59031         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
59032         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
59033         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
59034     }
59035     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59036         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
59037         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
59038     }
59039 }
59040 #endif
59041 #if defined(DRFLAC_SUPPORT_NEON)
59042 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)
59043 {
59044     drflac_uint64 i;
59045     drflac_uint64 frameCount4 = frameCount >> 2;
59046     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59047     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59048     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59049     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59050     int32x4_t shift4_0 = vdupq_n_s32(shift0);
59051     int32x4_t shift4_1 = vdupq_n_s32(shift1);
59052     for (i = 0; i < frameCount4; ++i) {
59053         int32x4_t left;
59054         int32x4_t right;
59055         left  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0));
59056         right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1));
59057         drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
59058     }
59059     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59060         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
59061         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
59062     }
59063 }
59064 #endif
59065 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)
59066 {
59067 #if defined(DRFLAC_SUPPORT_SSE2)
59068     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
59069         drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59070     } else
59071 #elif defined(DRFLAC_SUPPORT_NEON)
59072     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
59073         drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59074     } else
59075 #endif
59076     {
59077 #if 0
59078         drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59079 #else
59080         drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59081 #endif
59082     }
59083 }
59084 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut)
59085 {
59086     drflac_uint64 framesRead;
59087     drflac_uint32 unusedBitsPerSample;
59088     if (pFlac == NULL || framesToRead == 0) {
59089         return 0;
59090     }
59091     if (pBufferOut == NULL) {
59092         return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
59093     }
59094     DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
59095     unusedBitsPerSample = 32 - pFlac->bitsPerSample;
59096     framesRead = 0;
59097     while (framesToRead > 0) {
59098         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
59099             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
59100                 break;
59101             }
59102         } else {
59103             unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
59104             drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
59105             drflac_uint64 frameCountThisIteration = framesToRead;
59106             if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
59107                 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
59108             }
59109             if (channelCount == 2) {
59110                 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
59111                 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
59112                 switch (pFlac->currentFLACFrame.header.channelAssignment)
59113                 {
59114                     case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
59115                     {
59116                         drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59117                     } break;
59118                     case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
59119                     {
59120                         drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59121                     } break;
59122                     case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
59123                     {
59124                         drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59125                     } break;
59126                     case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
59127                     default:
59128                     {
59129                         drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59130                     } break;
59131                 }
59132             } else {
59133                 drflac_uint64 i;
59134                 for (i = 0; i < frameCountThisIteration; ++i) {
59135                     unsigned int j;
59136                     for (j = 0; j < channelCount; ++j) {
59137                         pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
59138                     }
59139                 }
59140             }
59141             framesRead                += frameCountThisIteration;
59142             pBufferOut                += frameCountThisIteration * channelCount;
59143             framesToRead              -= frameCountThisIteration;
59144             pFlac->currentPCMFrame    += frameCountThisIteration;
59145             pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
59146         }
59147     }
59148     return framesRead;
59149 }
59150 #if 0
59151 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)
59152 {
59153     drflac_uint64 i;
59154     for (i = 0; i < frameCount; ++i) {
59155         drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
59156         drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
59157         drflac_uint32 right = left - side;
59158         left  >>= 16;
59159         right >>= 16;
59160         pOutputSamples[i*2+0] = (drflac_int16)left;
59161         pOutputSamples[i*2+1] = (drflac_int16)right;
59162     }
59163 }
59164 #endif
59165 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)
59166 {
59167     drflac_uint64 i;
59168     drflac_uint64 frameCount4 = frameCount >> 2;
59169     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59170     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59171     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59172     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59173     for (i = 0; i < frameCount4; ++i) {
59174         drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
59175         drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
59176         drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
59177         drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
59178         drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
59179         drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
59180         drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
59181         drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
59182         drflac_uint32 right0 = left0 - side0;
59183         drflac_uint32 right1 = left1 - side1;
59184         drflac_uint32 right2 = left2 - side2;
59185         drflac_uint32 right3 = left3 - side3;
59186         left0  >>= 16;
59187         left1  >>= 16;
59188         left2  >>= 16;
59189         left3  >>= 16;
59190         right0 >>= 16;
59191         right1 >>= 16;
59192         right2 >>= 16;
59193         right3 >>= 16;
59194         pOutputSamples[i*8+0] = (drflac_int16)left0;
59195         pOutputSamples[i*8+1] = (drflac_int16)right0;
59196         pOutputSamples[i*8+2] = (drflac_int16)left1;
59197         pOutputSamples[i*8+3] = (drflac_int16)right1;
59198         pOutputSamples[i*8+4] = (drflac_int16)left2;
59199         pOutputSamples[i*8+5] = (drflac_int16)right2;
59200         pOutputSamples[i*8+6] = (drflac_int16)left3;
59201         pOutputSamples[i*8+7] = (drflac_int16)right3;
59202     }
59203     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59204         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
59205         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
59206         drflac_uint32 right = left - side;
59207         left  >>= 16;
59208         right >>= 16;
59209         pOutputSamples[i*2+0] = (drflac_int16)left;
59210         pOutputSamples[i*2+1] = (drflac_int16)right;
59211     }
59212 }
59213 #if defined(DRFLAC_SUPPORT_SSE2)
59214 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)
59215 {
59216     drflac_uint64 i;
59217     drflac_uint64 frameCount4 = frameCount >> 2;
59218     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59219     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59220     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59221     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59222     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59223     for (i = 0; i < frameCount4; ++i) {
59224         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
59225         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
59226         __m128i right = _mm_sub_epi32(left, side);
59227         left  = _mm_srai_epi32(left,  16);
59228         right = _mm_srai_epi32(right, 16);
59229         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
59230     }
59231     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59232         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
59233         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
59234         drflac_uint32 right = left - side;
59235         left  >>= 16;
59236         right >>= 16;
59237         pOutputSamples[i*2+0] = (drflac_int16)left;
59238         pOutputSamples[i*2+1] = (drflac_int16)right;
59239     }
59240 }
59241 #endif
59242 #if defined(DRFLAC_SUPPORT_NEON)
59243 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)
59244 {
59245     drflac_uint64 i;
59246     drflac_uint64 frameCount4 = frameCount >> 2;
59247     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59248     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59249     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59250     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59251     int32x4_t shift0_4;
59252     int32x4_t shift1_4;
59253     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59254     shift0_4 = vdupq_n_s32(shift0);
59255     shift1_4 = vdupq_n_s32(shift1);
59256     for (i = 0; i < frameCount4; ++i) {
59257         uint32x4_t left;
59258         uint32x4_t side;
59259         uint32x4_t right;
59260         left  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
59261         side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
59262         right = vsubq_u32(left, side);
59263         left  = vshrq_n_u32(left,  16);
59264         right = vshrq_n_u32(right, 16);
59265         drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
59266     }
59267     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59268         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
59269         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
59270         drflac_uint32 right = left - side;
59271         left  >>= 16;
59272         right >>= 16;
59273         pOutputSamples[i*2+0] = (drflac_int16)left;
59274         pOutputSamples[i*2+1] = (drflac_int16)right;
59275     }
59276 }
59277 #endif
59278 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)
59279 {
59280 #if defined(DRFLAC_SUPPORT_SSE2)
59281     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
59282         drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59283     } else
59284 #elif defined(DRFLAC_SUPPORT_NEON)
59285     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
59286         drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59287     } else
59288 #endif
59289     {
59290 #if 0
59291         drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59292 #else
59293         drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59294 #endif
59295     }
59296 }
59297 #if 0
59298 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)
59299 {
59300     drflac_uint64 i;
59301     for (i = 0; i < frameCount; ++i) {
59302         drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
59303         drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
59304         drflac_uint32 left  = right + side;
59305         left  >>= 16;
59306         right >>= 16;
59307         pOutputSamples[i*2+0] = (drflac_int16)left;
59308         pOutputSamples[i*2+1] = (drflac_int16)right;
59309     }
59310 }
59311 #endif
59312 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)
59313 {
59314     drflac_uint64 i;
59315     drflac_uint64 frameCount4 = frameCount >> 2;
59316     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59317     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59318     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59319     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59320     for (i = 0; i < frameCount4; ++i) {
59321         drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
59322         drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
59323         drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
59324         drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
59325         drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
59326         drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
59327         drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
59328         drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
59329         drflac_uint32 left0 = right0 + side0;
59330         drflac_uint32 left1 = right1 + side1;
59331         drflac_uint32 left2 = right2 + side2;
59332         drflac_uint32 left3 = right3 + side3;
59333         left0  >>= 16;
59334         left1  >>= 16;
59335         left2  >>= 16;
59336         left3  >>= 16;
59337         right0 >>= 16;
59338         right1 >>= 16;
59339         right2 >>= 16;
59340         right3 >>= 16;
59341         pOutputSamples[i*8+0] = (drflac_int16)left0;
59342         pOutputSamples[i*8+1] = (drflac_int16)right0;
59343         pOutputSamples[i*8+2] = (drflac_int16)left1;
59344         pOutputSamples[i*8+3] = (drflac_int16)right1;
59345         pOutputSamples[i*8+4] = (drflac_int16)left2;
59346         pOutputSamples[i*8+5] = (drflac_int16)right2;
59347         pOutputSamples[i*8+6] = (drflac_int16)left3;
59348         pOutputSamples[i*8+7] = (drflac_int16)right3;
59349     }
59350     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59351         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
59352         drflac_uint32 right = pInputSamples1U32[i] << shift1;
59353         drflac_uint32 left  = right + side;
59354         left  >>= 16;
59355         right >>= 16;
59356         pOutputSamples[i*2+0] = (drflac_int16)left;
59357         pOutputSamples[i*2+1] = (drflac_int16)right;
59358     }
59359 }
59360 #if defined(DRFLAC_SUPPORT_SSE2)
59361 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)
59362 {
59363     drflac_uint64 i;
59364     drflac_uint64 frameCount4 = frameCount >> 2;
59365     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59366     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59367     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59368     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59369     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59370     for (i = 0; i < frameCount4; ++i) {
59371         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
59372         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
59373         __m128i left  = _mm_add_epi32(right, side);
59374         left  = _mm_srai_epi32(left,  16);
59375         right = _mm_srai_epi32(right, 16);
59376         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
59377     }
59378     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59379         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
59380         drflac_uint32 right = pInputSamples1U32[i] << shift1;
59381         drflac_uint32 left  = right + side;
59382         left  >>= 16;
59383         right >>= 16;
59384         pOutputSamples[i*2+0] = (drflac_int16)left;
59385         pOutputSamples[i*2+1] = (drflac_int16)right;
59386     }
59387 }
59388 #endif
59389 #if defined(DRFLAC_SUPPORT_NEON)
59390 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)
59391 {
59392     drflac_uint64 i;
59393     drflac_uint64 frameCount4 = frameCount >> 2;
59394     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59395     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59396     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59397     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59398     int32x4_t shift0_4;
59399     int32x4_t shift1_4;
59400     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59401     shift0_4 = vdupq_n_s32(shift0);
59402     shift1_4 = vdupq_n_s32(shift1);
59403     for (i = 0; i < frameCount4; ++i) {
59404         uint32x4_t side;
59405         uint32x4_t right;
59406         uint32x4_t left;
59407         side  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
59408         right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
59409         left  = vaddq_u32(right, side);
59410         left  = vshrq_n_u32(left,  16);
59411         right = vshrq_n_u32(right, 16);
59412         drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
59413     }
59414     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59415         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
59416         drflac_uint32 right = pInputSamples1U32[i] << shift1;
59417         drflac_uint32 left  = right + side;
59418         left  >>= 16;
59419         right >>= 16;
59420         pOutputSamples[i*2+0] = (drflac_int16)left;
59421         pOutputSamples[i*2+1] = (drflac_int16)right;
59422     }
59423 }
59424 #endif
59425 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)
59426 {
59427 #if defined(DRFLAC_SUPPORT_SSE2)
59428     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
59429         drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59430     } else
59431 #elif defined(DRFLAC_SUPPORT_NEON)
59432     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
59433         drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59434     } else
59435 #endif
59436     {
59437 #if 0
59438         drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59439 #else
59440         drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59441 #endif
59442     }
59443 }
59444 #if 0
59445 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)
59446 {
59447     for (drflac_uint64 i = 0; i < frameCount; ++i) {
59448         drflac_uint32 mid  = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59449         drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59450         mid = (mid << 1) | (side & 0x01);
59451         pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
59452         pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
59453     }
59454 }
59455 #endif
59456 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)
59457 {
59458     drflac_uint64 i;
59459     drflac_uint64 frameCount4 = frameCount >> 2;
59460     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59461     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59462     drflac_uint32 shift = unusedBitsPerSample;
59463     if (shift > 0) {
59464         shift -= 1;
59465         for (i = 0; i < frameCount4; ++i) {
59466             drflac_uint32 temp0L;
59467             drflac_uint32 temp1L;
59468             drflac_uint32 temp2L;
59469             drflac_uint32 temp3L;
59470             drflac_uint32 temp0R;
59471             drflac_uint32 temp1R;
59472             drflac_uint32 temp2R;
59473             drflac_uint32 temp3R;
59474             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59475             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59476             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59477             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59478             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59479             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59480             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59481             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59482             mid0 = (mid0 << 1) | (side0 & 0x01);
59483             mid1 = (mid1 << 1) | (side1 & 0x01);
59484             mid2 = (mid2 << 1) | (side2 & 0x01);
59485             mid3 = (mid3 << 1) | (side3 & 0x01);
59486             temp0L = (mid0 + side0) << shift;
59487             temp1L = (mid1 + side1) << shift;
59488             temp2L = (mid2 + side2) << shift;
59489             temp3L = (mid3 + side3) << shift;
59490             temp0R = (mid0 - side0) << shift;
59491             temp1R = (mid1 - side1) << shift;
59492             temp2R = (mid2 - side2) << shift;
59493             temp3R = (mid3 - side3) << shift;
59494             temp0L >>= 16;
59495             temp1L >>= 16;
59496             temp2L >>= 16;
59497             temp3L >>= 16;
59498             temp0R >>= 16;
59499             temp1R >>= 16;
59500             temp2R >>= 16;
59501             temp3R >>= 16;
59502             pOutputSamples[i*8+0] = (drflac_int16)temp0L;
59503             pOutputSamples[i*8+1] = (drflac_int16)temp0R;
59504             pOutputSamples[i*8+2] = (drflac_int16)temp1L;
59505             pOutputSamples[i*8+3] = (drflac_int16)temp1R;
59506             pOutputSamples[i*8+4] = (drflac_int16)temp2L;
59507             pOutputSamples[i*8+5] = (drflac_int16)temp2R;
59508             pOutputSamples[i*8+6] = (drflac_int16)temp3L;
59509             pOutputSamples[i*8+7] = (drflac_int16)temp3R;
59510         }
59511     } else {
59512         for (i = 0; i < frameCount4; ++i) {
59513             drflac_uint32 temp0L;
59514             drflac_uint32 temp1L;
59515             drflac_uint32 temp2L;
59516             drflac_uint32 temp3L;
59517             drflac_uint32 temp0R;
59518             drflac_uint32 temp1R;
59519             drflac_uint32 temp2R;
59520             drflac_uint32 temp3R;
59521             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59522             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59523             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59524             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59525             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59526             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59527             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59528             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59529             mid0 = (mid0 << 1) | (side0 & 0x01);
59530             mid1 = (mid1 << 1) | (side1 & 0x01);
59531             mid2 = (mid2 << 1) | (side2 & 0x01);
59532             mid3 = (mid3 << 1) | (side3 & 0x01);
59533             temp0L = ((drflac_int32)(mid0 + side0) >> 1);
59534             temp1L = ((drflac_int32)(mid1 + side1) >> 1);
59535             temp2L = ((drflac_int32)(mid2 + side2) >> 1);
59536             temp3L = ((drflac_int32)(mid3 + side3) >> 1);
59537             temp0R = ((drflac_int32)(mid0 - side0) >> 1);
59538             temp1R = ((drflac_int32)(mid1 - side1) >> 1);
59539             temp2R = ((drflac_int32)(mid2 - side2) >> 1);
59540             temp3R = ((drflac_int32)(mid3 - side3) >> 1);
59541             temp0L >>= 16;
59542             temp1L >>= 16;
59543             temp2L >>= 16;
59544             temp3L >>= 16;
59545             temp0R >>= 16;
59546             temp1R >>= 16;
59547             temp2R >>= 16;
59548             temp3R >>= 16;
59549             pOutputSamples[i*8+0] = (drflac_int16)temp0L;
59550             pOutputSamples[i*8+1] = (drflac_int16)temp0R;
59551             pOutputSamples[i*8+2] = (drflac_int16)temp1L;
59552             pOutputSamples[i*8+3] = (drflac_int16)temp1R;
59553             pOutputSamples[i*8+4] = (drflac_int16)temp2L;
59554             pOutputSamples[i*8+5] = (drflac_int16)temp2R;
59555             pOutputSamples[i*8+6] = (drflac_int16)temp3L;
59556             pOutputSamples[i*8+7] = (drflac_int16)temp3R;
59557         }
59558     }
59559     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59560         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59561         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59562         mid = (mid << 1) | (side & 0x01);
59563         pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
59564         pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
59565     }
59566 }
59567 #if defined(DRFLAC_SUPPORT_SSE2)
59568 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)
59569 {
59570     drflac_uint64 i;
59571     drflac_uint64 frameCount4 = frameCount >> 2;
59572     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59573     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59574     drflac_uint32 shift = unusedBitsPerSample;
59575     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59576     if (shift == 0) {
59577         for (i = 0; i < frameCount4; ++i) {
59578             __m128i mid;
59579             __m128i side;
59580             __m128i left;
59581             __m128i right;
59582             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
59583             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
59584             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
59585             left  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
59586             right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
59587             left  = _mm_srai_epi32(left,  16);
59588             right = _mm_srai_epi32(right, 16);
59589             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
59590         }
59591         for (i = (frameCount4 << 2); i < frameCount; ++i) {
59592             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59593             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59594             mid = (mid << 1) | (side & 0x01);
59595             pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
59596             pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
59597         }
59598     } else {
59599         shift -= 1;
59600         for (i = 0; i < frameCount4; ++i) {
59601             __m128i mid;
59602             __m128i side;
59603             __m128i left;
59604             __m128i right;
59605             mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
59606             side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
59607             mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
59608             left  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
59609             right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
59610             left  = _mm_srai_epi32(left,  16);
59611             right = _mm_srai_epi32(right, 16);
59612             _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
59613         }
59614         for (i = (frameCount4 << 2); i < frameCount; ++i) {
59615             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59616             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59617             mid = (mid << 1) | (side & 0x01);
59618             pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
59619             pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
59620         }
59621     }
59622 }
59623 #endif
59624 #if defined(DRFLAC_SUPPORT_NEON)
59625 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)
59626 {
59627     drflac_uint64 i;
59628     drflac_uint64 frameCount4 = frameCount >> 2;
59629     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59630     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59631     drflac_uint32 shift = unusedBitsPerSample;
59632     int32x4_t wbpsShift0_4;
59633     int32x4_t wbpsShift1_4;
59634     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59635     wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
59636     wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
59637     if (shift == 0) {
59638         for (i = 0; i < frameCount4; ++i) {
59639             uint32x4_t mid;
59640             uint32x4_t side;
59641             int32x4_t left;
59642             int32x4_t right;
59643             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
59644             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
59645             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
59646             left  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
59647             right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
59648             left  = vshrq_n_s32(left,  16);
59649             right = vshrq_n_s32(right, 16);
59650             drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
59651         }
59652         for (i = (frameCount4 << 2); i < frameCount; ++i) {
59653             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59654             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59655             mid = (mid << 1) | (side & 0x01);
59656             pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
59657             pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
59658         }
59659     } else {
59660         int32x4_t shift4;
59661         shift -= 1;
59662         shift4 = vdupq_n_s32(shift);
59663         for (i = 0; i < frameCount4; ++i) {
59664             uint32x4_t mid;
59665             uint32x4_t side;
59666             int32x4_t left;
59667             int32x4_t right;
59668             mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
59669             side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
59670             mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
59671             left  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
59672             right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
59673             left  = vshrq_n_s32(left,  16);
59674             right = vshrq_n_s32(right, 16);
59675             drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
59676         }
59677         for (i = (frameCount4 << 2); i < frameCount; ++i) {
59678             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59679             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59680             mid = (mid << 1) | (side & 0x01);
59681             pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
59682             pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
59683         }
59684     }
59685 }
59686 #endif
59687 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)
59688 {
59689 #if defined(DRFLAC_SUPPORT_SSE2)
59690     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
59691         drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59692     } else
59693 #elif defined(DRFLAC_SUPPORT_NEON)
59694     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
59695         drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59696     } else
59697 #endif
59698     {
59699 #if 0
59700         drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59701 #else
59702         drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59703 #endif
59704     }
59705 }
59706 #if 0
59707 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)
59708 {
59709     for (drflac_uint64 i = 0; i < frameCount; ++i) {
59710         pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16);
59711         pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16);
59712     }
59713 }
59714 #endif
59715 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)
59716 {
59717     drflac_uint64 i;
59718     drflac_uint64 frameCount4 = frameCount >> 2;
59719     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59720     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59721     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59722     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59723     for (i = 0; i < frameCount4; ++i) {
59724         drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
59725         drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
59726         drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
59727         drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
59728         drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
59729         drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
59730         drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
59731         drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
59732         tempL0 >>= 16;
59733         tempL1 >>= 16;
59734         tempL2 >>= 16;
59735         tempL3 >>= 16;
59736         tempR0 >>= 16;
59737         tempR1 >>= 16;
59738         tempR2 >>= 16;
59739         tempR3 >>= 16;
59740         pOutputSamples[i*8+0] = (drflac_int16)tempL0;
59741         pOutputSamples[i*8+1] = (drflac_int16)tempR0;
59742         pOutputSamples[i*8+2] = (drflac_int16)tempL1;
59743         pOutputSamples[i*8+3] = (drflac_int16)tempR1;
59744         pOutputSamples[i*8+4] = (drflac_int16)tempL2;
59745         pOutputSamples[i*8+5] = (drflac_int16)tempR2;
59746         pOutputSamples[i*8+6] = (drflac_int16)tempL3;
59747         pOutputSamples[i*8+7] = (drflac_int16)tempR3;
59748     }
59749     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59750         pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
59751         pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
59752     }
59753 }
59754 #if defined(DRFLAC_SUPPORT_SSE2)
59755 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)
59756 {
59757     drflac_uint64 i;
59758     drflac_uint64 frameCount4 = frameCount >> 2;
59759     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59760     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59761     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59762     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59763     for (i = 0; i < frameCount4; ++i) {
59764         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
59765         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
59766         left  = _mm_srai_epi32(left,  16);
59767         right = _mm_srai_epi32(right, 16);
59768         _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
59769     }
59770     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59771         pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
59772         pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
59773     }
59774 }
59775 #endif
59776 #if defined(DRFLAC_SUPPORT_NEON)
59777 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)
59778 {
59779     drflac_uint64 i;
59780     drflac_uint64 frameCount4 = frameCount >> 2;
59781     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59782     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59783     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59784     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59785     int32x4_t shift0_4 = vdupq_n_s32(shift0);
59786     int32x4_t shift1_4 = vdupq_n_s32(shift1);
59787     for (i = 0; i < frameCount4; ++i) {
59788         int32x4_t left;
59789         int32x4_t right;
59790         left  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
59791         right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
59792         left  = vshrq_n_s32(left,  16);
59793         right = vshrq_n_s32(right, 16);
59794         drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
59795     }
59796     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59797         pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
59798         pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
59799     }
59800 }
59801 #endif
59802 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)
59803 {
59804 #if defined(DRFLAC_SUPPORT_SSE2)
59805     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
59806         drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59807     } else
59808 #elif defined(DRFLAC_SUPPORT_NEON)
59809     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
59810         drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59811     } else
59812 #endif
59813     {
59814 #if 0
59815         drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59816 #else
59817         drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
59818 #endif
59819     }
59820 }
59821 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut)
59822 {
59823     drflac_uint64 framesRead;
59824     drflac_uint32 unusedBitsPerSample;
59825     if (pFlac == NULL || framesToRead == 0) {
59826         return 0;
59827     }
59828     if (pBufferOut == NULL) {
59829         return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
59830     }
59831     DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
59832     unusedBitsPerSample = 32 - pFlac->bitsPerSample;
59833     framesRead = 0;
59834     while (framesToRead > 0) {
59835         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
59836             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
59837                 break;
59838             }
59839         } else {
59840             unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
59841             drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
59842             drflac_uint64 frameCountThisIteration = framesToRead;
59843             if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
59844                 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
59845             }
59846             if (channelCount == 2) {
59847                 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
59848                 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
59849                 switch (pFlac->currentFLACFrame.header.channelAssignment)
59850                 {
59851                     case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
59852                     {
59853                         drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59854                     } break;
59855                     case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
59856                     {
59857                         drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59858                     } break;
59859                     case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
59860                     {
59861                         drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59862                     } break;
59863                     case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
59864                     default:
59865                     {
59866                         drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
59867                     } break;
59868                 }
59869             } else {
59870                 drflac_uint64 i;
59871                 for (i = 0; i < frameCountThisIteration; ++i) {
59872                     unsigned int j;
59873                     for (j = 0; j < channelCount; ++j) {
59874                         drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
59875                         pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16);
59876                     }
59877                 }
59878             }
59879             framesRead                += frameCountThisIteration;
59880             pBufferOut                += frameCountThisIteration * channelCount;
59881             framesToRead              -= frameCountThisIteration;
59882             pFlac->currentPCMFrame    += frameCountThisIteration;
59883             pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
59884         }
59885     }
59886     return framesRead;
59887 }
59888 #if 0
59889 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)
59890 {
59891     drflac_uint64 i;
59892     for (i = 0; i < frameCount; ++i) {
59893         drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
59894         drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
59895         drflac_uint32 right = left - side;
59896         pOutputSamples[i*2+0] = (float)((drflac_int32)left  / 2147483648.0);
59897         pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
59898     }
59899 }
59900 #endif
59901 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)
59902 {
59903     drflac_uint64 i;
59904     drflac_uint64 frameCount4 = frameCount >> 2;
59905     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59906     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59907     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
59908     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
59909     float factor = 1 / 2147483648.0;
59910     for (i = 0; i < frameCount4; ++i) {
59911         drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
59912         drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
59913         drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
59914         drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
59915         drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
59916         drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
59917         drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
59918         drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
59919         drflac_uint32 right0 = left0 - side0;
59920         drflac_uint32 right1 = left1 - side1;
59921         drflac_uint32 right2 = left2 - side2;
59922         drflac_uint32 right3 = left3 - side3;
59923         pOutputSamples[i*8+0] = (drflac_int32)left0  * factor;
59924         pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
59925         pOutputSamples[i*8+2] = (drflac_int32)left1  * factor;
59926         pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
59927         pOutputSamples[i*8+4] = (drflac_int32)left2  * factor;
59928         pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
59929         pOutputSamples[i*8+6] = (drflac_int32)left3  * factor;
59930         pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
59931     }
59932     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59933         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
59934         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
59935         drflac_uint32 right = left - side;
59936         pOutputSamples[i*2+0] = (drflac_int32)left  * factor;
59937         pOutputSamples[i*2+1] = (drflac_int32)right * factor;
59938     }
59939 }
59940 #if defined(DRFLAC_SUPPORT_SSE2)
59941 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)
59942 {
59943     drflac_uint64 i;
59944     drflac_uint64 frameCount4 = frameCount >> 2;
59945     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59946     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59947     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
59948     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
59949     __m128 factor;
59950     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59951     factor = _mm_set1_ps(1.0f / 8388608.0f);
59952     for (i = 0; i < frameCount4; ++i) {
59953         __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
59954         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
59955         __m128i right = _mm_sub_epi32(left, side);
59956         __m128 leftf  = _mm_mul_ps(_mm_cvtepi32_ps(left),  factor);
59957         __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
59958         _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
59959         _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
59960     }
59961     for (i = (frameCount4 << 2); i < frameCount; ++i) {
59962         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
59963         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
59964         drflac_uint32 right = left - side;
59965         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
59966         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
59967     }
59968 }
59969 #endif
59970 #if defined(DRFLAC_SUPPORT_NEON)
59971 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)
59972 {
59973     drflac_uint64 i;
59974     drflac_uint64 frameCount4 = frameCount >> 2;
59975     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
59976     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
59977     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
59978     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
59979     float32x4_t factor4;
59980     int32x4_t shift0_4;
59981     int32x4_t shift1_4;
59982     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
59983     factor4  = vdupq_n_f32(1.0f / 8388608.0f);
59984     shift0_4 = vdupq_n_s32(shift0);
59985     shift1_4 = vdupq_n_s32(shift1);
59986     for (i = 0; i < frameCount4; ++i) {
59987         uint32x4_t left;
59988         uint32x4_t side;
59989         uint32x4_t right;
59990         float32x4_t leftf;
59991         float32x4_t rightf;
59992         left   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
59993         side   = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
59994         right  = vsubq_u32(left, side);
59995         leftf  = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)),  factor4);
59996         rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
59997         drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
59998     }
59999     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60000         drflac_uint32 left  = pInputSamples0U32[i] << shift0;
60001         drflac_uint32 side  = pInputSamples1U32[i] << shift1;
60002         drflac_uint32 right = left - side;
60003         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
60004         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
60005     }
60006 }
60007 #endif
60008 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)
60009 {
60010 #if defined(DRFLAC_SUPPORT_SSE2)
60011     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
60012         drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60013     } else
60014 #elif defined(DRFLAC_SUPPORT_NEON)
60015     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
60016         drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60017     } else
60018 #endif
60019     {
60020 #if 0
60021         drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60022 #else
60023         drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60024 #endif
60025     }
60026 }
60027 #if 0
60028 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)
60029 {
60030     drflac_uint64 i;
60031     for (i = 0; i < frameCount; ++i) {
60032         drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
60033         drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
60034         drflac_uint32 left  = right + side;
60035         pOutputSamples[i*2+0] = (float)((drflac_int32)left  / 2147483648.0);
60036         pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
60037     }
60038 }
60039 #endif
60040 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)
60041 {
60042     drflac_uint64 i;
60043     drflac_uint64 frameCount4 = frameCount >> 2;
60044     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60045     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60046     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60047     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60048     float factor = 1 / 2147483648.0;
60049     for (i = 0; i < frameCount4; ++i) {
60050         drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
60051         drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
60052         drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
60053         drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
60054         drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
60055         drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
60056         drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
60057         drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
60058         drflac_uint32 left0 = right0 + side0;
60059         drflac_uint32 left1 = right1 + side1;
60060         drflac_uint32 left2 = right2 + side2;
60061         drflac_uint32 left3 = right3 + side3;
60062         pOutputSamples[i*8+0] = (drflac_int32)left0  * factor;
60063         pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
60064         pOutputSamples[i*8+2] = (drflac_int32)left1  * factor;
60065         pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
60066         pOutputSamples[i*8+4] = (drflac_int32)left2  * factor;
60067         pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
60068         pOutputSamples[i*8+6] = (drflac_int32)left3  * factor;
60069         pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
60070     }
60071     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60072         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
60073         drflac_uint32 right = pInputSamples1U32[i] << shift1;
60074         drflac_uint32 left  = right + side;
60075         pOutputSamples[i*2+0] = (drflac_int32)left  * factor;
60076         pOutputSamples[i*2+1] = (drflac_int32)right * factor;
60077     }
60078 }
60079 #if defined(DRFLAC_SUPPORT_SSE2)
60080 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)
60081 {
60082     drflac_uint64 i;
60083     drflac_uint64 frameCount4 = frameCount >> 2;
60084     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60085     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60086     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
60087     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
60088     __m128 factor;
60089     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
60090     factor = _mm_set1_ps(1.0f / 8388608.0f);
60091     for (i = 0; i < frameCount4; ++i) {
60092         __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
60093         __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
60094         __m128i left  = _mm_add_epi32(right, side);
60095         __m128 leftf  = _mm_mul_ps(_mm_cvtepi32_ps(left),  factor);
60096         __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
60097         _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
60098         _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
60099     }
60100     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60101         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
60102         drflac_uint32 right = pInputSamples1U32[i] << shift1;
60103         drflac_uint32 left  = right + side;
60104         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
60105         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
60106     }
60107 }
60108 #endif
60109 #if defined(DRFLAC_SUPPORT_NEON)
60110 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)
60111 {
60112     drflac_uint64 i;
60113     drflac_uint64 frameCount4 = frameCount >> 2;
60114     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60115     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60116     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
60117     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
60118     float32x4_t factor4;
60119     int32x4_t shift0_4;
60120     int32x4_t shift1_4;
60121     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
60122     factor4  = vdupq_n_f32(1.0f / 8388608.0f);
60123     shift0_4 = vdupq_n_s32(shift0);
60124     shift1_4 = vdupq_n_s32(shift1);
60125     for (i = 0; i < frameCount4; ++i) {
60126         uint32x4_t side;
60127         uint32x4_t right;
60128         uint32x4_t left;
60129         float32x4_t leftf;
60130         float32x4_t rightf;
60131         side   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
60132         right  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
60133         left   = vaddq_u32(right, side);
60134         leftf  = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)),  factor4);
60135         rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
60136         drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
60137     }
60138     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60139         drflac_uint32 side  = pInputSamples0U32[i] << shift0;
60140         drflac_uint32 right = pInputSamples1U32[i] << shift1;
60141         drflac_uint32 left  = right + side;
60142         pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
60143         pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
60144     }
60145 }
60146 #endif
60147 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)
60148 {
60149 #if defined(DRFLAC_SUPPORT_SSE2)
60150     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
60151         drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60152     } else
60153 #elif defined(DRFLAC_SUPPORT_NEON)
60154     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
60155         drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60156     } else
60157 #endif
60158     {
60159 #if 0
60160         drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60161 #else
60162         drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60163 #endif
60164     }
60165 }
60166 #if 0
60167 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)
60168 {
60169     for (drflac_uint64 i = 0; i < frameCount; ++i) {
60170         drflac_uint32 mid  = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60171         drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60172         mid = (mid << 1) | (side & 0x01);
60173         pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
60174         pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
60175     }
60176 }
60177 #endif
60178 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)
60179 {
60180     drflac_uint64 i;
60181     drflac_uint64 frameCount4 = frameCount >> 2;
60182     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60183     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60184     drflac_uint32 shift = unusedBitsPerSample;
60185     float factor = 1 / 2147483648.0;
60186     if (shift > 0) {
60187         shift -= 1;
60188         for (i = 0; i < frameCount4; ++i) {
60189             drflac_uint32 temp0L;
60190             drflac_uint32 temp1L;
60191             drflac_uint32 temp2L;
60192             drflac_uint32 temp3L;
60193             drflac_uint32 temp0R;
60194             drflac_uint32 temp1R;
60195             drflac_uint32 temp2R;
60196             drflac_uint32 temp3R;
60197             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60198             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60199             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60200             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60201             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60202             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60203             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60204             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60205             mid0 = (mid0 << 1) | (side0 & 0x01);
60206             mid1 = (mid1 << 1) | (side1 & 0x01);
60207             mid2 = (mid2 << 1) | (side2 & 0x01);
60208             mid3 = (mid3 << 1) | (side3 & 0x01);
60209             temp0L = (mid0 + side0) << shift;
60210             temp1L = (mid1 + side1) << shift;
60211             temp2L = (mid2 + side2) << shift;
60212             temp3L = (mid3 + side3) << shift;
60213             temp0R = (mid0 - side0) << shift;
60214             temp1R = (mid1 - side1) << shift;
60215             temp2R = (mid2 - side2) << shift;
60216             temp3R = (mid3 - side3) << shift;
60217             pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
60218             pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
60219             pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
60220             pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
60221             pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
60222             pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
60223             pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
60224             pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
60225         }
60226     } else {
60227         for (i = 0; i < frameCount4; ++i) {
60228             drflac_uint32 temp0L;
60229             drflac_uint32 temp1L;
60230             drflac_uint32 temp2L;
60231             drflac_uint32 temp3L;
60232             drflac_uint32 temp0R;
60233             drflac_uint32 temp1R;
60234             drflac_uint32 temp2R;
60235             drflac_uint32 temp3R;
60236             drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60237             drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60238             drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60239             drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60240             drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60241             drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60242             drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60243             drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60244             mid0 = (mid0 << 1) | (side0 & 0x01);
60245             mid1 = (mid1 << 1) | (side1 & 0x01);
60246             mid2 = (mid2 << 1) | (side2 & 0x01);
60247             mid3 = (mid3 << 1) | (side3 & 0x01);
60248             temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
60249             temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
60250             temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
60251             temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
60252             temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
60253             temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
60254             temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
60255             temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
60256             pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
60257             pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
60258             pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
60259             pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
60260             pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
60261             pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
60262             pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
60263             pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
60264         }
60265     }
60266     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60267         drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60268         drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60269         mid = (mid << 1) | (side & 0x01);
60270         pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor;
60271         pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor;
60272     }
60273 }
60274 #if defined(DRFLAC_SUPPORT_SSE2)
60275 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)
60276 {
60277     drflac_uint64 i;
60278     drflac_uint64 frameCount4 = frameCount >> 2;
60279     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60280     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60281     drflac_uint32 shift = unusedBitsPerSample - 8;
60282     float factor;
60283     __m128 factor128;
60284     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
60285     factor = 1.0f / 8388608.0f;
60286     factor128 = _mm_set1_ps(factor);
60287     if (shift == 0) {
60288         for (i = 0; i < frameCount4; ++i) {
60289             __m128i mid;
60290             __m128i side;
60291             __m128i tempL;
60292             __m128i tempR;
60293             __m128  leftf;
60294             __m128  rightf;
60295             mid    = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
60296             side   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
60297             mid    = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
60298             tempL  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
60299             tempR  = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
60300             leftf  = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
60301             rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
60302             _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
60303             _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
60304         }
60305         for (i = (frameCount4 << 2); i < frameCount; ++i) {
60306             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60307             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60308             mid = (mid << 1) | (side & 0x01);
60309             pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
60310             pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
60311         }
60312     } else {
60313         shift -= 1;
60314         for (i = 0; i < frameCount4; ++i) {
60315             __m128i mid;
60316             __m128i side;
60317             __m128i tempL;
60318             __m128i tempR;
60319             __m128 leftf;
60320             __m128 rightf;
60321             mid    = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
60322             side   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
60323             mid    = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
60324             tempL  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
60325             tempR  = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
60326             leftf  = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
60327             rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
60328             _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
60329             _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
60330         }
60331         for (i = (frameCount4 << 2); i < frameCount; ++i) {
60332             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60333             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60334             mid = (mid << 1) | (side & 0x01);
60335             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
60336             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
60337         }
60338     }
60339 }
60340 #endif
60341 #if defined(DRFLAC_SUPPORT_NEON)
60342 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)
60343 {
60344     drflac_uint64 i;
60345     drflac_uint64 frameCount4 = frameCount >> 2;
60346     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60347     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60348     drflac_uint32 shift = unusedBitsPerSample - 8;
60349     float factor;
60350     float32x4_t factor4;
60351     int32x4_t shift4;
60352     int32x4_t wbps0_4;
60353     int32x4_t wbps1_4;
60354     DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
60355     factor  = 1.0f / 8388608.0f;
60356     factor4 = vdupq_n_f32(factor);
60357     wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
60358     wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
60359     if (shift == 0) {
60360         for (i = 0; i < frameCount4; ++i) {
60361             int32x4_t lefti;
60362             int32x4_t righti;
60363             float32x4_t leftf;
60364             float32x4_t rightf;
60365             uint32x4_t mid  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
60366             uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
60367             mid    = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
60368             lefti  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
60369             righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
60370             leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
60371             rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
60372             drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
60373         }
60374         for (i = (frameCount4 << 2); i < frameCount; ++i) {
60375             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60376             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60377             mid = (mid << 1) | (side & 0x01);
60378             pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
60379             pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
60380         }
60381     } else {
60382         shift -= 1;
60383         shift4 = vdupq_n_s32(shift);
60384         for (i = 0; i < frameCount4; ++i) {
60385             uint32x4_t mid;
60386             uint32x4_t side;
60387             int32x4_t lefti;
60388             int32x4_t righti;
60389             float32x4_t leftf;
60390             float32x4_t rightf;
60391             mid    = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
60392             side   = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
60393             mid    = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
60394             lefti  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
60395             righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
60396             leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
60397             rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
60398             drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
60399         }
60400         for (i = (frameCount4 << 2); i < frameCount; ++i) {
60401             drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60402             drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60403             mid = (mid << 1) | (side & 0x01);
60404             pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
60405             pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
60406         }
60407     }
60408 }
60409 #endif
60410 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)
60411 {
60412 #if defined(DRFLAC_SUPPORT_SSE2)
60413     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
60414         drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60415     } else
60416 #elif defined(DRFLAC_SUPPORT_NEON)
60417     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
60418         drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60419     } else
60420 #endif
60421     {
60422 #if 0
60423         drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60424 #else
60425         drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60426 #endif
60427     }
60428 }
60429 #if 0
60430 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)
60431 {
60432     for (drflac_uint64 i = 0; i < frameCount; ++i) {
60433         pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0);
60434         pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0);
60435     }
60436 }
60437 #endif
60438 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)
60439 {
60440     drflac_uint64 i;
60441     drflac_uint64 frameCount4 = frameCount >> 2;
60442     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60443     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60444     drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
60445     drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
60446     float factor = 1 / 2147483648.0;
60447     for (i = 0; i < frameCount4; ++i) {
60448         drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
60449         drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
60450         drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
60451         drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
60452         drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
60453         drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
60454         drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
60455         drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
60456         pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor;
60457         pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor;
60458         pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor;
60459         pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor;
60460         pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor;
60461         pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor;
60462         pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor;
60463         pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor;
60464     }
60465     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60466         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
60467         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
60468     }
60469 }
60470 #if defined(DRFLAC_SUPPORT_SSE2)
60471 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)
60472 {
60473     drflac_uint64 i;
60474     drflac_uint64 frameCount4 = frameCount >> 2;
60475     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60476     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60477     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
60478     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
60479     float factor = 1.0f / 8388608.0f;
60480     __m128 factor128 = _mm_set1_ps(factor);
60481     for (i = 0; i < frameCount4; ++i) {
60482         __m128i lefti;
60483         __m128i righti;
60484         __m128 leftf;
60485         __m128 rightf;
60486         lefti  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
60487         righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
60488         leftf  = _mm_mul_ps(_mm_cvtepi32_ps(lefti),  factor128);
60489         rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128);
60490         _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
60491         _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
60492     }
60493     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60494         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
60495         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
60496     }
60497 }
60498 #endif
60499 #if defined(DRFLAC_SUPPORT_NEON)
60500 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)
60501 {
60502     drflac_uint64 i;
60503     drflac_uint64 frameCount4 = frameCount >> 2;
60504     const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
60505     const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
60506     drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
60507     drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
60508     float factor = 1.0f / 8388608.0f;
60509     float32x4_t factor4 = vdupq_n_f32(factor);
60510     int32x4_t shift0_4  = vdupq_n_s32(shift0);
60511     int32x4_t shift1_4  = vdupq_n_s32(shift1);
60512     for (i = 0; i < frameCount4; ++i) {
60513         int32x4_t lefti;
60514         int32x4_t righti;
60515         float32x4_t leftf;
60516         float32x4_t rightf;
60517         lefti  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
60518         righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
60519         leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
60520         rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
60521         drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
60522     }
60523     for (i = (frameCount4 << 2); i < frameCount; ++i) {
60524         pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
60525         pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
60526     }
60527 }
60528 #endif
60529 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)
60530 {
60531 #if defined(DRFLAC_SUPPORT_SSE2)
60532     if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
60533         drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60534     } else
60535 #elif defined(DRFLAC_SUPPORT_NEON)
60536     if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
60537         drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60538     } else
60539 #endif
60540     {
60541 #if 0
60542         drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60543 #else
60544         drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
60545 #endif
60546     }
60547 }
60548 DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut)
60549 {
60550     drflac_uint64 framesRead;
60551     drflac_uint32 unusedBitsPerSample;
60552     if (pFlac == NULL || framesToRead == 0) {
60553         return 0;
60554     }
60555     if (pBufferOut == NULL) {
60556         return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
60557     }
60558     DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
60559     unusedBitsPerSample = 32 - pFlac->bitsPerSample;
60560     framesRead = 0;
60561     while (framesToRead > 0) {
60562         if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
60563             if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
60564                 break;
60565             }
60566         } else {
60567             unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
60568             drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
60569             drflac_uint64 frameCountThisIteration = framesToRead;
60570             if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
60571                 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
60572             }
60573             if (channelCount == 2) {
60574                 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
60575                 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
60576                 switch (pFlac->currentFLACFrame.header.channelAssignment)
60577                 {
60578                     case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
60579                     {
60580                         drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
60581                     } break;
60582                     case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
60583                     {
60584                         drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
60585                     } break;
60586                     case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
60587                     {
60588                         drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
60589                     } break;
60590                     case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
60591                     default:
60592                     {
60593                         drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
60594                     } break;
60595                 }
60596             } else {
60597                 drflac_uint64 i;
60598                 for (i = 0; i < frameCountThisIteration; ++i) {
60599                     unsigned int j;
60600                     for (j = 0; j < channelCount; ++j) {
60601                         drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
60602                         pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0);
60603                     }
60604                 }
60605             }
60606             framesRead                += frameCountThisIteration;
60607             pBufferOut                += frameCountThisIteration * channelCount;
60608             framesToRead              -= frameCountThisIteration;
60609             pFlac->currentPCMFrame    += frameCountThisIteration;
60610             pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration;
60611         }
60612     }
60613     return framesRead;
60614 }
60615 DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
60616 {
60617     if (pFlac == NULL) {
60618         return DRFLAC_FALSE;
60619     }
60620     if (pFlac->currentPCMFrame == pcmFrameIndex) {
60621         return DRFLAC_TRUE;
60622     }
60623     if (pFlac->firstFLACFramePosInBytes == 0) {
60624         return DRFLAC_FALSE;
60625     }
60626     if (pcmFrameIndex == 0) {
60627         pFlac->currentPCMFrame = 0;
60628         return drflac__seek_to_first_frame(pFlac);
60629     } else {
60630         drflac_bool32 wasSuccessful = DRFLAC_FALSE;
60631         drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame;
60632         if (pcmFrameIndex > pFlac->totalPCMFrameCount) {
60633             pcmFrameIndex = pFlac->totalPCMFrameCount;
60634         }
60635         if (pcmFrameIndex > pFlac->currentPCMFrame) {
60636             drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame);
60637             if (pFlac->currentFLACFrame.pcmFramesRemaining >  offset) {
60638                 pFlac->currentFLACFrame.pcmFramesRemaining -= offset;
60639                 pFlac->currentPCMFrame = pcmFrameIndex;
60640                 return DRFLAC_TRUE;
60641             }
60642         } else {
60643             drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex);
60644             drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
60645             drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining;
60646             if (currentFLACFramePCMFramesConsumed > offsetAbs) {
60647                 pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs;
60648                 pFlac->currentPCMFrame = pcmFrameIndex;
60649                 return DRFLAC_TRUE;
60650             }
60651         }
60652 #ifndef DR_FLAC_NO_OGG
60653         if (pFlac->container == drflac_container_ogg)
60654         {
60655             wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex);
60656         }
60657         else
60658 #endif
60659         {
60660             if (!pFlac->_noSeekTableSeek) {
60661                 wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex);
60662             }
60663 #if !defined(DR_FLAC_NO_CRC)
60664             if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) {
60665                 wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex);
60666             }
60667 #endif
60668             if (!wasSuccessful && !pFlac->_noBruteForceSeek) {
60669                 wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex);
60670             }
60671         }
60672         if (wasSuccessful) {
60673             pFlac->currentPCMFrame = pcmFrameIndex;
60674         } else {
60675             if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) {
60676                 drflac_seek_to_pcm_frame(pFlac, 0);
60677             }
60678         }
60679         return wasSuccessful;
60680     }
60681 }
60682 #if defined(SIZE_MAX)
60683     #define DRFLAC_SIZE_MAX  SIZE_MAX
60684 #else
60685     #if defined(DRFLAC_64BIT)
60686         #define DRFLAC_SIZE_MAX  ((drflac_uint64)0xFFFFFFFFFFFFFFFF)
60687     #else
60688         #define DRFLAC_SIZE_MAX  0xFFFFFFFF
60689     #endif
60690 #endif
60691 #define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \
60692 static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\
60693 {                                                                                                                                                                   \
60694     type* pSampleData = NULL;                                                                                                                                       \
60695     drflac_uint64 totalPCMFrameCount;                                                                                                                               \
60696                                                                                                                                                                     \
60697     DRFLAC_ASSERT(pFlac != NULL);                                                                                                                                   \
60698                                                                                                                                                                     \
60699     totalPCMFrameCount = pFlac->totalPCMFrameCount;                                                                                                                 \
60700                                                                                                                                                                     \
60701     if (totalPCMFrameCount == 0) {                                                                                                                                  \
60702         type buffer[4096];                                                                                                                                          \
60703         drflac_uint64 pcmFramesRead;                                                                                                                                \
60704         size_t sampleDataBufferSize = sizeof(buffer);                                                                                                               \
60705                                                                                                                                                                     \
60706         pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks);                                                      \
60707         if (pSampleData == NULL) {                                                                                                                                  \
60708             goto on_error;                                                                                                                                          \
60709         }                                                                                                                                                           \
60710                                                                                                                                                                     \
60711         while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) {          \
60712             if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) {                                                   \
60713                 type* pNewSampleData;                                                                                                                               \
60714                 size_t newSampleDataBufferSize;                                                                                                                     \
60715                                                                                                                                                                     \
60716                 newSampleDataBufferSize = sampleDataBufferSize * 2;                                                                                                 \
60717                 pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks);    \
60718                 if (pNewSampleData == NULL) {                                                                                                                       \
60719                     drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks);                                                                          \
60720                     goto on_error;                                                                                                                                  \
60721                 }                                                                                                                                                   \
60722                                                                                                                                                                     \
60723                 sampleDataBufferSize = newSampleDataBufferSize;                                                                                                     \
60724                 pSampleData = pNewSampleData;                                                                                                                       \
60725             }                                                                                                                                                       \
60726                                                                                                                                                                     \
60727             DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type)));                   \
60728             totalPCMFrameCount += pcmFramesRead;                                                                                                                    \
60729         }                                                                                                                                                           \
60730                                                                                                                                                                     \
60731                                                                                                                          \
60732         DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type)));   \
60733     } else {                                                                                                                                                        \
60734         drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type);                                                                                   \
60735         if (dataSize > DRFLAC_SIZE_MAX) {                                                                                                                           \
60736             goto on_error;                                                                                                        \
60737         }                                                                                                                                                           \
60738                                                                                                                                                                     \
60739         pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks);               \
60740         if (pSampleData == NULL) {                                                                                                                                  \
60741             goto on_error;                                                                                                                                          \
60742         }                                                                                                                                                           \
60743                                                                                                                                                                     \
60744         totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData);                                                     \
60745     }                                                                                                                                                               \
60746                                                                                                                                                                     \
60747     if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;                                                                                                          \
60748     if (channelsOut) *channelsOut = pFlac->channels;                                                                                                                \
60749     if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount;                                                                                         \
60750                                                                                                                                                                     \
60751     drflac_close(pFlac);                                                                                                                                            \
60752     return pSampleData;                                                                                                                                             \
60753                                                                                                                                                                     \
60754 on_error:                                                                                                                                                           \
60755     drflac_close(pFlac);                                                                                                                                            \
60756     return NULL;                                                                                                                                                    \
60757 }
60758 DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
60759 DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
60760 DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
60761 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)
60762 {
60763     drflac* pFlac;
60764     if (channelsOut) {
60765         *channelsOut = 0;
60766     }
60767     if (sampleRateOut) {
60768         *sampleRateOut = 0;
60769     }
60770     if (totalPCMFrameCountOut) {
60771         *totalPCMFrameCountOut = 0;
60772     }
60773     pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
60774     if (pFlac == NULL) {
60775         return NULL;
60776     }
60777     return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
60778 }
60779 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)
60780 {
60781     drflac* pFlac;
60782     if (channelsOut) {
60783         *channelsOut = 0;
60784     }
60785     if (sampleRateOut) {
60786         *sampleRateOut = 0;
60787     }
60788     if (totalPCMFrameCountOut) {
60789         *totalPCMFrameCountOut = 0;
60790     }
60791     pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
60792     if (pFlac == NULL) {
60793         return NULL;
60794     }
60795     return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
60796 }
60797 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)
60798 {
60799     drflac* pFlac;
60800     if (channelsOut) {
60801         *channelsOut = 0;
60802     }
60803     if (sampleRateOut) {
60804         *sampleRateOut = 0;
60805     }
60806     if (totalPCMFrameCountOut) {
60807         *totalPCMFrameCountOut = 0;
60808     }
60809     pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
60810     if (pFlac == NULL) {
60811         return NULL;
60812     }
60813     return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
60814 }
60815 #ifndef DR_FLAC_NO_STDIO
60816 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)
60817 {
60818     drflac* pFlac;
60819     if (sampleRate) {
60820         *sampleRate = 0;
60821     }
60822     if (channels) {
60823         *channels = 0;
60824     }
60825     if (totalPCMFrameCount) {
60826         *totalPCMFrameCount = 0;
60827     }
60828     pFlac = drflac_open_file(filename, pAllocationCallbacks);
60829     if (pFlac == NULL) {
60830         return NULL;
60831     }
60832     return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
60833 }
60834 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)
60835 {
60836     drflac* pFlac;
60837     if (sampleRate) {
60838         *sampleRate = 0;
60839     }
60840     if (channels) {
60841         *channels = 0;
60842     }
60843     if (totalPCMFrameCount) {
60844         *totalPCMFrameCount = 0;
60845     }
60846     pFlac = drflac_open_file(filename, pAllocationCallbacks);
60847     if (pFlac == NULL) {
60848         return NULL;
60849     }
60850     return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
60851 }
60852 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)
60853 {
60854     drflac* pFlac;
60855     if (sampleRate) {
60856         *sampleRate = 0;
60857     }
60858     if (channels) {
60859         *channels = 0;
60860     }
60861     if (totalPCMFrameCount) {
60862         *totalPCMFrameCount = 0;
60863     }
60864     pFlac = drflac_open_file(filename, pAllocationCallbacks);
60865     if (pFlac == NULL) {
60866         return NULL;
60867     }
60868     return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
60869 }
60870 #endif
60871 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)
60872 {
60873     drflac* pFlac;
60874     if (sampleRate) {
60875         *sampleRate = 0;
60876     }
60877     if (channels) {
60878         *channels = 0;
60879     }
60880     if (totalPCMFrameCount) {
60881         *totalPCMFrameCount = 0;
60882     }
60883     pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
60884     if (pFlac == NULL) {
60885         return NULL;
60886     }
60887     return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
60888 }
60889 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)
60890 {
60891     drflac* pFlac;
60892     if (sampleRate) {
60893         *sampleRate = 0;
60894     }
60895     if (channels) {
60896         *channels = 0;
60897     }
60898     if (totalPCMFrameCount) {
60899         *totalPCMFrameCount = 0;
60900     }
60901     pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
60902     if (pFlac == NULL) {
60903         return NULL;
60904     }
60905     return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
60906 }
60907 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)
60908 {
60909     drflac* pFlac;
60910     if (sampleRate) {
60911         *sampleRate = 0;
60912     }
60913     if (channels) {
60914         *channels = 0;
60915     }
60916     if (totalPCMFrameCount) {
60917         *totalPCMFrameCount = 0;
60918     }
60919     pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
60920     if (pFlac == NULL) {
60921         return NULL;
60922     }
60923     return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
60924 }
60925 DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
60926 {
60927     if (pAllocationCallbacks != NULL) {
60928         drflac__free_from_callbacks(p, pAllocationCallbacks);
60929     } else {
60930         drflac__free_default(p, NULL);
60931     }
60932 }
60933 DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments)
60934 {
60935     if (pIter == NULL) {
60936         return;
60937     }
60938     pIter->countRemaining = commentCount;
60939     pIter->pRunningData   = (const char*)pComments;
60940 }
60941 DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut)
60942 {
60943     drflac_int32 length;
60944     const char* pComment;
60945     if (pCommentLengthOut) {
60946         *pCommentLengthOut = 0;
60947     }
60948     if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
60949         return NULL;
60950     }
60951     length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData);
60952     pIter->pRunningData += 4;
60953     pComment = pIter->pRunningData;
60954     pIter->pRunningData += length;
60955     pIter->countRemaining -= 1;
60956     if (pCommentLengthOut) {
60957         *pCommentLengthOut = length;
60958     }
60959     return pComment;
60960 }
60961 DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData)
60962 {
60963     if (pIter == NULL) {
60964         return;
60965     }
60966     pIter->countRemaining = trackCount;
60967     pIter->pRunningData   = (const char*)pTrackData;
60968 }
60969 DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack)
60970 {
60971     drflac_cuesheet_track cuesheetTrack;
60972     const char* pRunningData;
60973     drflac_uint64 offsetHi;
60974     drflac_uint64 offsetLo;
60975     if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
60976         return DRFLAC_FALSE;
60977     }
60978     pRunningData = pIter->pRunningData;
60979     offsetHi                   = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
60980     offsetLo                   = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
60981     cuesheetTrack.offset       = offsetLo | (offsetHi << 32);
60982     cuesheetTrack.trackNumber  = pRunningData[0];                                         pRunningData += 1;
60983     DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC));     pRunningData += 12;
60984     cuesheetTrack.isAudio      = (pRunningData[0] & 0x80) != 0;
60985     cuesheetTrack.preEmphasis  = (pRunningData[0] & 0x40) != 0;                           pRunningData += 14;
60986     cuesheetTrack.indexCount   = pRunningData[0];                                         pRunningData += 1;
60987     cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData;        pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index);
60988     pIter->pRunningData = pRunningData;
60989     pIter->countRemaining -= 1;
60990     if (pCuesheetTrack) {
60991         *pCuesheetTrack = cuesheetTrack;
60992     }
60993     return DRFLAC_TRUE;
60994 }
60995 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
60996     #pragma GCC diagnostic pop
60997 #endif
60998 #endif
60999 /* dr_flac_c end */
61000 #endif  /* DRFLAC_IMPLEMENTATION */
61001 #endif  /* MA_NO_FLAC */
61002
61003 #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING)
61004 #if !defined(DR_MP3_IMPLEMENTATION) && !defined(DRMP3_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */
61005 /* dr_mp3_c begin */
61006 #ifndef dr_mp3_c
61007 #define dr_mp3_c
61008 #include <stdlib.h>
61009 #include <string.h>
61010 #include <limits.h>
61011 DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision)
61012 {
61013     if (pMajor) {
61014         *pMajor = DRMP3_VERSION_MAJOR;
61015     }
61016     if (pMinor) {
61017         *pMinor = DRMP3_VERSION_MINOR;
61018     }
61019     if (pRevision) {
61020         *pRevision = DRMP3_VERSION_REVISION;
61021     }
61022 }
61023 DRMP3_API const char* drmp3_version_string(void)
61024 {
61025     return DRMP3_VERSION_STRING;
61026 }
61027 #if defined(__TINYC__)
61028 #define DR_MP3_NO_SIMD
61029 #endif
61030 #define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset)))
61031 #define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE  2304
61032 #ifndef DRMP3_MAX_FRAME_SYNC_MATCHES
61033 #define DRMP3_MAX_FRAME_SYNC_MATCHES      10
61034 #endif
61035 #define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES  DRMP3_MAX_FREE_FORMAT_FRAME_SIZE
61036 #define DRMP3_MAX_BITRESERVOIR_BYTES      511
61037 #define DRMP3_SHORT_BLOCK_TYPE            2
61038 #define DRMP3_STOP_BLOCK_TYPE             3
61039 #define DRMP3_MODE_MONO                   3
61040 #define DRMP3_MODE_JOINT_STEREO           1
61041 #define DRMP3_HDR_SIZE                    4
61042 #define DRMP3_HDR_IS_MONO(h)              (((h[3]) & 0xC0) == 0xC0)
61043 #define DRMP3_HDR_IS_MS_STEREO(h)         (((h[3]) & 0xE0) == 0x60)
61044 #define DRMP3_HDR_IS_FREE_FORMAT(h)       (((h[2]) & 0xF0) == 0)
61045 #define DRMP3_HDR_IS_CRC(h)               (!((h[1]) & 1))
61046 #define DRMP3_HDR_TEST_PADDING(h)         ((h[2]) & 0x2)
61047 #define DRMP3_HDR_TEST_MPEG1(h)           ((h[1]) & 0x8)
61048 #define DRMP3_HDR_TEST_NOT_MPEG25(h)      ((h[1]) & 0x10)
61049 #define DRMP3_HDR_TEST_I_STEREO(h)        ((h[3]) & 0x10)
61050 #define DRMP3_HDR_TEST_MS_STEREO(h)       ((h[3]) & 0x20)
61051 #define DRMP3_HDR_GET_STEREO_MODE(h)      (((h[3]) >> 6) & 3)
61052 #define DRMP3_HDR_GET_STEREO_MODE_EXT(h)  (((h[3]) >> 4) & 3)
61053 #define DRMP3_HDR_GET_LAYER(h)            (((h[1]) >> 1) & 3)
61054 #define DRMP3_HDR_GET_BITRATE(h)          ((h[2]) >> 4)
61055 #define DRMP3_HDR_GET_SAMPLE_RATE(h)      (((h[2]) >> 2) & 3)
61056 #define DRMP3_HDR_GET_MY_SAMPLE_RATE(h)   (DRMP3_HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3)
61057 #define DRMP3_HDR_IS_FRAME_576(h)         ((h[1] & 14) == 2)
61058 #define DRMP3_HDR_IS_LAYER_1(h)           ((h[1] & 6) == 6)
61059 #define DRMP3_BITS_DEQUANTIZER_OUT        -1
61060 #define DRMP3_MAX_SCF                     (255 + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210)
61061 #define DRMP3_MAX_SCFI                    ((DRMP3_MAX_SCF + 3) & ~3)
61062 #define DRMP3_MIN(a, b)           ((a) > (b) ? (b) : (a))
61063 #define DRMP3_MAX(a, b)           ((a) < (b) ? (b) : (a))
61064 #if !defined(DR_MP3_NO_SIMD)
61065 #if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64))
61066 #define DR_MP3_ONLY_SIMD
61067 #endif
61068 #if ((defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__))
61069 #if defined(_MSC_VER)
61070 #include <intrin.h>
61071 #endif
61072 #include <emmintrin.h>
61073 #define DRMP3_HAVE_SSE 1
61074 #define DRMP3_HAVE_SIMD 1
61075 #define DRMP3_VSTORE _mm_storeu_ps
61076 #define DRMP3_VLD _mm_loadu_ps
61077 #define DRMP3_VSET _mm_set1_ps
61078 #define DRMP3_VADD _mm_add_ps
61079 #define DRMP3_VSUB _mm_sub_ps
61080 #define DRMP3_VMUL _mm_mul_ps
61081 #define DRMP3_VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y))
61082 #define DRMP3_VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y))
61083 #define DRMP3_VMUL_S(x, s)  _mm_mul_ps(x, _mm_set1_ps(s))
61084 #define DRMP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3))
61085 typedef __m128 drmp3_f4;
61086 #if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)
61087 #define drmp3_cpuid __cpuid
61088 #else
61089 static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType)
61090 {
61091 #if defined(__PIC__)
61092     __asm__ __volatile__(
61093 #if defined(__x86_64__)
61094         "push %%rbx\n"
61095         "cpuid\n"
61096         "xchgl %%ebx, %1\n"
61097         "pop  %%rbx\n"
61098 #else
61099         "xchgl %%ebx, %1\n"
61100         "cpuid\n"
61101         "xchgl %%ebx, %1\n"
61102 #endif
61103         : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
61104         : "a" (InfoType));
61105 #else
61106     __asm__ __volatile__(
61107         "cpuid"
61108         : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
61109         : "a" (InfoType));
61110 #endif
61111 }
61112 #endif
61113 static int drmp3_have_simd(void)
61114 {
61115 #ifdef DR_MP3_ONLY_SIMD
61116     return 1;
61117 #else
61118     static int g_have_simd;
61119     int CPUInfo[4];
61120 #ifdef MINIMP3_TEST
61121     static int g_counter;
61122     if (g_counter++ > 100)
61123         return 0;
61124 #endif
61125     if (g_have_simd)
61126         goto end;
61127     drmp3_cpuid(CPUInfo, 0);
61128     if (CPUInfo[0] > 0)
61129     {
61130         drmp3_cpuid(CPUInfo, 1);
61131         g_have_simd = (CPUInfo[3] & (1 << 26)) + 1;
61132         return g_have_simd - 1;
61133     }
61134 end:
61135     return g_have_simd - 1;
61136 #endif
61137 }
61138 #elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)
61139 #include <arm_neon.h>
61140 #define DRMP3_HAVE_SSE 0
61141 #define DRMP3_HAVE_SIMD 1
61142 #define DRMP3_VSTORE vst1q_f32
61143 #define DRMP3_VLD vld1q_f32
61144 #define DRMP3_VSET vmovq_n_f32
61145 #define DRMP3_VADD vaddq_f32
61146 #define DRMP3_VSUB vsubq_f32
61147 #define DRMP3_VMUL vmulq_f32
61148 #define DRMP3_VMAC(a, x, y) vmlaq_f32(a, x, y)
61149 #define DRMP3_VMSB(a, x, y) vmlsq_f32(a, x, y)
61150 #define DRMP3_VMUL_S(x, s)  vmulq_f32(x, vmovq_n_f32(s))
61151 #define DRMP3_VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x)))
61152 typedef float32x4_t drmp3_f4;
61153 static int drmp3_have_simd(void)
61154 {
61155     return 1;
61156 }
61157 #else
61158 #define DRMP3_HAVE_SSE 0
61159 #define DRMP3_HAVE_SIMD 0
61160 #ifdef DR_MP3_ONLY_SIMD
61161 #error DR_MP3_ONLY_SIMD used, but SSE/NEON not enabled
61162 #endif
61163 #endif
61164 #else
61165 #define DRMP3_HAVE_SIMD 0
61166 #endif
61167 #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64)
61168 #define DRMP3_HAVE_ARMV6 1
61169 static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(int32_t a)
61170 {
61171     drmp3_int32 x = 0;
61172     __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a));
61173     return x;
61174 }
61175 #else
61176 #define DRMP3_HAVE_ARMV6 0
61177 #endif
61178 typedef struct
61179 {
61180     const drmp3_uint8 *buf;
61181     int pos, limit;
61182 } drmp3_bs;
61183 typedef struct
61184 {
61185     float scf[3*64];
61186     drmp3_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64];
61187 } drmp3_L12_scale_info;
61188 typedef struct
61189 {
61190     drmp3_uint8 tab_offset, code_tab_width, band_count;
61191 } drmp3_L12_subband_alloc;
61192 typedef struct
61193 {
61194     const drmp3_uint8 *sfbtab;
61195     drmp3_uint16 part_23_length, big_values, scalefac_compress;
61196     drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb;
61197     drmp3_uint8 table_select[3], region_count[3], subblock_gain[3];
61198     drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi;
61199 } drmp3_L3_gr_info;
61200 typedef struct
61201 {
61202     drmp3_bs bs;
61203     drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES];
61204     drmp3_L3_gr_info gr_info[4];
61205     float grbuf[2][576], scf[40], syn[18 + 15][2*32];
61206     drmp3_uint8 ist_pos[2][39];
61207 } drmp3dec_scratch;
61208 static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes)
61209 {
61210     bs->buf   = data;
61211     bs->pos   = 0;
61212     bs->limit = bytes*8;
61213 }
61214 static drmp3_uint32 drmp3_bs_get_bits(drmp3_bs *bs, int n)
61215 {
61216     drmp3_uint32 next, cache = 0, s = bs->pos & 7;
61217     int shl = n + s;
61218     const drmp3_uint8 *p = bs->buf + (bs->pos >> 3);
61219     if ((bs->pos += n) > bs->limit)
61220         return 0;
61221     next = *p++ & (255 >> s);
61222     while ((shl -= 8) > 0)
61223     {
61224         cache |= next << shl;
61225         next = *p++;
61226     }
61227     return cache | (next >> -shl);
61228 }
61229 static int drmp3_hdr_valid(const drmp3_uint8 *h)
61230 {
61231     return h[0] == 0xff &&
61232         ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) &&
61233         (DRMP3_HDR_GET_LAYER(h) != 0) &&
61234         (DRMP3_HDR_GET_BITRATE(h) != 15) &&
61235         (DRMP3_HDR_GET_SAMPLE_RATE(h) != 3);
61236 }
61237 static int drmp3_hdr_compare(const drmp3_uint8 *h1, const drmp3_uint8 *h2)
61238 {
61239     return drmp3_hdr_valid(h2) &&
61240         ((h1[1] ^ h2[1]) & 0xFE) == 0 &&
61241         ((h1[2] ^ h2[2]) & 0x0C) == 0 &&
61242         !(DRMP3_HDR_IS_FREE_FORMAT(h1) ^ DRMP3_HDR_IS_FREE_FORMAT(h2));
61243 }
61244 static unsigned drmp3_hdr_bitrate_kbps(const drmp3_uint8 *h)
61245 {
61246     static const drmp3_uint8 halfrate[2][3][15] = {
61247         { { 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 } },
61248         { { 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 } },
61249     };
61250     return 2*halfrate[!!DRMP3_HDR_TEST_MPEG1(h)][DRMP3_HDR_GET_LAYER(h) - 1][DRMP3_HDR_GET_BITRATE(h)];
61251 }
61252 static unsigned drmp3_hdr_sample_rate_hz(const drmp3_uint8 *h)
61253 {
61254     static const unsigned g_hz[3] = { 44100, 48000, 32000 };
61255     return g_hz[DRMP3_HDR_GET_SAMPLE_RATE(h)] >> (int)!DRMP3_HDR_TEST_MPEG1(h) >> (int)!DRMP3_HDR_TEST_NOT_MPEG25(h);
61256 }
61257 static unsigned drmp3_hdr_frame_samples(const drmp3_uint8 *h)
61258 {
61259     return DRMP3_HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)DRMP3_HDR_IS_FRAME_576(h));
61260 }
61261 static int drmp3_hdr_frame_bytes(const drmp3_uint8 *h, int free_format_size)
61262 {
61263     int frame_bytes = drmp3_hdr_frame_samples(h)*drmp3_hdr_bitrate_kbps(h)*125/drmp3_hdr_sample_rate_hz(h);
61264     if (DRMP3_HDR_IS_LAYER_1(h))
61265     {
61266         frame_bytes &= ~3;
61267     }
61268     return frame_bytes ? frame_bytes : free_format_size;
61269 }
61270 static int drmp3_hdr_padding(const drmp3_uint8 *h)
61271 {
61272     return DRMP3_HDR_TEST_PADDING(h) ? (DRMP3_HDR_IS_LAYER_1(h) ? 4 : 1) : 0;
61273 }
61274 #ifndef DR_MP3_ONLY_MP3
61275 static const drmp3_L12_subband_alloc *drmp3_L12_subband_alloc_table(const drmp3_uint8 *hdr, drmp3_L12_scale_info *sci)
61276 {
61277     const drmp3_L12_subband_alloc *alloc;
61278     int mode = DRMP3_HDR_GET_STEREO_MODE(hdr);
61279     int nbands, stereo_bands = (mode == DRMP3_MODE_MONO) ? 0 : (mode == DRMP3_MODE_JOINT_STEREO) ? (DRMP3_HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32;
61280     if (DRMP3_HDR_IS_LAYER_1(hdr))
61281     {
61282         static const drmp3_L12_subband_alloc g_alloc_L1[] = { { 76, 4, 32 } };
61283         alloc = g_alloc_L1;
61284         nbands = 32;
61285     } else if (!DRMP3_HDR_TEST_MPEG1(hdr))
61286     {
61287         static const drmp3_L12_subband_alloc g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } };
61288         alloc = g_alloc_L2M2;
61289         nbands = 30;
61290     } else
61291     {
61292         static const drmp3_L12_subband_alloc g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } };
61293         int sample_rate_idx = DRMP3_HDR_GET_SAMPLE_RATE(hdr);
61294         unsigned kbps = drmp3_hdr_bitrate_kbps(hdr) >> (int)(mode != DRMP3_MODE_MONO);
61295         if (!kbps)
61296         {
61297             kbps = 192;
61298         }
61299         alloc = g_alloc_L2M1;
61300         nbands = 27;
61301         if (kbps < 56)
61302         {
61303             static const drmp3_L12_subband_alloc g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } };
61304             alloc = g_alloc_L2M1_lowrate;
61305             nbands = sample_rate_idx == 2 ? 12 : 8;
61306         } else if (kbps >= 96 && sample_rate_idx != 1)
61307         {
61308             nbands = 30;
61309         }
61310     }
61311     sci->total_bands = (drmp3_uint8)nbands;
61312     sci->stereo_bands = (drmp3_uint8)DRMP3_MIN(stereo_bands, nbands);
61313     return alloc;
61314 }
61315 static void drmp3_L12_read_scalefactors(drmp3_bs *bs, drmp3_uint8 *pba, drmp3_uint8 *scfcod, int bands, float *scf)
61316 {
61317     static const float g_deq_L12[18*3] = {
61318 #define DRMP3_DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x
61319         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)
61320     };
61321     int i, m;
61322     for (i = 0; i < bands; i++)
61323     {
61324         float s = 0;
61325         int ba = *pba++;
61326         int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0;
61327         for (m = 4; m; m >>= 1)
61328         {
61329             if (mask & m)
61330             {
61331                 int b = drmp3_bs_get_bits(bs, 6);
61332                 s = g_deq_L12[ba*3 - 6 + b % 3]*(int)(1 << 21 >> b/3);
61333             }
61334             *scf++ = s;
61335         }
61336     }
61337 }
61338 static void drmp3_L12_read_scale_info(const drmp3_uint8 *hdr, drmp3_bs *bs, drmp3_L12_scale_info *sci)
61339 {
61340     static const drmp3_uint8 g_bitalloc_code_tab[] = {
61341         0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16,
61342         0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16,
61343         0,17,18, 3,19,4,5,16,
61344         0,17,18,16,
61345         0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15,
61346         0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14,
61347         0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16
61348     };
61349     const drmp3_L12_subband_alloc *subband_alloc = drmp3_L12_subband_alloc_table(hdr, sci);
61350     int i, k = 0, ba_bits = 0;
61351     const drmp3_uint8 *ba_code_tab = g_bitalloc_code_tab;
61352     for (i = 0; i < sci->total_bands; i++)
61353     {
61354         drmp3_uint8 ba;
61355         if (i == k)
61356         {
61357             k += subband_alloc->band_count;
61358             ba_bits = subband_alloc->code_tab_width;
61359             ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset;
61360             subband_alloc++;
61361         }
61362         ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)];
61363         sci->bitalloc[2*i] = ba;
61364         if (i < sci->stereo_bands)
61365         {
61366             ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)];
61367         }
61368         sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0;
61369     }
61370     for (i = 0; i < 2*sci->total_bands; i++)
61371     {
61372         sci->scfcod[i] = (drmp3_uint8)(sci->bitalloc[i] ? DRMP3_HDR_IS_LAYER_1(hdr) ? 2 : drmp3_bs_get_bits(bs, 2) : 6);
61373     }
61374     drmp3_L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf);
61375     for (i = sci->stereo_bands; i < sci->total_bands; i++)
61376     {
61377         sci->bitalloc[2*i + 1] = 0;
61378     }
61379 }
61380 static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_scale_info *sci, int group_size)
61381 {
61382     int i, j, k, choff = 576;
61383     for (j = 0; j < 4; j++)
61384     {
61385         float *dst = grbuf + group_size*j;
61386         for (i = 0; i < 2*sci->total_bands; i++)
61387         {
61388             int ba = sci->bitalloc[i];
61389             if (ba != 0)
61390             {
61391                 if (ba < 17)
61392                 {
61393                     int half = (1 << (ba - 1)) - 1;
61394                     for (k = 0; k < group_size; k++)
61395                     {
61396                         dst[k] = (float)((int)drmp3_bs_get_bits(bs, ba) - half);
61397                     }
61398                 } else
61399                 {
61400                     unsigned mod = (2 << (ba - 17)) + 1;
61401                     unsigned code = drmp3_bs_get_bits(bs, mod + 2 - (mod >> 3));
61402                     for (k = 0; k < group_size; k++, code /= mod)
61403                     {
61404                         dst[k] = (float)((int)(code % mod - mod/2));
61405                     }
61406                 }
61407             }
61408             dst += choff;
61409             choff = 18 - choff;
61410         }
61411     }
61412     return group_size*4;
61413 }
61414 static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst)
61415 {
61416     int i, k;
61417     memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float));
61418     for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6)
61419     {
61420         for (k = 0; k < 12; k++)
61421         {
61422             dst[k + 0]   *= scf[0];
61423             dst[k + 576] *= scf[3];
61424         }
61425     }
61426 }
61427 #endif
61428 static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr)
61429 {
61430     static const drmp3_uint8 g_scf_long[8][23] = {
61431         { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
61432         { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 },
61433         { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
61434         { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 },
61435         { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
61436         { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 },
61437         { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 },
61438         { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 }
61439     };
61440     static const drmp3_uint8 g_scf_short[8][40] = {
61441         { 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 },
61442         { 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 },
61443         { 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 },
61444         { 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 },
61445         { 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 },
61446         { 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 },
61447         { 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 },
61448         { 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 }
61449     };
61450     static const drmp3_uint8 g_scf_mixed[8][40] = {
61451         { 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 },
61452         { 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 },
61453         { 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 },
61454         { 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 },
61455         { 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 },
61456         { 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 },
61457         { 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 },
61458         { 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 }
61459     };
61460     unsigned tables, scfsi = 0;
61461     int main_data_begin, part_23_sum = 0;
61462     int gr_count = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
61463     int sr_idx = DRMP3_HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0);
61464     if (DRMP3_HDR_TEST_MPEG1(hdr))
61465     {
61466         gr_count *= 2;
61467         main_data_begin = drmp3_bs_get_bits(bs, 9);
61468         scfsi = drmp3_bs_get_bits(bs, 7 + gr_count);
61469     } else
61470     {
61471         main_data_begin = drmp3_bs_get_bits(bs, 8 + gr_count) >> gr_count;
61472     }
61473     do
61474     {
61475         if (DRMP3_HDR_IS_MONO(hdr))
61476         {
61477             scfsi <<= 4;
61478         }
61479         gr->part_23_length = (drmp3_uint16)drmp3_bs_get_bits(bs, 12);
61480         part_23_sum += gr->part_23_length;
61481         gr->big_values = (drmp3_uint16)drmp3_bs_get_bits(bs,  9);
61482         if (gr->big_values > 288)
61483         {
61484             return -1;
61485         }
61486         gr->global_gain = (drmp3_uint8)drmp3_bs_get_bits(bs, 8);
61487         gr->scalefac_compress = (drmp3_uint16)drmp3_bs_get_bits(bs, DRMP3_HDR_TEST_MPEG1(hdr) ? 4 : 9);
61488         gr->sfbtab = g_scf_long[sr_idx];
61489         gr->n_long_sfb  = 22;
61490         gr->n_short_sfb = 0;
61491         if (drmp3_bs_get_bits(bs, 1))
61492         {
61493             gr->block_type = (drmp3_uint8)drmp3_bs_get_bits(bs, 2);
61494             if (!gr->block_type)
61495             {
61496                 return -1;
61497             }
61498             gr->mixed_block_flag = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
61499             gr->region_count[0] = 7;
61500             gr->region_count[1] = 255;
61501             if (gr->block_type == DRMP3_SHORT_BLOCK_TYPE)
61502             {
61503                 scfsi &= 0x0F0F;
61504                 if (!gr->mixed_block_flag)
61505                 {
61506                     gr->region_count[0] = 8;
61507                     gr->sfbtab = g_scf_short[sr_idx];
61508                     gr->n_long_sfb = 0;
61509                     gr->n_short_sfb = 39;
61510                 } else
61511                 {
61512                     gr->sfbtab = g_scf_mixed[sr_idx];
61513                     gr->n_long_sfb = DRMP3_HDR_TEST_MPEG1(hdr) ? 8 : 6;
61514                     gr->n_short_sfb = 30;
61515                 }
61516             }
61517             tables = drmp3_bs_get_bits(bs, 10);
61518             tables <<= 5;
61519             gr->subblock_gain[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
61520             gr->subblock_gain[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
61521             gr->subblock_gain[2] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
61522         } else
61523         {
61524             gr->block_type = 0;
61525             gr->mixed_block_flag = 0;
61526             tables = drmp3_bs_get_bits(bs, 15);
61527             gr->region_count[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 4);
61528             gr->region_count[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
61529             gr->region_count[2] = 255;
61530         }
61531         gr->table_select[0] = (drmp3_uint8)(tables >> 10);
61532         gr->table_select[1] = (drmp3_uint8)((tables >> 5) & 31);
61533         gr->table_select[2] = (drmp3_uint8)((tables) & 31);
61534         gr->preflag = (drmp3_uint8)(DRMP3_HDR_TEST_MPEG1(hdr) ? drmp3_bs_get_bits(bs, 1) : (gr->scalefac_compress >= 500));
61535         gr->scalefac_scale = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
61536         gr->count1_table = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
61537         gr->scfsi = (drmp3_uint8)((scfsi >> 12) & 15);
61538         scfsi <<= 4;
61539         gr++;
61540     } while(--gr_count);
61541     if (part_23_sum + bs->pos > bs->limit + main_data_begin*8)
61542     {
61543         return -1;
61544     }
61545     return main_data_begin;
61546 }
61547 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)
61548 {
61549     int i, k;
61550     for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2)
61551     {
61552         int cnt = scf_count[i];
61553         if (scfsi & 8)
61554         {
61555             memcpy(scf, ist_pos, cnt);
61556         } else
61557         {
61558             int bits = scf_size[i];
61559             if (!bits)
61560             {
61561                 memset(scf, 0, cnt);
61562                 memset(ist_pos, 0, cnt);
61563             } else
61564             {
61565                 int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1;
61566                 for (k = 0; k < cnt; k++)
61567                 {
61568                     int s = drmp3_bs_get_bits(bitbuf, bits);
61569                     ist_pos[k] = (drmp3_uint8)(s == max_scf ? -1 : s);
61570                     scf[k] = (drmp3_uint8)s;
61571                 }
61572             }
61573         }
61574         ist_pos += cnt;
61575         scf += cnt;
61576     }
61577     scf[0] = scf[1] = scf[2] = 0;
61578 }
61579 static float drmp3_L3_ldexp_q2(float y, int exp_q2)
61580 {
61581     static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f };
61582     int e;
61583     do
61584     {
61585         e = DRMP3_MIN(30*4, exp_q2);
61586         y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2));
61587     } while ((exp_q2 -= e) > 0);
61588     return y;
61589 }
61590 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)
61591 {
61592     static const drmp3_uint8 g_scf_partitions[3][28] = {
61593         { 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 },
61594         { 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 },
61595         { 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 }
61596     };
61597     const drmp3_uint8 *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb];
61598     drmp3_uint8 scf_size[4], iscf[40];
61599     int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi;
61600     float gain;
61601     if (DRMP3_HDR_TEST_MPEG1(hdr))
61602     {
61603         static const drmp3_uint8 g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 };
61604         int part = g_scfc_decode[gr->scalefac_compress];
61605         scf_size[1] = scf_size[0] = (drmp3_uint8)(part >> 2);
61606         scf_size[3] = scf_size[2] = (drmp3_uint8)(part & 3);
61607     } else
61608     {
61609         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 };
61610         int k, modprod, sfc, ist = DRMP3_HDR_TEST_I_STEREO(hdr) && ch;
61611         sfc = gr->scalefac_compress >> ist;
61612         for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4)
61613         {
61614             for (modprod = 1, i = 3; i >= 0; i--)
61615             {
61616                 scf_size[i] = (drmp3_uint8)(sfc / modprod % g_mod[k + i]);
61617                 modprod *= g_mod[k + i];
61618             }
61619         }
61620         scf_partition += k;
61621         scfsi = -16;
61622     }
61623     drmp3_L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi);
61624     if (gr->n_short_sfb)
61625     {
61626         int sh = 3 - scf_shift;
61627         for (i = 0; i < gr->n_short_sfb; i += 3)
61628         {
61629             iscf[gr->n_long_sfb + i + 0] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 0] + (gr->subblock_gain[0] << sh));
61630             iscf[gr->n_long_sfb + i + 1] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 1] + (gr->subblock_gain[1] << sh));
61631             iscf[gr->n_long_sfb + i + 2] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 2] + (gr->subblock_gain[2] << sh));
61632         }
61633     } else if (gr->preflag)
61634     {
61635         static const drmp3_uint8 g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 };
61636         for (i = 0; i < 10; i++)
61637         {
61638             iscf[11 + i] = (drmp3_uint8)(iscf[11 + i] + g_preamp[i]);
61639         }
61640     }
61641     gain_exp = gr->global_gain + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210 - (DRMP3_HDR_IS_MS_STEREO(hdr) ? 2 : 0);
61642     gain = drmp3_L3_ldexp_q2(1 << (DRMP3_MAX_SCFI/4),  DRMP3_MAX_SCFI - gain_exp);
61643     for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++)
61644     {
61645         scf[i] = drmp3_L3_ldexp_q2(gain, iscf[i] << scf_shift);
61646     }
61647 }
61648 static const float g_drmp3_pow43[129 + 16] = {
61649     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,
61650     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
61651 };
61652 static float drmp3_L3_pow_43(int x)
61653 {
61654     float frac;
61655     int sign, mult = 256;
61656     if (x < 129)
61657     {
61658         return g_drmp3_pow43[16 + x];
61659     }
61660     if (x < 1024)
61661     {
61662         mult = 16;
61663         x <<= 3;
61664     }
61665     sign = 2*x & 64;
61666     frac = (float)((x & 63) - sign) / ((x & ~63) + sign);
61667     return g_drmp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult;
61668 }
61669 static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit)
61670 {
61671     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,
61672         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,
61673         -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,
61674         -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,
61675         -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,
61676         -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,
61677         -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,
61678         -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,
61679         -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,
61680         -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,
61681         -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,
61682         -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,
61683         -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,
61684         -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,
61685         -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,
61686         -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 };
61687     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};
61688     static const drmp3_uint8 tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 };
61689     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 };
61690     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 };
61691 #define DRMP3_PEEK_BITS(n)    (bs_cache >> (32 - n))
61692 #define DRMP3_FLUSH_BITS(n)   { bs_cache <<= (n); bs_sh += (n); }
61693 #define DRMP3_CHECK_BITS      while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; }
61694 #define DRMP3_BSPOS           ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh)
61695     float one = 0.0f;
61696     int ireg = 0, big_val_cnt = gr_info->big_values;
61697     const drmp3_uint8 *sfb = gr_info->sfbtab;
61698     const drmp3_uint8 *bs_next_ptr = bs->buf + bs->pos/8;
61699     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);
61700     int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8;
61701     bs_next_ptr += 4;
61702     while (big_val_cnt > 0)
61703     {
61704         int tab_num = gr_info->table_select[ireg];
61705         int sfb_cnt = gr_info->region_count[ireg++];
61706         const drmp3_int16 *codebook = tabs + tabindex[tab_num];
61707         int linbits = g_linbits[tab_num];
61708         if (linbits)
61709         {
61710             do
61711             {
61712                 np = *sfb++ / 2;
61713                 pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
61714                 one = *scf++;
61715                 do
61716                 {
61717                     int j, w = 5;
61718                     int leaf = codebook[DRMP3_PEEK_BITS(w)];
61719                     while (leaf < 0)
61720                     {
61721                         DRMP3_FLUSH_BITS(w);
61722                         w = leaf & 7;
61723                         leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
61724                     }
61725                     DRMP3_FLUSH_BITS(leaf >> 8);
61726                     for (j = 0; j < 2; j++, dst++, leaf >>= 4)
61727                     {
61728                         int lsb = leaf & 0x0F;
61729                         if (lsb == 15)
61730                         {
61731                             lsb += DRMP3_PEEK_BITS(linbits);
61732                             DRMP3_FLUSH_BITS(linbits);
61733                             DRMP3_CHECK_BITS;
61734                             *dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1);
61735                         } else
61736                         {
61737                             *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
61738                         }
61739                         DRMP3_FLUSH_BITS(lsb ? 1 : 0);
61740                     }
61741                     DRMP3_CHECK_BITS;
61742                 } while (--pairs_to_decode);
61743             } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
61744         } else
61745         {
61746             do
61747             {
61748                 np = *sfb++ / 2;
61749                 pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
61750                 one = *scf++;
61751                 do
61752                 {
61753                     int j, w = 5;
61754                     int leaf = codebook[DRMP3_PEEK_BITS(w)];
61755                     while (leaf < 0)
61756                     {
61757                         DRMP3_FLUSH_BITS(w);
61758                         w = leaf & 7;
61759                         leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
61760                     }
61761                     DRMP3_FLUSH_BITS(leaf >> 8);
61762                     for (j = 0; j < 2; j++, dst++, leaf >>= 4)
61763                     {
61764                         int lsb = leaf & 0x0F;
61765                         *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
61766                         DRMP3_FLUSH_BITS(lsb ? 1 : 0);
61767                     }
61768                     DRMP3_CHECK_BITS;
61769                 } while (--pairs_to_decode);
61770             } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
61771         }
61772     }
61773     for (np = 1 - big_val_cnt;; dst += 4)
61774     {
61775         const drmp3_uint8 *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32;
61776         int leaf = codebook_count1[DRMP3_PEEK_BITS(4)];
61777         if (!(leaf & 8))
61778         {
61779             leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))];
61780         }
61781         DRMP3_FLUSH_BITS(leaf & 7);
61782         if (DRMP3_BSPOS > layer3gr_limit)
61783         {
61784             break;
61785         }
61786 #define DRMP3_RELOAD_SCALEFACTOR  if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; }
61787 #define DRMP3_DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((drmp3_int32)bs_cache < 0) ? -one : one; DRMP3_FLUSH_BITS(1) }
61788         DRMP3_RELOAD_SCALEFACTOR;
61789         DRMP3_DEQ_COUNT1(0);
61790         DRMP3_DEQ_COUNT1(1);
61791         DRMP3_RELOAD_SCALEFACTOR;
61792         DRMP3_DEQ_COUNT1(2);
61793         DRMP3_DEQ_COUNT1(3);
61794         DRMP3_CHECK_BITS;
61795     }
61796     bs->pos = layer3gr_limit;
61797 }
61798 static void drmp3_L3_midside_stereo(float *left, int n)
61799 {
61800     int i = 0;
61801     float *right = left + 576;
61802 #if DRMP3_HAVE_SIMD
61803     if (drmp3_have_simd()) for (; i < n - 3; i += 4)
61804     {
61805         drmp3_f4 vl = DRMP3_VLD(left + i);
61806         drmp3_f4 vr = DRMP3_VLD(right + i);
61807         DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr));
61808         DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr));
61809     }
61810 #endif
61811     for (; i < n; i++)
61812     {
61813         float a = left[i];
61814         float b = right[i];
61815         left[i] = a + b;
61816         right[i] = a - b;
61817     }
61818 }
61819 static void drmp3_L3_intensity_stereo_band(float *left, int n, float kl, float kr)
61820 {
61821     int i;
61822     for (i = 0; i < n; i++)
61823     {
61824         left[i + 576] = left[i]*kr;
61825         left[i] = left[i]*kl;
61826     }
61827 }
61828 static void drmp3_L3_stereo_top_band(const float *right, const drmp3_uint8 *sfb, int nbands, int max_band[3])
61829 {
61830     int i, k;
61831     max_band[0] = max_band[1] = max_band[2] = -1;
61832     for (i = 0; i < nbands; i++)
61833     {
61834         for (k = 0; k < sfb[i]; k += 2)
61835         {
61836             if (right[k] != 0 || right[k + 1] != 0)
61837             {
61838                 max_band[i % 3] = i;
61839                 break;
61840             }
61841         }
61842         right += sfb[i];
61843     }
61844 }
61845 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)
61846 {
61847     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 };
61848     unsigned i, max_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 7 : 64;
61849     for (i = 0; sfb[i]; i++)
61850     {
61851         unsigned ipos = ist_pos[i];
61852         if ((int)i > max_band[i % 3] && ipos < max_pos)
61853         {
61854             float kl, kr, s = DRMP3_HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1;
61855             if (DRMP3_HDR_TEST_MPEG1(hdr))
61856             {
61857                 kl = g_pan[2*ipos];
61858                 kr = g_pan[2*ipos + 1];
61859             } else
61860             {
61861                 kl = 1;
61862                 kr = drmp3_L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh);
61863                 if (ipos & 1)
61864                 {
61865                     kl = kr;
61866                     kr = 1;
61867                 }
61868             }
61869             drmp3_L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s);
61870         } else if (DRMP3_HDR_TEST_MS_STEREO(hdr))
61871         {
61872             drmp3_L3_midside_stereo(left, sfb[i]);
61873         }
61874         left += sfb[i];
61875     }
61876 }
61877 static void drmp3_L3_intensity_stereo(float *left, drmp3_uint8 *ist_pos, const drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr)
61878 {
61879     int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb;
61880     int i, max_blocks = gr->n_short_sfb ? 3 : 1;
61881     drmp3_L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band);
61882     if (gr->n_long_sfb)
61883     {
61884         max_band[0] = max_band[1] = max_band[2] = DRMP3_MAX(DRMP3_MAX(max_band[0], max_band[1]), max_band[2]);
61885     }
61886     for (i = 0; i < max_blocks; i++)
61887     {
61888         int default_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 3 : 0;
61889         int itop = n_sfb - max_blocks + i;
61890         int prev = itop - max_blocks;
61891         ist_pos[itop] = (drmp3_uint8)(max_band[i] >= prev ? default_pos : ist_pos[prev]);
61892     }
61893     drmp3_L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1);
61894 }
61895 static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sfb)
61896 {
61897     int i, len;
61898     float *src = grbuf, *dst = scratch;
61899     for (;0 != (len = *sfb); sfb += 3, src += 2*len)
61900     {
61901         for (i = 0; i < len; i++, src++)
61902         {
61903             *dst++ = src[0*len];
61904             *dst++ = src[1*len];
61905             *dst++ = src[2*len];
61906         }
61907     }
61908     memcpy(grbuf, scratch, (dst - scratch)*sizeof(float));
61909 }
61910 static void drmp3_L3_antialias(float *grbuf, int nbands)
61911 {
61912     static const float g_aa[2][8] = {
61913         {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f},
61914         {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f}
61915     };
61916     for (; nbands > 0; nbands--, grbuf += 18)
61917     {
61918         int i = 0;
61919 #if DRMP3_HAVE_SIMD
61920         if (drmp3_have_simd()) for (; i < 8; i += 4)
61921         {
61922             drmp3_f4 vu = DRMP3_VLD(grbuf + 18 + i);
61923             drmp3_f4 vd = DRMP3_VLD(grbuf + 14 - i);
61924             drmp3_f4 vc0 = DRMP3_VLD(g_aa[0] + i);
61925             drmp3_f4 vc1 = DRMP3_VLD(g_aa[1] + i);
61926             vd = DRMP3_VREV(vd);
61927             DRMP3_VSTORE(grbuf + 18 + i, DRMP3_VSUB(DRMP3_VMUL(vu, vc0), DRMP3_VMUL(vd, vc1)));
61928             vd = DRMP3_VADD(DRMP3_VMUL(vu, vc1), DRMP3_VMUL(vd, vc0));
61929             DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vd));
61930         }
61931 #endif
61932 #ifndef DR_MP3_ONLY_SIMD
61933         for(; i < 8; i++)
61934         {
61935             float u = grbuf[18 + i];
61936             float d = grbuf[17 - i];
61937             grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i];
61938             grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i];
61939         }
61940 #endif
61941     }
61942 }
61943 static void drmp3_L3_dct3_9(float *y)
61944 {
61945     float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4;
61946     s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8];
61947     t0 = s0 + s6*0.5f;
61948     s0 -= s6;
61949     t4 = (s4 + s2)*0.93969262f;
61950     t2 = (s8 + s2)*0.76604444f;
61951     s6 = (s4 - s8)*0.17364818f;
61952     s4 += s8 - s2;
61953     s2 = s0 - s4*0.5f;
61954     y[4] = s4 + s0;
61955     s8 = t0 - t2 + s6;
61956     s0 = t0 - t4 + t2;
61957     s4 = t0 + t4 - s6;
61958     s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7];
61959     s3 *= 0.86602540f;
61960     t0 = (s5 + s1)*0.98480775f;
61961     t4 = (s5 - s7)*0.34202014f;
61962     t2 = (s1 + s7)*0.64278761f;
61963     s1 = (s1 - s5 - s7)*0.86602540f;
61964     s5 = t0 - s3 - t2;
61965     s7 = t4 - s3 - t0;
61966     s3 = t4 + s3 - t2;
61967     y[0] = s4 - s7;
61968     y[1] = s2 + s1;
61969     y[2] = s0 - s3;
61970     y[3] = s8 + s5;
61971     y[5] = s8 - s5;
61972     y[6] = s0 + s3;
61973     y[7] = s2 - s1;
61974     y[8] = s4 + s7;
61975 }
61976 static void drmp3_L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands)
61977 {
61978     int i, j;
61979     static const float g_twid9[18] = {
61980         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
61981     };
61982     for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9)
61983     {
61984         float co[9], si[9];
61985         co[0] = -grbuf[0];
61986         si[0] = grbuf[17];
61987         for (i = 0; i < 4; i++)
61988         {
61989             si[8 - 2*i] =   grbuf[4*i + 1] - grbuf[4*i + 2];
61990             co[1 + 2*i] =   grbuf[4*i + 1] + grbuf[4*i + 2];
61991             si[7 - 2*i] =   grbuf[4*i + 4] - grbuf[4*i + 3];
61992             co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]);
61993         }
61994         drmp3_L3_dct3_9(co);
61995         drmp3_L3_dct3_9(si);
61996         si[1] = -si[1];
61997         si[3] = -si[3];
61998         si[5] = -si[5];
61999         si[7] = -si[7];
62000         i = 0;
62001 #if DRMP3_HAVE_SIMD
62002         if (drmp3_have_simd()) for (; i < 8; i += 4)
62003         {
62004             drmp3_f4 vovl = DRMP3_VLD(overlap + i);
62005             drmp3_f4 vc = DRMP3_VLD(co + i);
62006             drmp3_f4 vs = DRMP3_VLD(si + i);
62007             drmp3_f4 vr0 = DRMP3_VLD(g_twid9 + i);
62008             drmp3_f4 vr1 = DRMP3_VLD(g_twid9 + 9 + i);
62009             drmp3_f4 vw0 = DRMP3_VLD(window + i);
62010             drmp3_f4 vw1 = DRMP3_VLD(window + 9 + i);
62011             drmp3_f4 vsum = DRMP3_VADD(DRMP3_VMUL(vc, vr1), DRMP3_VMUL(vs, vr0));
62012             DRMP3_VSTORE(overlap + i, DRMP3_VSUB(DRMP3_VMUL(vc, vr0), DRMP3_VMUL(vs, vr1)));
62013             DRMP3_VSTORE(grbuf + i, DRMP3_VSUB(DRMP3_VMUL(vovl, vw0), DRMP3_VMUL(vsum, vw1)));
62014             vsum = DRMP3_VADD(DRMP3_VMUL(vovl, vw1), DRMP3_VMUL(vsum, vw0));
62015             DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vsum));
62016         }
62017 #endif
62018         for (; i < 9; i++)
62019         {
62020             float ovl  = overlap[i];
62021             float sum  = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i];
62022             overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i];
62023             grbuf[i]      = ovl*window[0 + i] - sum*window[9 + i];
62024             grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i];
62025         }
62026     }
62027 }
62028 static void drmp3_L3_idct3(float x0, float x1, float x2, float *dst)
62029 {
62030     float m1 = x1*0.86602540f;
62031     float a1 = x0 - x2*0.5f;
62032     dst[1] = x0 + x2;
62033     dst[0] = a1 + m1;
62034     dst[2] = a1 - m1;
62035 }
62036 static void drmp3_L3_imdct12(float *x, float *dst, float *overlap)
62037 {
62038     static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f };
62039     float co[3], si[3];
62040     int i;
62041     drmp3_L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co);
62042     drmp3_L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si);
62043     si[1] = -si[1];
62044     for (i = 0; i < 3; i++)
62045     {
62046         float ovl  = overlap[i];
62047         float sum  = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i];
62048         overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i];
62049         dst[i]     = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i];
62050         dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i];
62051     }
62052 }
62053 static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands)
62054 {
62055     for (;nbands > 0; nbands--, overlap += 9, grbuf += 18)
62056     {
62057         float tmp[18];
62058         memcpy(tmp, grbuf, sizeof(tmp));
62059         memcpy(grbuf, overlap, 6*sizeof(float));
62060         drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6);
62061         drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6);
62062         drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6);
62063     }
62064 }
62065 static void drmp3_L3_change_sign(float *grbuf)
62066 {
62067     int b, i;
62068     for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36)
62069         for (i = 1; i < 18; i += 2)
62070             grbuf[i] = -grbuf[i];
62071 }
62072 static void drmp3_L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands)
62073 {
62074     static const float g_mdct_window[2][18] = {
62075         { 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 },
62076         { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f }
62077     };
62078     if (n_long_bands)
62079     {
62080         drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands);
62081         grbuf += 18*n_long_bands;
62082         overlap += 9*n_long_bands;
62083     }
62084     if (block_type == DRMP3_SHORT_BLOCK_TYPE)
62085         drmp3_L3_imdct_short(grbuf, overlap, 32 - n_long_bands);
62086     else
62087         drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[block_type == DRMP3_STOP_BLOCK_TYPE], 32 - n_long_bands);
62088 }
62089 static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s)
62090 {
62091     int pos = (s->bs.pos + 7)/8u;
62092     int remains = s->bs.limit/8u - pos;
62093     if (remains > DRMP3_MAX_BITRESERVOIR_BYTES)
62094     {
62095         pos += remains - DRMP3_MAX_BITRESERVOIR_BYTES;
62096         remains = DRMP3_MAX_BITRESERVOIR_BYTES;
62097     }
62098     if (remains > 0)
62099     {
62100         memmove(h->reserv_buf, s->maindata + pos, remains);
62101     }
62102     h->reserv = remains;
62103 }
62104 static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratch *s, int main_data_begin)
62105 {
62106     int frame_bytes = (bs->limit - bs->pos)/8;
62107     int bytes_have = DRMP3_MIN(h->reserv, main_data_begin);
62108     memcpy(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin));
62109     memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes);
62110     drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes);
62111     return h->reserv >= main_data_begin;
62112 }
62113 static void drmp3_L3_decode(drmp3dec *h, drmp3dec_scratch *s, drmp3_L3_gr_info *gr_info, int nch)
62114 {
62115     int ch;
62116     for (ch = 0; ch < nch; ch++)
62117     {
62118         int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length;
62119         drmp3_L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch);
62120         drmp3_L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit);
62121     }
62122     if (DRMP3_HDR_TEST_I_STEREO(h->header))
62123     {
62124         drmp3_L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header);
62125     } else if (DRMP3_HDR_IS_MS_STEREO(h->header))
62126     {
62127         drmp3_L3_midside_stereo(s->grbuf[0], 576);
62128     }
62129     for (ch = 0; ch < nch; ch++, gr_info++)
62130     {
62131         int aa_bands = 31;
62132         int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(DRMP3_HDR_GET_MY_SAMPLE_RATE(h->header) == 2);
62133         if (gr_info->n_short_sfb)
62134         {
62135             aa_bands = n_long_bands - 1;
62136             drmp3_L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb);
62137         }
62138         drmp3_L3_antialias(s->grbuf[ch], aa_bands);
62139         drmp3_L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands);
62140         drmp3_L3_change_sign(s->grbuf[ch]);
62141     }
62142 }
62143 static void drmp3d_DCT_II(float *grbuf, int n)
62144 {
62145     static const float g_sec[24] = {
62146         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
62147     };
62148     int i, k = 0;
62149 #if DRMP3_HAVE_SIMD
62150     if (drmp3_have_simd()) for (; k < n; k += 4)
62151     {
62152         drmp3_f4 t[4][8], *x;
62153         float *y = grbuf + k;
62154         for (x = t[0], i = 0; i < 8; i++, x++)
62155         {
62156             drmp3_f4 x0 = DRMP3_VLD(&y[i*18]);
62157             drmp3_f4 x1 = DRMP3_VLD(&y[(15 - i)*18]);
62158             drmp3_f4 x2 = DRMP3_VLD(&y[(16 + i)*18]);
62159             drmp3_f4 x3 = DRMP3_VLD(&y[(31 - i)*18]);
62160             drmp3_f4 t0 = DRMP3_VADD(x0, x3);
62161             drmp3_f4 t1 = DRMP3_VADD(x1, x2);
62162             drmp3_f4 t2 = DRMP3_VMUL_S(DRMP3_VSUB(x1, x2), g_sec[3*i + 0]);
62163             drmp3_f4 t3 = DRMP3_VMUL_S(DRMP3_VSUB(x0, x3), g_sec[3*i + 1]);
62164             x[0] = DRMP3_VADD(t0, t1);
62165             x[8] = DRMP3_VMUL_S(DRMP3_VSUB(t0, t1), g_sec[3*i + 2]);
62166             x[16] = DRMP3_VADD(t3, t2);
62167             x[24] = DRMP3_VMUL_S(DRMP3_VSUB(t3, t2), g_sec[3*i + 2]);
62168         }
62169         for (x = t[0], i = 0; i < 4; i++, x += 8)
62170         {
62171             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;
62172             xt = DRMP3_VSUB(x0, x7); x0 = DRMP3_VADD(x0, x7);
62173             x7 = DRMP3_VSUB(x1, x6); x1 = DRMP3_VADD(x1, x6);
62174             x6 = DRMP3_VSUB(x2, x5); x2 = DRMP3_VADD(x2, x5);
62175             x5 = DRMP3_VSUB(x3, x4); x3 = DRMP3_VADD(x3, x4);
62176             x4 = DRMP3_VSUB(x0, x3); x0 = DRMP3_VADD(x0, x3);
62177             x3 = DRMP3_VSUB(x1, x2); x1 = DRMP3_VADD(x1, x2);
62178             x[0] = DRMP3_VADD(x0, x1);
62179             x[4] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x1), 0.70710677f);
62180             x5 = DRMP3_VADD(x5, x6);
62181             x6 = DRMP3_VMUL_S(DRMP3_VADD(x6, x7), 0.70710677f);
62182             x7 = DRMP3_VADD(x7, xt);
62183             x3 = DRMP3_VMUL_S(DRMP3_VADD(x3, x4), 0.70710677f);
62184             x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f));
62185             x7 = DRMP3_VADD(x7, DRMP3_VMUL_S(x5, 0.382683432f));
62186             x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f));
62187             x0 = DRMP3_VSUB(xt, x6); xt = DRMP3_VADD(xt, x6);
62188             x[1] = DRMP3_VMUL_S(DRMP3_VADD(xt, x7), 0.50979561f);
62189             x[2] = DRMP3_VMUL_S(DRMP3_VADD(x4, x3), 0.54119611f);
62190             x[3] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x5), 0.60134488f);
62191             x[5] = DRMP3_VMUL_S(DRMP3_VADD(x0, x5), 0.89997619f);
62192             x[6] = DRMP3_VMUL_S(DRMP3_VSUB(x4, x3), 1.30656302f);
62193             x[7] = DRMP3_VMUL_S(DRMP3_VSUB(xt, x7), 2.56291556f);
62194         }
62195         if (k > n - 3)
62196         {
62197 #if DRMP3_HAVE_SSE
62198 #define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v)
62199 #else
62200 #define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18],  vget_low_f32(v))
62201 #endif
62202             for (i = 0; i < 7; i++, y += 4*18)
62203             {
62204                 drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
62205                 DRMP3_VSAVE2(0, t[0][i]);
62206                 DRMP3_VSAVE2(1, DRMP3_VADD(t[2][i], s));
62207                 DRMP3_VSAVE2(2, DRMP3_VADD(t[1][i], t[1][i + 1]));
62208                 DRMP3_VSAVE2(3, DRMP3_VADD(t[2][1 + i], s));
62209             }
62210             DRMP3_VSAVE2(0, t[0][7]);
62211             DRMP3_VSAVE2(1, DRMP3_VADD(t[2][7], t[3][7]));
62212             DRMP3_VSAVE2(2, t[1][7]);
62213             DRMP3_VSAVE2(3, t[3][7]);
62214         } else
62215         {
62216 #define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[i*18], v)
62217             for (i = 0; i < 7; i++, y += 4*18)
62218             {
62219                 drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
62220                 DRMP3_VSAVE4(0, t[0][i]);
62221                 DRMP3_VSAVE4(1, DRMP3_VADD(t[2][i], s));
62222                 DRMP3_VSAVE4(2, DRMP3_VADD(t[1][i], t[1][i + 1]));
62223                 DRMP3_VSAVE4(3, DRMP3_VADD(t[2][1 + i], s));
62224             }
62225             DRMP3_VSAVE4(0, t[0][7]);
62226             DRMP3_VSAVE4(1, DRMP3_VADD(t[2][7], t[3][7]));
62227             DRMP3_VSAVE4(2, t[1][7]);
62228             DRMP3_VSAVE4(3, t[3][7]);
62229         }
62230     } else
62231 #endif
62232 #ifdef DR_MP3_ONLY_SIMD
62233     {}
62234 #else
62235     for (; k < n; k++)
62236     {
62237         float t[4][8], *x, *y = grbuf + k;
62238         for (x = t[0], i = 0; i < 8; i++, x++)
62239         {
62240             float x0 = y[i*18];
62241             float x1 = y[(15 - i)*18];
62242             float x2 = y[(16 + i)*18];
62243             float x3 = y[(31 - i)*18];
62244             float t0 = x0 + x3;
62245             float t1 = x1 + x2;
62246             float t2 = (x1 - x2)*g_sec[3*i + 0];
62247             float t3 = (x0 - x3)*g_sec[3*i + 1];
62248             x[0] = t0 + t1;
62249             x[8] = (t0 - t1)*g_sec[3*i + 2];
62250             x[16] = t3 + t2;
62251             x[24] = (t3 - t2)*g_sec[3*i + 2];
62252         }
62253         for (x = t[0], i = 0; i < 4; i++, x += 8)
62254         {
62255             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;
62256             xt = x0 - x7; x0 += x7;
62257             x7 = x1 - x6; x1 += x6;
62258             x6 = x2 - x5; x2 += x5;
62259             x5 = x3 - x4; x3 += x4;
62260             x4 = x0 - x3; x0 += x3;
62261             x3 = x1 - x2; x1 += x2;
62262             x[0] = x0 + x1;
62263             x[4] = (x0 - x1)*0.70710677f;
62264             x5 =  x5 + x6;
62265             x6 = (x6 + x7)*0.70710677f;
62266             x7 =  x7 + xt;
62267             x3 = (x3 + x4)*0.70710677f;
62268             x5 -= x7*0.198912367f;
62269             x7 += x5*0.382683432f;
62270             x5 -= x7*0.198912367f;
62271             x0 = xt - x6; xt += x6;
62272             x[1] = (xt + x7)*0.50979561f;
62273             x[2] = (x4 + x3)*0.54119611f;
62274             x[3] = (x0 - x5)*0.60134488f;
62275             x[5] = (x0 + x5)*0.89997619f;
62276             x[6] = (x4 - x3)*1.30656302f;
62277             x[7] = (xt - x7)*2.56291556f;
62278         }
62279         for (i = 0; i < 7; i++, y += 4*18)
62280         {
62281             y[0*18] = t[0][i];
62282             y[1*18] = t[2][i] + t[3][i] + t[3][i + 1];
62283             y[2*18] = t[1][i] + t[1][i + 1];
62284             y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1];
62285         }
62286         y[0*18] = t[0][7];
62287         y[1*18] = t[2][7] + t[3][7];
62288         y[2*18] = t[1][7];
62289         y[3*18] = t[3][7];
62290     }
62291 #endif
62292 }
62293 #ifndef DR_MP3_FLOAT_OUTPUT
62294 typedef drmp3_int16 drmp3d_sample_t;
62295 static drmp3_int16 drmp3d_scale_pcm(float sample)
62296 {
62297     drmp3_int16 s;
62298 #if DRMP3_HAVE_ARMV6
62299     drmp3_int32 s32 = (drmp3_int32)(sample + .5f);
62300     s32 -= (s32 < 0);
62301     s = (drmp3_int16)drmp3_clip_int16_arm(s32);
62302 #else
62303     if (sample >=  32766.5) return (drmp3_int16) 32767;
62304     if (sample <= -32767.5) return (drmp3_int16)-32768;
62305     s = (drmp3_int16)(sample + .5f);
62306     s -= (s < 0);
62307 #endif
62308     return s;
62309 }
62310 #else
62311 typedef float drmp3d_sample_t;
62312 static float drmp3d_scale_pcm(float sample)
62313 {
62314     return sample*(1.f/32768.f);
62315 }
62316 #endif
62317 static void drmp3d_synth_pair(drmp3d_sample_t *pcm, int nch, const float *z)
62318 {
62319     float a;
62320     a  = (z[14*64] - z[    0]) * 29;
62321     a += (z[ 1*64] + z[13*64]) * 213;
62322     a += (z[12*64] - z[ 2*64]) * 459;
62323     a += (z[ 3*64] + z[11*64]) * 2037;
62324     a += (z[10*64] - z[ 4*64]) * 5153;
62325     a += (z[ 5*64] + z[ 9*64]) * 6574;
62326     a += (z[ 8*64] - z[ 6*64]) * 37489;
62327     a +=  z[ 7*64]             * 75038;
62328     pcm[0] = drmp3d_scale_pcm(a);
62329     z += 2;
62330     a  = z[14*64] * 104;
62331     a += z[12*64] * 1567;
62332     a += z[10*64] * 9727;
62333     a += z[ 8*64] * 64019;
62334     a += z[ 6*64] * -9975;
62335     a += z[ 4*64] * -45;
62336     a += z[ 2*64] * 146;
62337     a += z[ 0*64] * -5;
62338     pcm[16*nch] = drmp3d_scale_pcm(a);
62339 }
62340 static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins)
62341 {
62342     int i;
62343     float *xr = xl + 576*(nch - 1);
62344     drmp3d_sample_t *dstr = dstl + (nch - 1);
62345     static const float g_win[] = {
62346         -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992,
62347         -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856,
62348         -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630,
62349         -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313,
62350         -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908,
62351         -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415,
62352         -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835,
62353         -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169,
62354         -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420,
62355         -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590,
62356         -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679,
62357         -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692,
62358         -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629,
62359         -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494,
62360         -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290
62361     };
62362     float *zlin = lins + 15*64;
62363     const float *w = g_win;
62364     zlin[4*15]     = xl[18*16];
62365     zlin[4*15 + 1] = xr[18*16];
62366     zlin[4*15 + 2] = xl[0];
62367     zlin[4*15 + 3] = xr[0];
62368     zlin[4*31]     = xl[1 + 18*16];
62369     zlin[4*31 + 1] = xr[1 + 18*16];
62370     zlin[4*31 + 2] = xl[1];
62371     zlin[4*31 + 3] = xr[1];
62372     drmp3d_synth_pair(dstr, nch, lins + 4*15 + 1);
62373     drmp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1);
62374     drmp3d_synth_pair(dstl, nch, lins + 4*15);
62375     drmp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64);
62376 #if DRMP3_HAVE_SIMD
62377     if (drmp3_have_simd()) for (i = 14; i >= 0; i--)
62378     {
62379 #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)]);
62380 #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));  }
62381 #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))); }
62382 #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))); }
62383         drmp3_f4 a, b;
62384         zlin[4*i]     = xl[18*(31 - i)];
62385         zlin[4*i + 1] = xr[18*(31 - i)];
62386         zlin[4*i + 2] = xl[1 + 18*(31 - i)];
62387         zlin[4*i + 3] = xr[1 + 18*(31 - i)];
62388         zlin[4*i + 64] = xl[1 + 18*(1 + i)];
62389         zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)];
62390         zlin[4*i - 64 + 2] = xl[18*(1 + i)];
62391         zlin[4*i - 64 + 3] = xr[18*(1 + i)];
62392         DRMP3_V0(0) DRMP3_V2(1) DRMP3_V1(2) DRMP3_V2(3) DRMP3_V1(4) DRMP3_V2(5) DRMP3_V1(6) DRMP3_V2(7)
62393         {
62394 #ifndef DR_MP3_FLOAT_OUTPUT
62395 #if DRMP3_HAVE_SSE
62396             static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f };
62397             static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f };
62398             __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)),
62399                                            _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min)));
62400             dstr[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
62401             dstr[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 5);
62402             dstl[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
62403             dstl[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 4);
62404             dstr[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 3);
62405             dstr[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 7);
62406             dstl[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
62407             dstl[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 6);
62408 #else
62409             int16x4_t pcma, pcmb;
62410             a = DRMP3_VADD(a, DRMP3_VSET(0.5f));
62411             b = DRMP3_VADD(b, DRMP3_VSET(0.5f));
62412             pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0)))));
62413             pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0)))));
62414             vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1);
62415             vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1);
62416             vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0);
62417             vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0);
62418             vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3);
62419             vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3);
62420             vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2);
62421             vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2);
62422 #endif
62423 #else
62424             static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
62425             a = DRMP3_VMUL(a, g_scale);
62426             b = DRMP3_VMUL(b, g_scale);
62427 #if DRMP3_HAVE_SSE
62428             _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)));
62429             _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1)));
62430             _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)));
62431             _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0)));
62432             _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)));
62433             _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3)));
62434             _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
62435             _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2)));
62436 #else
62437             vst1q_lane_f32(dstr + (15 - i)*nch, a, 1);
62438             vst1q_lane_f32(dstr + (17 + i)*nch, b, 1);
62439             vst1q_lane_f32(dstl + (15 - i)*nch, a, 0);
62440             vst1q_lane_f32(dstl + (17 + i)*nch, b, 0);
62441             vst1q_lane_f32(dstr + (47 - i)*nch, a, 3);
62442             vst1q_lane_f32(dstr + (49 + i)*nch, b, 3);
62443             vst1q_lane_f32(dstl + (47 - i)*nch, a, 2);
62444             vst1q_lane_f32(dstl + (49 + i)*nch, b, 2);
62445 #endif
62446 #endif
62447         }
62448     } else
62449 #endif
62450 #ifdef DR_MP3_ONLY_SIMD
62451     {}
62452 #else
62453     for (i = 14; i >= 0; i--)
62454     {
62455 #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];
62456 #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; }
62457 #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; }
62458 #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; }
62459         float a[4], b[4];
62460         zlin[4*i]     = xl[18*(31 - i)];
62461         zlin[4*i + 1] = xr[18*(31 - i)];
62462         zlin[4*i + 2] = xl[1 + 18*(31 - i)];
62463         zlin[4*i + 3] = xr[1 + 18*(31 - i)];
62464         zlin[4*(i + 16)]   = xl[1 + 18*(1 + i)];
62465         zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)];
62466         zlin[4*(i - 16) + 2] = xl[18*(1 + i)];
62467         zlin[4*(i - 16) + 3] = xr[18*(1 + i)];
62468         DRMP3_S0(0) DRMP3_S2(1) DRMP3_S1(2) DRMP3_S2(3) DRMP3_S1(4) DRMP3_S2(5) DRMP3_S1(6) DRMP3_S2(7)
62469         dstr[(15 - i)*nch] = drmp3d_scale_pcm(a[1]);
62470         dstr[(17 + i)*nch] = drmp3d_scale_pcm(b[1]);
62471         dstl[(15 - i)*nch] = drmp3d_scale_pcm(a[0]);
62472         dstl[(17 + i)*nch] = drmp3d_scale_pcm(b[0]);
62473         dstr[(47 - i)*nch] = drmp3d_scale_pcm(a[3]);
62474         dstr[(49 + i)*nch] = drmp3d_scale_pcm(b[3]);
62475         dstl[(47 - i)*nch] = drmp3d_scale_pcm(a[2]);
62476         dstl[(49 + i)*nch] = drmp3d_scale_pcm(b[2]);
62477     }
62478 #endif
62479 }
62480 static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, drmp3d_sample_t *pcm, float *lins)
62481 {
62482     int i;
62483     for (i = 0; i < nch; i++)
62484     {
62485         drmp3d_DCT_II(grbuf + 576*i, nbands);
62486     }
62487     memcpy(lins, qmf_state, sizeof(float)*15*64);
62488     for (i = 0; i < nbands; i += 2)
62489     {
62490         drmp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64);
62491     }
62492 #ifndef DR_MP3_NONSTANDARD_BUT_LOGICAL
62493     if (nch == 1)
62494     {
62495         for (i = 0; i < 15*64; i += 2)
62496         {
62497             qmf_state[i] = lins[nbands*64 + i];
62498         }
62499     } else
62500 #endif
62501     {
62502         memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64);
62503     }
62504 }
62505 static int drmp3d_match_frame(const drmp3_uint8 *hdr, int mp3_bytes, int frame_bytes)
62506 {
62507     int i, nmatch;
62508     for (i = 0, nmatch = 0; nmatch < DRMP3_MAX_FRAME_SYNC_MATCHES; nmatch++)
62509     {
62510         i += drmp3_hdr_frame_bytes(hdr + i, frame_bytes) + drmp3_hdr_padding(hdr + i);
62511         if (i + DRMP3_HDR_SIZE > mp3_bytes)
62512             return nmatch > 0;
62513         if (!drmp3_hdr_compare(hdr, hdr + i))
62514             return 0;
62515     }
62516     return 1;
62517 }
62518 static int drmp3d_find_frame(const drmp3_uint8 *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes)
62519 {
62520     int i, k;
62521     for (i = 0; i < mp3_bytes - DRMP3_HDR_SIZE; i++, mp3++)
62522     {
62523         if (drmp3_hdr_valid(mp3))
62524         {
62525             int frame_bytes = drmp3_hdr_frame_bytes(mp3, *free_format_bytes);
62526             int frame_and_padding = frame_bytes + drmp3_hdr_padding(mp3);
62527             for (k = DRMP3_HDR_SIZE; !frame_bytes && k < DRMP3_MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - DRMP3_HDR_SIZE; k++)
62528             {
62529                 if (drmp3_hdr_compare(mp3, mp3 + k))
62530                 {
62531                     int fb = k - drmp3_hdr_padding(mp3);
62532                     int nextfb = fb + drmp3_hdr_padding(mp3 + k);
62533                     if (i + k + nextfb + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + k + nextfb))
62534                         continue;
62535                     frame_and_padding = k;
62536                     frame_bytes = fb;
62537                     *free_format_bytes = fb;
62538                 }
62539             }
62540             if ((frame_bytes && i + frame_and_padding <= mp3_bytes &&
62541                 drmp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) ||
62542                 (!i && frame_and_padding == mp3_bytes))
62543             {
62544                 *ptr_frame_bytes = frame_and_padding;
62545                 return i;
62546             }
62547             *free_format_bytes = 0;
62548         }
62549     }
62550     *ptr_frame_bytes = 0;
62551     return mp3_bytes;
62552 }
62553 DRMP3_API void drmp3dec_init(drmp3dec *dec)
62554 {
62555     dec->header[0] = 0;
62556 }
62557 DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info)
62558 {
62559     int i = 0, igr, frame_size = 0, success = 1;
62560     const drmp3_uint8 *hdr;
62561     drmp3_bs bs_frame[1];
62562     drmp3dec_scratch scratch;
62563     if (mp3_bytes > 4 && dec->header[0] == 0xff && drmp3_hdr_compare(dec->header, mp3))
62564     {
62565         frame_size = drmp3_hdr_frame_bytes(mp3, dec->free_format_bytes) + drmp3_hdr_padding(mp3);
62566         if (frame_size != mp3_bytes && (frame_size + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + frame_size)))
62567         {
62568             frame_size = 0;
62569         }
62570     }
62571     if (!frame_size)
62572     {
62573         memset(dec, 0, sizeof(drmp3dec));
62574         i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size);
62575         if (!frame_size || i + frame_size > mp3_bytes)
62576         {
62577             info->frame_bytes = i;
62578             return 0;
62579         }
62580     }
62581     hdr = mp3 + i;
62582     memcpy(dec->header, hdr, DRMP3_HDR_SIZE);
62583     info->frame_bytes = i + frame_size;
62584     info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
62585     info->hz = drmp3_hdr_sample_rate_hz(hdr);
62586     info->layer = 4 - DRMP3_HDR_GET_LAYER(hdr);
62587     info->bitrate_kbps = drmp3_hdr_bitrate_kbps(hdr);
62588     drmp3_bs_init(bs_frame, hdr + DRMP3_HDR_SIZE, frame_size - DRMP3_HDR_SIZE);
62589     if (DRMP3_HDR_IS_CRC(hdr))
62590     {
62591         drmp3_bs_get_bits(bs_frame, 16);
62592     }
62593     if (info->layer == 3)
62594     {
62595         int main_data_begin = drmp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr);
62596         if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit)
62597         {
62598             drmp3dec_init(dec);
62599             return 0;
62600         }
62601         success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin);
62602         if (success && pcm != NULL)
62603         {
62604             for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels))
62605             {
62606                 memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
62607                 drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels);
62608                 drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
62609             }
62610         }
62611         drmp3_L3_save_reservoir(dec, &scratch);
62612     } else
62613     {
62614 #ifdef DR_MP3_ONLY_MP3
62615         return 0;
62616 #else
62617         drmp3_L12_scale_info sci[1];
62618         if (pcm == NULL) {
62619             return drmp3_hdr_frame_samples(hdr);
62620         }
62621         drmp3_L12_read_scale_info(hdr, bs_frame, sci);
62622         memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
62623         for (i = 0, igr = 0; igr < 3; igr++)
62624         {
62625             if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
62626             {
62627                 i = 0;
62628                 drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]);
62629                 drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
62630                 memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
62631                 pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels);
62632             }
62633             if (bs_frame->pos > bs_frame->limit)
62634             {
62635                 drmp3dec_init(dec);
62636                 return 0;
62637             }
62638         }
62639 #endif
62640     }
62641     return success*drmp3_hdr_frame_samples(dec->header);
62642 }
62643 DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples)
62644 {
62645     size_t i = 0;
62646 #if DRMP3_HAVE_SIMD
62647     size_t aligned_count = num_samples & ~7;
62648     for(; i < aligned_count; i+=8)
62649     {
62650         drmp3_f4 scale = DRMP3_VSET(32768.0f);
62651         drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i  ]), scale);
62652         drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), scale);
62653 #if DRMP3_HAVE_SSE
62654         drmp3_f4 s16max = DRMP3_VSET( 32767.0f);
62655         drmp3_f4 s16min = DRMP3_VSET(-32768.0f);
62656         __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, s16max), s16min)),
62657                                         _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, s16max), s16min)));
62658         out[i  ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
62659         out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
62660         out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
62661         out[i+3] = (drmp3_int16)_mm_extract_epi16(pcm8, 3);
62662         out[i+4] = (drmp3_int16)_mm_extract_epi16(pcm8, 4);
62663         out[i+5] = (drmp3_int16)_mm_extract_epi16(pcm8, 5);
62664         out[i+6] = (drmp3_int16)_mm_extract_epi16(pcm8, 6);
62665         out[i+7] = (drmp3_int16)_mm_extract_epi16(pcm8, 7);
62666 #else
62667         int16x4_t pcma, pcmb;
62668         a = DRMP3_VADD(a, DRMP3_VSET(0.5f));
62669         b = DRMP3_VADD(b, DRMP3_VSET(0.5f));
62670         pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0)))));
62671         pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0)))));
62672         vst1_lane_s16(out+i  , pcma, 0);
62673         vst1_lane_s16(out+i+1, pcma, 1);
62674         vst1_lane_s16(out+i+2, pcma, 2);
62675         vst1_lane_s16(out+i+3, pcma, 3);
62676         vst1_lane_s16(out+i+4, pcmb, 0);
62677         vst1_lane_s16(out+i+5, pcmb, 1);
62678         vst1_lane_s16(out+i+6, pcmb, 2);
62679         vst1_lane_s16(out+i+7, pcmb, 3);
62680 #endif
62681     }
62682 #endif
62683     for(; i < num_samples; i++)
62684     {
62685         float sample = in[i] * 32768.0f;
62686         if (sample >=  32766.5)
62687             out[i] = (drmp3_int16) 32767;
62688         else if (sample <= -32767.5)
62689             out[i] = (drmp3_int16)-32768;
62690         else
62691         {
62692             short s = (drmp3_int16)(sample + .5f);
62693             s -= (s < 0);
62694             out[i] = s;
62695         }
62696     }
62697 }
62698 #include <math.h>
62699 #if defined(SIZE_MAX)
62700     #define DRMP3_SIZE_MAX  SIZE_MAX
62701 #else
62702     #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
62703         #define DRMP3_SIZE_MAX  ((drmp3_uint64)0xFFFFFFFFFFFFFFFF)
62704     #else
62705         #define DRMP3_SIZE_MAX  0xFFFFFFFF
62706     #endif
62707 #endif
62708 #ifndef DRMP3_SEEK_LEADING_MP3_FRAMES
62709 #define DRMP3_SEEK_LEADING_MP3_FRAMES   2
62710 #endif
62711 #define DRMP3_MIN_DATA_CHUNK_SIZE   16384
62712 #ifndef DRMP3_DATA_CHUNK_SIZE
62713 #define DRMP3_DATA_CHUNK_SIZE  DRMP3_MIN_DATA_CHUNK_SIZE*4
62714 #endif
62715 #ifndef DRMP3_ASSERT
62716 #include <assert.h>
62717 #define DRMP3_ASSERT(expression) assert(expression)
62718 #endif
62719 #ifndef DRMP3_COPY_MEMORY
62720 #define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
62721 #endif
62722 #ifndef DRMP3_ZERO_MEMORY
62723 #define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
62724 #endif
62725 #define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p)))
62726 #ifndef DRMP3_MALLOC
62727 #define DRMP3_MALLOC(sz) malloc((sz))
62728 #endif
62729 #ifndef DRMP3_REALLOC
62730 #define DRMP3_REALLOC(p, sz) realloc((p), (sz))
62731 #endif
62732 #ifndef DRMP3_FREE
62733 #define DRMP3_FREE(p) free((p))
62734 #endif
62735 #define DRMP3_COUNTOF(x)        (sizeof(x) / sizeof(x[0]))
62736 #define DRMP3_CLAMP(x, lo, hi)  (DRMP3_MAX(lo, DRMP3_MIN(x, hi)))
62737 #ifndef DRMP3_PI_D
62738 #define DRMP3_PI_D    3.14159265358979323846264
62739 #endif
62740 #define DRMP3_DEFAULT_RESAMPLER_LPF_ORDER   2
62741 static DRMP3_INLINE float drmp3_mix_f32(float x, float y, float a)
62742 {
62743     return x*(1-a) + y*a;
62744 }
62745 static DRMP3_INLINE float drmp3_mix_f32_fast(float x, float y, float a)
62746 {
62747     float r0 = (y - x);
62748     float r1 = r0*a;
62749     return x + r1;
62750 }
62751 static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b)
62752 {
62753     for (;;) {
62754         if (b == 0) {
62755             break;
62756         } else {
62757             drmp3_uint32 t = a;
62758             a = b;
62759             b = t % a;
62760         }
62761     }
62762     return a;
62763 }
62764 static DRMP3_INLINE double drmp3_sin(double x)
62765 {
62766     return sin(x);
62767 }
62768 static DRMP3_INLINE double drmp3_exp(double x)
62769 {
62770     return exp(x);
62771 }
62772 static DRMP3_INLINE double drmp3_cos(double x)
62773 {
62774     return drmp3_sin((DRMP3_PI_D*0.5) - x);
62775 }
62776 static void* drmp3__malloc_default(size_t sz, void* pUserData)
62777 {
62778     (void)pUserData;
62779     return DRMP3_MALLOC(sz);
62780 }
62781 static void* drmp3__realloc_default(void* p, size_t sz, void* pUserData)
62782 {
62783     (void)pUserData;
62784     return DRMP3_REALLOC(p, sz);
62785 }
62786 static void drmp3__free_default(void* p, void* pUserData)
62787 {
62788     (void)pUserData;
62789     DRMP3_FREE(p);
62790 }
62791 static void* drmp3__malloc_from_callbacks(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
62792 {
62793     if (pAllocationCallbacks == NULL) {
62794         return NULL;
62795     }
62796     if (pAllocationCallbacks->onMalloc != NULL) {
62797         return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
62798     }
62799     if (pAllocationCallbacks->onRealloc != NULL) {
62800         return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
62801     }
62802     return NULL;
62803 }
62804 static void* drmp3__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drmp3_allocation_callbacks* pAllocationCallbacks)
62805 {
62806     if (pAllocationCallbacks == NULL) {
62807         return NULL;
62808     }
62809     if (pAllocationCallbacks->onRealloc != NULL) {
62810         return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
62811     }
62812     if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
62813         void* p2;
62814         p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
62815         if (p2 == NULL) {
62816             return NULL;
62817         }
62818         if (p != NULL) {
62819             DRMP3_COPY_MEMORY(p2, p, szOld);
62820             pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
62821         }
62822         return p2;
62823     }
62824     return NULL;
62825 }
62826 static void drmp3__free_from_callbacks(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
62827 {
62828     if (p == NULL || pAllocationCallbacks == NULL) {
62829         return;
62830     }
62831     if (pAllocationCallbacks->onFree != NULL) {
62832         pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
62833     }
62834 }
62835 static drmp3_allocation_callbacks drmp3_copy_allocation_callbacks_or_defaults(const drmp3_allocation_callbacks* pAllocationCallbacks)
62836 {
62837     if (pAllocationCallbacks != NULL) {
62838         return *pAllocationCallbacks;
62839     } else {
62840         drmp3_allocation_callbacks allocationCallbacks;
62841         allocationCallbacks.pUserData = NULL;
62842         allocationCallbacks.onMalloc  = drmp3__malloc_default;
62843         allocationCallbacks.onRealloc = drmp3__realloc_default;
62844         allocationCallbacks.onFree    = drmp3__free_default;
62845         return allocationCallbacks;
62846     }
62847 }
62848 static size_t drmp3__on_read(drmp3* pMP3, void* pBufferOut, size_t bytesToRead)
62849 {
62850     size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead);
62851     pMP3->streamCursor += bytesRead;
62852     return bytesRead;
62853 }
62854 static drmp3_bool32 drmp3__on_seek(drmp3* pMP3, int offset, drmp3_seek_origin origin)
62855 {
62856     DRMP3_ASSERT(offset >= 0);
62857     if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) {
62858         return DRMP3_FALSE;
62859     }
62860     if (origin == drmp3_seek_origin_start) {
62861         pMP3->streamCursor = (drmp3_uint64)offset;
62862     } else {
62863         pMP3->streamCursor += offset;
62864     }
62865     return DRMP3_TRUE;
62866 }
62867 static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_seek_origin origin)
62868 {
62869     if (offset <= 0x7FFFFFFF) {
62870         return drmp3__on_seek(pMP3, (int)offset, origin);
62871     }
62872     if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_start)) {
62873         return DRMP3_FALSE;
62874     }
62875     offset -= 0x7FFFFFFF;
62876     while (offset > 0) {
62877         if (offset <= 0x7FFFFFFF) {
62878             if (!drmp3__on_seek(pMP3, (int)offset, drmp3_seek_origin_current)) {
62879                 return DRMP3_FALSE;
62880             }
62881             offset = 0;
62882         } else {
62883             if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_current)) {
62884                 return DRMP3_FALSE;
62885             }
62886             offset -= 0x7FFFFFFF;
62887         }
62888     }
62889     return DRMP3_TRUE;
62890 }
62891 static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
62892 {
62893     drmp3_uint32 pcmFramesRead = 0;
62894     DRMP3_ASSERT(pMP3 != NULL);
62895     DRMP3_ASSERT(pMP3->onRead != NULL);
62896     if (pMP3->atEnd) {
62897         return 0;
62898     }
62899     for (;;) {
62900         drmp3dec_frame_info info;
62901         if (pMP3->dataSize < DRMP3_MIN_DATA_CHUNK_SIZE) {
62902             size_t bytesRead;
62903             if (pMP3->pData != NULL) {
62904                 memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
62905             }
62906             pMP3->dataConsumed = 0;
62907             if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) {
62908                 drmp3_uint8* pNewData;
62909                 size_t newDataCap;
62910                 newDataCap = DRMP3_DATA_CHUNK_SIZE;
62911                 pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
62912                 if (pNewData == NULL) {
62913                     return 0;
62914                 }
62915                 pMP3->pData = pNewData;
62916                 pMP3->dataCapacity = newDataCap;
62917             }
62918             bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
62919             if (bytesRead == 0) {
62920                 if (pMP3->dataSize == 0) {
62921                     pMP3->atEnd = DRMP3_TRUE;
62922                     return 0;
62923                 }
62924             }
62925             pMP3->dataSize += bytesRead;
62926         }
62927         if (pMP3->dataSize > INT_MAX) {
62928             pMP3->atEnd = DRMP3_TRUE;
62929             return 0;
62930         }
62931         DRMP3_ASSERT(pMP3->pData != NULL);
62932         DRMP3_ASSERT(pMP3->dataCapacity > 0);
62933         pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info);
62934         if (info.frame_bytes > 0) {
62935             pMP3->dataConsumed += (size_t)info.frame_bytes;
62936             pMP3->dataSize     -= (size_t)info.frame_bytes;
62937         }
62938         if (pcmFramesRead > 0) {
62939             pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
62940             pMP3->pcmFramesConsumedInMP3Frame = 0;
62941             pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
62942             pMP3->mp3FrameChannels = info.channels;
62943             pMP3->mp3FrameSampleRate = info.hz;
62944             break;
62945         } else if (info.frame_bytes == 0) {
62946             size_t bytesRead;
62947             memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
62948             pMP3->dataConsumed = 0;
62949             if (pMP3->dataCapacity == pMP3->dataSize) {
62950                 drmp3_uint8* pNewData;
62951                 size_t newDataCap;
62952                 newDataCap = pMP3->dataCapacity + DRMP3_DATA_CHUNK_SIZE;
62953                 pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
62954                 if (pNewData == NULL) {
62955                     return 0;
62956                 }
62957                 pMP3->pData = pNewData;
62958                 pMP3->dataCapacity = newDataCap;
62959             }
62960             bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
62961             if (bytesRead == 0) {
62962                 pMP3->atEnd = DRMP3_TRUE;
62963                 return 0;
62964             }
62965             pMP3->dataSize += bytesRead;
62966         }
62967     };
62968     return pcmFramesRead;
62969 }
62970 static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
62971 {
62972     drmp3_uint32 pcmFramesRead = 0;
62973     drmp3dec_frame_info info;
62974     DRMP3_ASSERT(pMP3 != NULL);
62975     DRMP3_ASSERT(pMP3->memory.pData != NULL);
62976     if (pMP3->atEnd) {
62977         return 0;
62978     }
62979     pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info);
62980     if (pcmFramesRead > 0) {
62981         pMP3->pcmFramesConsumedInMP3Frame  = 0;
62982         pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
62983         pMP3->mp3FrameChannels             = info.channels;
62984         pMP3->mp3FrameSampleRate           = info.hz;
62985     }
62986     pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
62987     return pcmFramesRead;
62988 }
62989 static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
62990 {
62991     if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) {
62992         return drmp3_decode_next_frame_ex__memory(pMP3, pPCMFrames);
62993     } else {
62994         return drmp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames);
62995     }
62996 }
62997 static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3)
62998 {
62999     DRMP3_ASSERT(pMP3 != NULL);
63000     return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames);
63001 }
63002 #if 0
63003 static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3)
63004 {
63005     drmp3_uint32 pcmFrameCount;
63006     DRMP3_ASSERT(pMP3 != NULL);
63007     pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL);
63008     if (pcmFrameCount == 0) {
63009         return 0;
63010     }
63011     pMP3->currentPCMFrame             += pcmFrameCount;
63012     pMP3->pcmFramesConsumedInMP3Frame  = pcmFrameCount;
63013     pMP3->pcmFramesRemainingInMP3Frame = 0;
63014     return pcmFrameCount;
63015 }
63016 #endif
63017 static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
63018 {
63019     DRMP3_ASSERT(pMP3 != NULL);
63020     DRMP3_ASSERT(onRead != NULL);
63021     drmp3dec_init(&pMP3->decoder);
63022     pMP3->onRead = onRead;
63023     pMP3->onSeek = onSeek;
63024     pMP3->pUserData = pUserData;
63025     pMP3->allocationCallbacks = drmp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
63026     if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) {
63027         return DRMP3_FALSE;
63028     }
63029     if (!drmp3_decode_next_frame(pMP3)) {
63030         drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks);
63031         return DRMP3_FALSE;
63032     }
63033     pMP3->channels   = pMP3->mp3FrameChannels;
63034     pMP3->sampleRate = pMP3->mp3FrameSampleRate;
63035     return DRMP3_TRUE;
63036 }
63037 DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
63038 {
63039     if (pMP3 == NULL || onRead == NULL) {
63040         return DRMP3_FALSE;
63041     }
63042     DRMP3_ZERO_OBJECT(pMP3);
63043     return drmp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks);
63044 }
63045 static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
63046 {
63047     drmp3* pMP3 = (drmp3*)pUserData;
63048     size_t bytesRemaining;
63049     DRMP3_ASSERT(pMP3 != NULL);
63050     DRMP3_ASSERT(pMP3->memory.dataSize >= pMP3->memory.currentReadPos);
63051     bytesRemaining = pMP3->memory.dataSize - pMP3->memory.currentReadPos;
63052     if (bytesToRead > bytesRemaining) {
63053         bytesToRead = bytesRemaining;
63054     }
63055     if (bytesToRead > 0) {
63056         DRMP3_COPY_MEMORY(pBufferOut, pMP3->memory.pData + pMP3->memory.currentReadPos, bytesToRead);
63057         pMP3->memory.currentReadPos += bytesToRead;
63058     }
63059     return bytesToRead;
63060 }
63061 static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3_seek_origin origin)
63062 {
63063     drmp3* pMP3 = (drmp3*)pUserData;
63064     DRMP3_ASSERT(pMP3 != NULL);
63065     if (origin == drmp3_seek_origin_current) {
63066         if (byteOffset > 0) {
63067             if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) {
63068                 byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos);
63069             }
63070         } else {
63071             if (pMP3->memory.currentReadPos < (size_t)-byteOffset) {
63072                 byteOffset = -(int)pMP3->memory.currentReadPos;
63073             }
63074         }
63075         pMP3->memory.currentReadPos += byteOffset;
63076     } else {
63077         if ((drmp3_uint32)byteOffset <= pMP3->memory.dataSize) {
63078             pMP3->memory.currentReadPos = byteOffset;
63079         } else {
63080             pMP3->memory.currentReadPos = pMP3->memory.dataSize;
63081         }
63082     }
63083     return DRMP3_TRUE;
63084 }
63085 DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks)
63086 {
63087     if (pMP3 == NULL) {
63088         return DRMP3_FALSE;
63089     }
63090     DRMP3_ZERO_OBJECT(pMP3);
63091     if (pData == NULL || dataSize == 0) {
63092         return DRMP3_FALSE;
63093     }
63094     pMP3->memory.pData = (const drmp3_uint8*)pData;
63095     pMP3->memory.dataSize = dataSize;
63096     pMP3->memory.currentReadPos = 0;
63097     return drmp3_init_internal(pMP3, drmp3__on_read_memory, drmp3__on_seek_memory, pMP3, pAllocationCallbacks);
63098 }
63099 #ifndef DR_MP3_NO_STDIO
63100 #include <stdio.h>
63101 #include <wchar.h>
63102 #include <errno.h>
63103 static drmp3_result drmp3_result_from_errno(int e)
63104 {
63105     switch (e)
63106     {
63107         case 0: return DRMP3_SUCCESS;
63108     #ifdef EPERM
63109         case EPERM: return DRMP3_INVALID_OPERATION;
63110     #endif
63111     #ifdef ENOENT
63112         case ENOENT: return DRMP3_DOES_NOT_EXIST;
63113     #endif
63114     #ifdef ESRCH
63115         case ESRCH: return DRMP3_DOES_NOT_EXIST;
63116     #endif
63117     #ifdef EINTR
63118         case EINTR: return DRMP3_INTERRUPT;
63119     #endif
63120     #ifdef EIO
63121         case EIO: return DRMP3_IO_ERROR;
63122     #endif
63123     #ifdef ENXIO
63124         case ENXIO: return DRMP3_DOES_NOT_EXIST;
63125     #endif
63126     #ifdef E2BIG
63127         case E2BIG: return DRMP3_INVALID_ARGS;
63128     #endif
63129     #ifdef ENOEXEC
63130         case ENOEXEC: return DRMP3_INVALID_FILE;
63131     #endif
63132     #ifdef EBADF
63133         case EBADF: return DRMP3_INVALID_FILE;
63134     #endif
63135     #ifdef ECHILD
63136         case ECHILD: return DRMP3_ERROR;
63137     #endif
63138     #ifdef EAGAIN
63139         case EAGAIN: return DRMP3_UNAVAILABLE;
63140     #endif
63141     #ifdef ENOMEM
63142         case ENOMEM: return DRMP3_OUT_OF_MEMORY;
63143     #endif
63144     #ifdef EACCES
63145         case EACCES: return DRMP3_ACCESS_DENIED;
63146     #endif
63147     #ifdef EFAULT
63148         case EFAULT: return DRMP3_BAD_ADDRESS;
63149     #endif
63150     #ifdef ENOTBLK
63151         case ENOTBLK: return DRMP3_ERROR;
63152     #endif
63153     #ifdef EBUSY
63154         case EBUSY: return DRMP3_BUSY;
63155     #endif
63156     #ifdef EEXIST
63157         case EEXIST: return DRMP3_ALREADY_EXISTS;
63158     #endif
63159     #ifdef EXDEV
63160         case EXDEV: return DRMP3_ERROR;
63161     #endif
63162     #ifdef ENODEV
63163         case ENODEV: return DRMP3_DOES_NOT_EXIST;
63164     #endif
63165     #ifdef ENOTDIR
63166         case ENOTDIR: return DRMP3_NOT_DIRECTORY;
63167     #endif
63168     #ifdef EISDIR
63169         case EISDIR: return DRMP3_IS_DIRECTORY;
63170     #endif
63171     #ifdef EINVAL
63172         case EINVAL: return DRMP3_INVALID_ARGS;
63173     #endif
63174     #ifdef ENFILE
63175         case ENFILE: return DRMP3_TOO_MANY_OPEN_FILES;
63176     #endif
63177     #ifdef EMFILE
63178         case EMFILE: return DRMP3_TOO_MANY_OPEN_FILES;
63179     #endif
63180     #ifdef ENOTTY
63181         case ENOTTY: return DRMP3_INVALID_OPERATION;
63182     #endif
63183     #ifdef ETXTBSY
63184         case ETXTBSY: return DRMP3_BUSY;
63185     #endif
63186     #ifdef EFBIG
63187         case EFBIG: return DRMP3_TOO_BIG;
63188     #endif
63189     #ifdef ENOSPC
63190         case ENOSPC: return DRMP3_NO_SPACE;
63191     #endif
63192     #ifdef ESPIPE
63193         case ESPIPE: return DRMP3_BAD_SEEK;
63194     #endif
63195     #ifdef EROFS
63196         case EROFS: return DRMP3_ACCESS_DENIED;
63197     #endif
63198     #ifdef EMLINK
63199         case EMLINK: return DRMP3_TOO_MANY_LINKS;
63200     #endif
63201     #ifdef EPIPE
63202         case EPIPE: return DRMP3_BAD_PIPE;
63203     #endif
63204     #ifdef EDOM
63205         case EDOM: return DRMP3_OUT_OF_RANGE;
63206     #endif
63207     #ifdef ERANGE
63208         case ERANGE: return DRMP3_OUT_OF_RANGE;
63209     #endif
63210     #ifdef EDEADLK
63211         case EDEADLK: return DRMP3_DEADLOCK;
63212     #endif
63213     #ifdef ENAMETOOLONG
63214         case ENAMETOOLONG: return DRMP3_PATH_TOO_LONG;
63215     #endif
63216     #ifdef ENOLCK
63217         case ENOLCK: return DRMP3_ERROR;
63218     #endif
63219     #ifdef ENOSYS
63220         case ENOSYS: return DRMP3_NOT_IMPLEMENTED;
63221     #endif
63222     #ifdef ENOTEMPTY
63223         case ENOTEMPTY: return DRMP3_DIRECTORY_NOT_EMPTY;
63224     #endif
63225     #ifdef ELOOP
63226         case ELOOP: return DRMP3_TOO_MANY_LINKS;
63227     #endif
63228     #ifdef ENOMSG
63229         case ENOMSG: return DRMP3_NO_MESSAGE;
63230     #endif
63231     #ifdef EIDRM
63232         case EIDRM: return DRMP3_ERROR;
63233     #endif
63234     #ifdef ECHRNG
63235         case ECHRNG: return DRMP3_ERROR;
63236     #endif
63237     #ifdef EL2NSYNC
63238         case EL2NSYNC: return DRMP3_ERROR;
63239     #endif
63240     #ifdef EL3HLT
63241         case EL3HLT: return DRMP3_ERROR;
63242     #endif
63243     #ifdef EL3RST
63244         case EL3RST: return DRMP3_ERROR;
63245     #endif
63246     #ifdef ELNRNG
63247         case ELNRNG: return DRMP3_OUT_OF_RANGE;
63248     #endif
63249     #ifdef EUNATCH
63250         case EUNATCH: return DRMP3_ERROR;
63251     #endif
63252     #ifdef ENOCSI
63253         case ENOCSI: return DRMP3_ERROR;
63254     #endif
63255     #ifdef EL2HLT
63256         case EL2HLT: return DRMP3_ERROR;
63257     #endif
63258     #ifdef EBADE
63259         case EBADE: return DRMP3_ERROR;
63260     #endif
63261     #ifdef EBADR
63262         case EBADR: return DRMP3_ERROR;
63263     #endif
63264     #ifdef EXFULL
63265         case EXFULL: return DRMP3_ERROR;
63266     #endif
63267     #ifdef ENOANO
63268         case ENOANO: return DRMP3_ERROR;
63269     #endif
63270     #ifdef EBADRQC
63271         case EBADRQC: return DRMP3_ERROR;
63272     #endif
63273     #ifdef EBADSLT
63274         case EBADSLT: return DRMP3_ERROR;
63275     #endif
63276     #ifdef EBFONT
63277         case EBFONT: return DRMP3_INVALID_FILE;
63278     #endif
63279     #ifdef ENOSTR
63280         case ENOSTR: return DRMP3_ERROR;
63281     #endif
63282     #ifdef ENODATA
63283         case ENODATA: return DRMP3_NO_DATA_AVAILABLE;
63284     #endif
63285     #ifdef ETIME
63286         case ETIME: return DRMP3_TIMEOUT;
63287     #endif
63288     #ifdef ENOSR
63289         case ENOSR: return DRMP3_NO_DATA_AVAILABLE;
63290     #endif
63291     #ifdef ENONET
63292         case ENONET: return DRMP3_NO_NETWORK;
63293     #endif
63294     #ifdef ENOPKG
63295         case ENOPKG: return DRMP3_ERROR;
63296     #endif
63297     #ifdef EREMOTE
63298         case EREMOTE: return DRMP3_ERROR;
63299     #endif
63300     #ifdef ENOLINK
63301         case ENOLINK: return DRMP3_ERROR;
63302     #endif
63303     #ifdef EADV
63304         case EADV: return DRMP3_ERROR;
63305     #endif
63306     #ifdef ESRMNT
63307         case ESRMNT: return DRMP3_ERROR;
63308     #endif
63309     #ifdef ECOMM
63310         case ECOMM: return DRMP3_ERROR;
63311     #endif
63312     #ifdef EPROTO
63313         case EPROTO: return DRMP3_ERROR;
63314     #endif
63315     #ifdef EMULTIHOP
63316         case EMULTIHOP: return DRMP3_ERROR;
63317     #endif
63318     #ifdef EDOTDOT
63319         case EDOTDOT: return DRMP3_ERROR;
63320     #endif
63321     #ifdef EBADMSG
63322         case EBADMSG: return DRMP3_BAD_MESSAGE;
63323     #endif
63324     #ifdef EOVERFLOW
63325         case EOVERFLOW: return DRMP3_TOO_BIG;
63326     #endif
63327     #ifdef ENOTUNIQ
63328         case ENOTUNIQ: return DRMP3_NOT_UNIQUE;
63329     #endif
63330     #ifdef EBADFD
63331         case EBADFD: return DRMP3_ERROR;
63332     #endif
63333     #ifdef EREMCHG
63334         case EREMCHG: return DRMP3_ERROR;
63335     #endif
63336     #ifdef ELIBACC
63337         case ELIBACC: return DRMP3_ACCESS_DENIED;
63338     #endif
63339     #ifdef ELIBBAD
63340         case ELIBBAD: return DRMP3_INVALID_FILE;
63341     #endif
63342     #ifdef ELIBSCN
63343         case ELIBSCN: return DRMP3_INVALID_FILE;
63344     #endif
63345     #ifdef ELIBMAX
63346         case ELIBMAX: return DRMP3_ERROR;
63347     #endif
63348     #ifdef ELIBEXEC
63349         case ELIBEXEC: return DRMP3_ERROR;
63350     #endif
63351     #ifdef EILSEQ
63352         case EILSEQ: return DRMP3_INVALID_DATA;
63353     #endif
63354     #ifdef ERESTART
63355         case ERESTART: return DRMP3_ERROR;
63356     #endif
63357     #ifdef ESTRPIPE
63358         case ESTRPIPE: return DRMP3_ERROR;
63359     #endif
63360     #ifdef EUSERS
63361         case EUSERS: return DRMP3_ERROR;
63362     #endif
63363     #ifdef ENOTSOCK
63364         case ENOTSOCK: return DRMP3_NOT_SOCKET;
63365     #endif
63366     #ifdef EDESTADDRREQ
63367         case EDESTADDRREQ: return DRMP3_NO_ADDRESS;
63368     #endif
63369     #ifdef EMSGSIZE
63370         case EMSGSIZE: return DRMP3_TOO_BIG;
63371     #endif
63372     #ifdef EPROTOTYPE
63373         case EPROTOTYPE: return DRMP3_BAD_PROTOCOL;
63374     #endif
63375     #ifdef ENOPROTOOPT
63376         case ENOPROTOOPT: return DRMP3_PROTOCOL_UNAVAILABLE;
63377     #endif
63378     #ifdef EPROTONOSUPPORT
63379         case EPROTONOSUPPORT: return DRMP3_PROTOCOL_NOT_SUPPORTED;
63380     #endif
63381     #ifdef ESOCKTNOSUPPORT
63382         case ESOCKTNOSUPPORT: return DRMP3_SOCKET_NOT_SUPPORTED;
63383     #endif
63384     #ifdef EOPNOTSUPP
63385         case EOPNOTSUPP: return DRMP3_INVALID_OPERATION;
63386     #endif
63387     #ifdef EPFNOSUPPORT
63388         case EPFNOSUPPORT: return DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED;
63389     #endif
63390     #ifdef EAFNOSUPPORT
63391         case EAFNOSUPPORT: return DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED;
63392     #endif
63393     #ifdef EADDRINUSE
63394         case EADDRINUSE: return DRMP3_ALREADY_IN_USE;
63395     #endif
63396     #ifdef EADDRNOTAVAIL
63397         case EADDRNOTAVAIL: return DRMP3_ERROR;
63398     #endif
63399     #ifdef ENETDOWN
63400         case ENETDOWN: return DRMP3_NO_NETWORK;
63401     #endif
63402     #ifdef ENETUNREACH
63403         case ENETUNREACH: return DRMP3_NO_NETWORK;
63404     #endif
63405     #ifdef ENETRESET
63406         case ENETRESET: return DRMP3_NO_NETWORK;
63407     #endif
63408     #ifdef ECONNABORTED
63409         case ECONNABORTED: return DRMP3_NO_NETWORK;
63410     #endif
63411     #ifdef ECONNRESET
63412         case ECONNRESET: return DRMP3_CONNECTION_RESET;
63413     #endif
63414     #ifdef ENOBUFS
63415         case ENOBUFS: return DRMP3_NO_SPACE;
63416     #endif
63417     #ifdef EISCONN
63418         case EISCONN: return DRMP3_ALREADY_CONNECTED;
63419     #endif
63420     #ifdef ENOTCONN
63421         case ENOTCONN: return DRMP3_NOT_CONNECTED;
63422     #endif
63423     #ifdef ESHUTDOWN
63424         case ESHUTDOWN: return DRMP3_ERROR;
63425     #endif
63426     #ifdef ETOOMANYREFS
63427         case ETOOMANYREFS: return DRMP3_ERROR;
63428     #endif
63429     #ifdef ETIMEDOUT
63430         case ETIMEDOUT: return DRMP3_TIMEOUT;
63431     #endif
63432     #ifdef ECONNREFUSED
63433         case ECONNREFUSED: return DRMP3_CONNECTION_REFUSED;
63434     #endif
63435     #ifdef EHOSTDOWN
63436         case EHOSTDOWN: return DRMP3_NO_HOST;
63437     #endif
63438     #ifdef EHOSTUNREACH
63439         case EHOSTUNREACH: return DRMP3_NO_HOST;
63440     #endif
63441     #ifdef EALREADY
63442         case EALREADY: return DRMP3_IN_PROGRESS;
63443     #endif
63444     #ifdef EINPROGRESS
63445         case EINPROGRESS: return DRMP3_IN_PROGRESS;
63446     #endif
63447     #ifdef ESTALE
63448         case ESTALE: return DRMP3_INVALID_FILE;
63449     #endif
63450     #ifdef EUCLEAN
63451         case EUCLEAN: return DRMP3_ERROR;
63452     #endif
63453     #ifdef ENOTNAM
63454         case ENOTNAM: return DRMP3_ERROR;
63455     #endif
63456     #ifdef ENAVAIL
63457         case ENAVAIL: return DRMP3_ERROR;
63458     #endif
63459     #ifdef EISNAM
63460         case EISNAM: return DRMP3_ERROR;
63461     #endif
63462     #ifdef EREMOTEIO
63463         case EREMOTEIO: return DRMP3_IO_ERROR;
63464     #endif
63465     #ifdef EDQUOT
63466         case EDQUOT: return DRMP3_NO_SPACE;
63467     #endif
63468     #ifdef ENOMEDIUM
63469         case ENOMEDIUM: return DRMP3_DOES_NOT_EXIST;
63470     #endif
63471     #ifdef EMEDIUMTYPE
63472         case EMEDIUMTYPE: return DRMP3_ERROR;
63473     #endif
63474     #ifdef ECANCELED
63475         case ECANCELED: return DRMP3_CANCELLED;
63476     #endif
63477     #ifdef ENOKEY
63478         case ENOKEY: return DRMP3_ERROR;
63479     #endif
63480     #ifdef EKEYEXPIRED
63481         case EKEYEXPIRED: return DRMP3_ERROR;
63482     #endif
63483     #ifdef EKEYREVOKED
63484         case EKEYREVOKED: return DRMP3_ERROR;
63485     #endif
63486     #ifdef EKEYREJECTED
63487         case EKEYREJECTED: return DRMP3_ERROR;
63488     #endif
63489     #ifdef EOWNERDEAD
63490         case EOWNERDEAD: return DRMP3_ERROR;
63491     #endif
63492     #ifdef ENOTRECOVERABLE
63493         case ENOTRECOVERABLE: return DRMP3_ERROR;
63494     #endif
63495     #ifdef ERFKILL
63496         case ERFKILL: return DRMP3_ERROR;
63497     #endif
63498     #ifdef EHWPOISON
63499         case EHWPOISON: return DRMP3_ERROR;
63500     #endif
63501         default: return DRMP3_ERROR;
63502     }
63503 }
63504 static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
63505 {
63506 #if defined(_MSC_VER) && _MSC_VER >= 1400
63507     errno_t err;
63508 #endif
63509     if (ppFile != NULL) {
63510         *ppFile = NULL;
63511     }
63512     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
63513         return DRMP3_INVALID_ARGS;
63514     }
63515 #if defined(_MSC_VER) && _MSC_VER >= 1400
63516     err = fopen_s(ppFile, pFilePath, pOpenMode);
63517     if (err != 0) {
63518         return drmp3_result_from_errno(err);
63519     }
63520 #else
63521 #if defined(_WIN32) || defined(__APPLE__)
63522     *ppFile = fopen(pFilePath, pOpenMode);
63523 #else
63524     #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
63525         *ppFile = fopen64(pFilePath, pOpenMode);
63526     #else
63527         *ppFile = fopen(pFilePath, pOpenMode);
63528     #endif
63529 #endif
63530     if (*ppFile == NULL) {
63531         drmp3_result result = drmp3_result_from_errno(errno);
63532         if (result == DRMP3_SUCCESS) {
63533             result = DRMP3_ERROR;
63534         }
63535         return result;
63536     }
63537 #endif
63538     return DRMP3_SUCCESS;
63539 }
63540 #if defined(_WIN32)
63541     #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
63542         #define DRMP3_HAS_WFOPEN
63543     #endif
63544 #endif
63545 static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drmp3_allocation_callbacks* pAllocationCallbacks)
63546 {
63547     if (ppFile != NULL) {
63548         *ppFile = NULL;
63549     }
63550     if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
63551         return DRMP3_INVALID_ARGS;
63552     }
63553 #if defined(DRMP3_HAS_WFOPEN)
63554     {
63555     #if defined(_MSC_VER) && _MSC_VER >= 1400
63556         errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
63557         if (err != 0) {
63558             return drmp3_result_from_errno(err);
63559         }
63560     #else
63561         *ppFile = _wfopen(pFilePath, pOpenMode);
63562         if (*ppFile == NULL) {
63563             return drmp3_result_from_errno(errno);
63564         }
63565     #endif
63566         (void)pAllocationCallbacks;
63567     }
63568 #else
63569     {
63570         mbstate_t mbs;
63571         size_t lenMB;
63572         const wchar_t* pFilePathTemp = pFilePath;
63573         char* pFilePathMB = NULL;
63574         char pOpenModeMB[32] = {0};
63575         DRMP3_ZERO_OBJECT(&mbs);
63576         lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
63577         if (lenMB == (size_t)-1) {
63578             return drmp3_result_from_errno(errno);
63579         }
63580         pFilePathMB = (char*)drmp3__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
63581         if (pFilePathMB == NULL) {
63582             return DRMP3_OUT_OF_MEMORY;
63583         }
63584         pFilePathTemp = pFilePath;
63585         DRMP3_ZERO_OBJECT(&mbs);
63586         wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
63587         {
63588             size_t i = 0;
63589             for (;;) {
63590                 if (pOpenMode[i] == 0) {
63591                     pOpenModeMB[i] = '\0';
63592                     break;
63593                 }
63594                 pOpenModeMB[i] = (char)pOpenMode[i];
63595                 i += 1;
63596             }
63597         }
63598         *ppFile = fopen(pFilePathMB, pOpenModeMB);
63599         drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
63600     }
63601     if (*ppFile == NULL) {
63602         return DRMP3_ERROR;
63603     }
63604 #endif
63605     return DRMP3_SUCCESS;
63606 }
63607 static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
63608 {
63609     return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
63610 }
63611 static drmp3_bool32 drmp3__on_seek_stdio(void* pUserData, int offset, drmp3_seek_origin origin)
63612 {
63613     return fseek((FILE*)pUserData, offset, (origin == drmp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
63614 }
63615 DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
63616 {
63617     drmp3_bool32 result;
63618     FILE* pFile;
63619     if (drmp3_fopen(&pFile, pFilePath, "rb") != DRMP3_SUCCESS) {
63620         return DRMP3_FALSE;
63621     }
63622     result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
63623     if (result != DRMP3_TRUE) {
63624         fclose(pFile);
63625         return result;
63626     }
63627     return DRMP3_TRUE;
63628 }
63629 DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
63630 {
63631     drmp3_bool32 result;
63632     FILE* pFile;
63633     if (drmp3_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != DRMP3_SUCCESS) {
63634         return DRMP3_FALSE;
63635     }
63636     result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
63637     if (result != DRMP3_TRUE) {
63638         fclose(pFile);
63639         return result;
63640     }
63641     return DRMP3_TRUE;
63642 }
63643 #endif
63644 DRMP3_API void drmp3_uninit(drmp3* pMP3)
63645 {
63646     if (pMP3 == NULL) {
63647         return;
63648     }
63649 #ifndef DR_MP3_NO_STDIO
63650     if (pMP3->onRead == drmp3__on_read_stdio) {
63651         FILE* pFile = (FILE*)pMP3->pUserData;
63652         if (pFile != NULL) {
63653             fclose(pFile);
63654             pMP3->pUserData = NULL;
63655         }
63656     }
63657 #endif
63658     drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks);
63659 }
63660 #if defined(DR_MP3_FLOAT_OUTPUT)
63661 static void drmp3_f32_to_s16(drmp3_int16* dst, const float* src, drmp3_uint64 sampleCount)
63662 {
63663     drmp3_uint64 i;
63664     drmp3_uint64 i4;
63665     drmp3_uint64 sampleCount4;
63666     i = 0;
63667     sampleCount4 = sampleCount >> 2;
63668     for (i4 = 0; i4 < sampleCount4; i4 += 1) {
63669         float x0 = src[i+0];
63670         float x1 = src[i+1];
63671         float x2 = src[i+2];
63672         float x3 = src[i+3];
63673         x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0));
63674         x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1));
63675         x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2));
63676         x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3));
63677         x0 = x0 * 32767.0f;
63678         x1 = x1 * 32767.0f;
63679         x2 = x2 * 32767.0f;
63680         x3 = x3 * 32767.0f;
63681         dst[i+0] = (drmp3_int16)x0;
63682         dst[i+1] = (drmp3_int16)x1;
63683         dst[i+2] = (drmp3_int16)x2;
63684         dst[i+3] = (drmp3_int16)x3;
63685         i += 4;
63686     }
63687     for (; i < sampleCount; i += 1) {
63688         float x = src[i];
63689         x = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
63690         x = x * 32767.0f;
63691         dst[i] = (drmp3_int16)x;
63692     }
63693 }
63694 #endif
63695 #if !defined(DR_MP3_FLOAT_OUTPUT)
63696 static void drmp3_s16_to_f32(float* dst, const drmp3_int16* src, drmp3_uint64 sampleCount)
63697 {
63698     drmp3_uint64 i;
63699     for (i = 0; i < sampleCount; i += 1) {
63700         float x = (float)src[i];
63701         x = x * 0.000030517578125f;
63702         dst[i] = x;
63703     }
63704 }
63705 #endif
63706 static drmp3_uint64 drmp3_read_pcm_frames_raw(drmp3* pMP3, drmp3_uint64 framesToRead, void* pBufferOut)
63707 {
63708     drmp3_uint64 totalFramesRead = 0;
63709     DRMP3_ASSERT(pMP3 != NULL);
63710     DRMP3_ASSERT(pMP3->onRead != NULL);
63711     while (framesToRead > 0) {
63712         drmp3_uint32 framesToConsume = (drmp3_uint32)DRMP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead);
63713         if (pBufferOut != NULL) {
63714         #if defined(DR_MP3_FLOAT_OUTPUT)
63715             float* pFramesOutF32 = (float*)DRMP3_OFFSET_PTR(pBufferOut,          sizeof(float) * totalFramesRead                   * pMP3->channels);
63716             float* pFramesInF32  = (float*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels);
63717             DRMP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels);
63718         #else
63719             drmp3_int16* pFramesOutS16 = (drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut,          sizeof(drmp3_int16) * totalFramesRead                   * pMP3->channels);
63720             drmp3_int16* pFramesInS16  = (drmp3_int16*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(drmp3_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels);
63721             DRMP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(drmp3_int16) * framesToConsume * pMP3->channels);
63722         #endif
63723         }
63724         pMP3->currentPCMFrame              += framesToConsume;
63725         pMP3->pcmFramesConsumedInMP3Frame  += framesToConsume;
63726         pMP3->pcmFramesRemainingInMP3Frame -= framesToConsume;
63727         totalFramesRead                    += framesToConsume;
63728         framesToRead                       -= framesToConsume;
63729         if (framesToRead == 0) {
63730             break;
63731         }
63732         DRMP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0);
63733         if (drmp3_decode_next_frame(pMP3) == 0) {
63734             break;
63735         }
63736     }
63737     return totalFramesRead;
63738 }
63739 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut)
63740 {
63741     if (pMP3 == NULL || pMP3->onRead == NULL) {
63742         return 0;
63743     }
63744 #if defined(DR_MP3_FLOAT_OUTPUT)
63745     return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut);
63746 #else
63747     {
63748         drmp3_int16 pTempS16[8192];
63749         drmp3_uint64 totalPCMFramesRead = 0;
63750         while (totalPCMFramesRead < framesToRead) {
63751             drmp3_uint64 framesJustRead;
63752             drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead;
63753             drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempS16) / pMP3->channels;
63754             if (framesToReadNow > framesRemaining) {
63755                 framesToReadNow = framesRemaining;
63756             }
63757             framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempS16);
63758             if (framesJustRead == 0) {
63759                 break;
63760             }
63761             drmp3_s16_to_f32((float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels);
63762             totalPCMFramesRead += framesJustRead;
63763         }
63764         return totalPCMFramesRead;
63765     }
63766 #endif
63767 }
63768 DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut)
63769 {
63770     if (pMP3 == NULL || pMP3->onRead == NULL) {
63771         return 0;
63772     }
63773 #if !defined(DR_MP3_FLOAT_OUTPUT)
63774     return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut);
63775 #else
63776     {
63777         float pTempF32[4096];
63778         drmp3_uint64 totalPCMFramesRead = 0;
63779         while (totalPCMFramesRead < framesToRead) {
63780             drmp3_uint64 framesJustRead;
63781             drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead;
63782             drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempF32) / pMP3->channels;
63783             if (framesToReadNow > framesRemaining) {
63784                 framesToReadNow = framesRemaining;
63785             }
63786             framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempF32);
63787             if (framesJustRead == 0) {
63788                 break;
63789             }
63790             drmp3_f32_to_s16((drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(drmp3_int16) * totalPCMFramesRead * pMP3->channels), pTempF32, framesJustRead * pMP3->channels);
63791             totalPCMFramesRead += framesJustRead;
63792         }
63793         return totalPCMFramesRead;
63794     }
63795 #endif
63796 }
63797 static void drmp3_reset(drmp3* pMP3)
63798 {
63799     DRMP3_ASSERT(pMP3 != NULL);
63800     pMP3->pcmFramesConsumedInMP3Frame = 0;
63801     pMP3->pcmFramesRemainingInMP3Frame = 0;
63802     pMP3->currentPCMFrame = 0;
63803     pMP3->dataSize = 0;
63804     pMP3->atEnd = DRMP3_FALSE;
63805     drmp3dec_init(&pMP3->decoder);
63806 }
63807 static drmp3_bool32 drmp3_seek_to_start_of_stream(drmp3* pMP3)
63808 {
63809     DRMP3_ASSERT(pMP3 != NULL);
63810     DRMP3_ASSERT(pMP3->onSeek != NULL);
63811     if (!drmp3__on_seek(pMP3, 0, drmp3_seek_origin_start)) {
63812         return DRMP3_FALSE;
63813     }
63814     drmp3_reset(pMP3);
63815     return DRMP3_TRUE;
63816 }
63817 static drmp3_bool32 drmp3_seek_forward_by_pcm_frames__brute_force(drmp3* pMP3, drmp3_uint64 frameOffset)
63818 {
63819     drmp3_uint64 framesRead;
63820 #if defined(DR_MP3_FLOAT_OUTPUT)
63821     framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL);
63822 #else
63823     framesRead = drmp3_read_pcm_frames_s16(pMP3, frameOffset, NULL);
63824 #endif
63825     if (framesRead != frameOffset) {
63826         return DRMP3_FALSE;
63827     }
63828     return DRMP3_TRUE;
63829 }
63830 static drmp3_bool32 drmp3_seek_to_pcm_frame__brute_force(drmp3* pMP3, drmp3_uint64 frameIndex)
63831 {
63832     DRMP3_ASSERT(pMP3 != NULL);
63833     if (frameIndex == pMP3->currentPCMFrame) {
63834         return DRMP3_TRUE;
63835     }
63836     if (frameIndex < pMP3->currentPCMFrame) {
63837         if (!drmp3_seek_to_start_of_stream(pMP3)) {
63838             return DRMP3_FALSE;
63839         }
63840     }
63841     DRMP3_ASSERT(frameIndex >= pMP3->currentPCMFrame);
63842     return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, (frameIndex - pMP3->currentPCMFrame));
63843 }
63844 static drmp3_bool32 drmp3_find_closest_seek_point(drmp3* pMP3, drmp3_uint64 frameIndex, drmp3_uint32* pSeekPointIndex)
63845 {
63846     drmp3_uint32 iSeekPoint;
63847     DRMP3_ASSERT(pSeekPointIndex != NULL);
63848     *pSeekPointIndex = 0;
63849     if (frameIndex < pMP3->pSeekPoints[0].pcmFrameIndex) {
63850         return DRMP3_FALSE;
63851     }
63852     for (iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) {
63853         if (pMP3->pSeekPoints[iSeekPoint].pcmFrameIndex > frameIndex) {
63854             break;
63855         }
63856         *pSeekPointIndex = iSeekPoint;
63857     }
63858     return DRMP3_TRUE;
63859 }
63860 static drmp3_bool32 drmp3_seek_to_pcm_frame__seek_table(drmp3* pMP3, drmp3_uint64 frameIndex)
63861 {
63862     drmp3_seek_point seekPoint;
63863     drmp3_uint32 priorSeekPointIndex;
63864     drmp3_uint16 iMP3Frame;
63865     drmp3_uint64 leftoverFrames;
63866     DRMP3_ASSERT(pMP3 != NULL);
63867     DRMP3_ASSERT(pMP3->pSeekPoints != NULL);
63868     DRMP3_ASSERT(pMP3->seekPointCount > 0);
63869     if (drmp3_find_closest_seek_point(pMP3, frameIndex, &priorSeekPointIndex)) {
63870         seekPoint = pMP3->pSeekPoints[priorSeekPointIndex];
63871     } else {
63872         seekPoint.seekPosInBytes     = 0;
63873         seekPoint.pcmFrameIndex      = 0;
63874         seekPoint.mp3FramesToDiscard = 0;
63875         seekPoint.pcmFramesToDiscard = 0;
63876     }
63877     if (!drmp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, drmp3_seek_origin_start)) {
63878         return DRMP3_FALSE;
63879     }
63880     drmp3_reset(pMP3);
63881     for (iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) {
63882         drmp3_uint32 pcmFramesRead;
63883         drmp3d_sample_t* pPCMFrames;
63884         pPCMFrames = NULL;
63885         if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) {
63886             pPCMFrames = (drmp3d_sample_t*)pMP3->pcmFrames;
63887         }
63888         pcmFramesRead = drmp3_decode_next_frame_ex(pMP3, pPCMFrames);
63889         if (pcmFramesRead == 0) {
63890             return DRMP3_FALSE;
63891         }
63892     }
63893     pMP3->currentPCMFrame = seekPoint.pcmFrameIndex - seekPoint.pcmFramesToDiscard;
63894     leftoverFrames = frameIndex - pMP3->currentPCMFrame;
63895     return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, leftoverFrames);
63896 }
63897 DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex)
63898 {
63899     if (pMP3 == NULL || pMP3->onSeek == NULL) {
63900         return DRMP3_FALSE;
63901     }
63902     if (frameIndex == 0) {
63903         return drmp3_seek_to_start_of_stream(pMP3);
63904     }
63905     if (pMP3->pSeekPoints != NULL && pMP3->seekPointCount > 0) {
63906         return drmp3_seek_to_pcm_frame__seek_table(pMP3, frameIndex);
63907     } else {
63908         return drmp3_seek_to_pcm_frame__brute_force(pMP3, frameIndex);
63909     }
63910 }
63911 DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount)
63912 {
63913     drmp3_uint64 currentPCMFrame;
63914     drmp3_uint64 totalPCMFrameCount;
63915     drmp3_uint64 totalMP3FrameCount;
63916     if (pMP3 == NULL) {
63917         return DRMP3_FALSE;
63918     }
63919     if (pMP3->onSeek == NULL) {
63920         return DRMP3_FALSE;
63921     }
63922     currentPCMFrame = pMP3->currentPCMFrame;
63923     if (!drmp3_seek_to_start_of_stream(pMP3)) {
63924         return DRMP3_FALSE;
63925     }
63926     totalPCMFrameCount = 0;
63927     totalMP3FrameCount = 0;
63928     for (;;) {
63929         drmp3_uint32 pcmFramesInCurrentMP3Frame;
63930         pcmFramesInCurrentMP3Frame = drmp3_decode_next_frame_ex(pMP3, NULL);
63931         if (pcmFramesInCurrentMP3Frame == 0) {
63932             break;
63933         }
63934         totalPCMFrameCount += pcmFramesInCurrentMP3Frame;
63935         totalMP3FrameCount += 1;
63936     }
63937     if (!drmp3_seek_to_start_of_stream(pMP3)) {
63938         return DRMP3_FALSE;
63939     }
63940     if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) {
63941         return DRMP3_FALSE;
63942     }
63943     if (pMP3FrameCount != NULL) {
63944         *pMP3FrameCount = totalMP3FrameCount;
63945     }
63946     if (pPCMFrameCount != NULL) {
63947         *pPCMFrameCount = totalPCMFrameCount;
63948     }
63949     return DRMP3_TRUE;
63950 }
63951 DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3)
63952 {
63953     drmp3_uint64 totalPCMFrameCount;
63954     if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) {
63955         return 0;
63956     }
63957     return totalPCMFrameCount;
63958 }
63959 DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3)
63960 {
63961     drmp3_uint64 totalMP3FrameCount;
63962     if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, NULL)) {
63963         return 0;
63964     }
63965     return totalMP3FrameCount;
63966 }
63967 static void drmp3__accumulate_running_pcm_frame_count(drmp3* pMP3, drmp3_uint32 pcmFrameCountIn, drmp3_uint64* pRunningPCMFrameCount, float* pRunningPCMFrameCountFractionalPart)
63968 {
63969     float srcRatio;
63970     float pcmFrameCountOutF;
63971     drmp3_uint32 pcmFrameCountOut;
63972     srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate;
63973     DRMP3_ASSERT(srcRatio > 0);
63974     pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio);
63975     pcmFrameCountOut  = (drmp3_uint32)pcmFrameCountOutF;
63976     *pRunningPCMFrameCountFractionalPart = pcmFrameCountOutF - pcmFrameCountOut;
63977     *pRunningPCMFrameCount += pcmFrameCountOut;
63978 }
63979 typedef struct
63980 {
63981     drmp3_uint64 bytePos;
63982     drmp3_uint64 pcmFrameIndex;
63983 } drmp3__seeking_mp3_frame_info;
63984 DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints)
63985 {
63986     drmp3_uint32 seekPointCount;
63987     drmp3_uint64 currentPCMFrame;
63988     drmp3_uint64 totalMP3FrameCount;
63989     drmp3_uint64 totalPCMFrameCount;
63990     if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) {
63991         return DRMP3_FALSE;
63992     }
63993     seekPointCount = *pSeekPointCount;
63994     if (seekPointCount == 0) {
63995         return DRMP3_FALSE;
63996     }
63997     currentPCMFrame = pMP3->currentPCMFrame;
63998     if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) {
63999         return DRMP3_FALSE;
64000     }
64001     if (totalMP3FrameCount < DRMP3_SEEK_LEADING_MP3_FRAMES+1) {
64002         seekPointCount = 1;
64003         pSeekPoints[0].seekPosInBytes     = 0;
64004         pSeekPoints[0].pcmFrameIndex      = 0;
64005         pSeekPoints[0].mp3FramesToDiscard = 0;
64006         pSeekPoints[0].pcmFramesToDiscard = 0;
64007     } else {
64008         drmp3_uint64 pcmFramesBetweenSeekPoints;
64009         drmp3__seeking_mp3_frame_info mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES+1];
64010         drmp3_uint64 runningPCMFrameCount = 0;
64011         float runningPCMFrameCountFractionalPart = 0;
64012         drmp3_uint64 nextTargetPCMFrame;
64013         drmp3_uint32 iMP3Frame;
64014         drmp3_uint32 iSeekPoint;
64015         if (seekPointCount > totalMP3FrameCount-1) {
64016             seekPointCount = (drmp3_uint32)totalMP3FrameCount-1;
64017         }
64018         pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1);
64019         if (!drmp3_seek_to_start_of_stream(pMP3)) {
64020             return DRMP3_FALSE;
64021         }
64022         for (iMP3Frame = 0; iMP3Frame < DRMP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) {
64023             drmp3_uint32 pcmFramesInCurrentMP3FrameIn;
64024             DRMP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize);
64025             mp3FrameInfo[iMP3Frame].bytePos       = pMP3->streamCursor - pMP3->dataSize;
64026             mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount;
64027             pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL);
64028             if (pcmFramesInCurrentMP3FrameIn == 0) {
64029                 return DRMP3_FALSE;
64030             }
64031             drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart);
64032         }
64033         nextTargetPCMFrame = 0;
64034         for (iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) {
64035             nextTargetPCMFrame += pcmFramesBetweenSeekPoints;
64036             for (;;) {
64037                 if (nextTargetPCMFrame < runningPCMFrameCount) {
64038                     pSeekPoints[iSeekPoint].seekPosInBytes     = mp3FrameInfo[0].bytePos;
64039                     pSeekPoints[iSeekPoint].pcmFrameIndex      = nextTargetPCMFrame;
64040                     pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES;
64041                     pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex);
64042                     break;
64043                 } else {
64044                     size_t i;
64045                     drmp3_uint32 pcmFramesInCurrentMP3FrameIn;
64046                     for (i = 0; i < DRMP3_COUNTOF(mp3FrameInfo)-1; ++i) {
64047                         mp3FrameInfo[i] = mp3FrameInfo[i+1];
64048                     }
64049                     mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].bytePos       = pMP3->streamCursor - pMP3->dataSize;
64050                     mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount;
64051                     pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL);
64052                     if (pcmFramesInCurrentMP3FrameIn == 0) {
64053                         pSeekPoints[iSeekPoint].seekPosInBytes     = mp3FrameInfo[0].bytePos;
64054                         pSeekPoints[iSeekPoint].pcmFrameIndex      = nextTargetPCMFrame;
64055                         pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES;
64056                         pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex);
64057                         break;
64058                     }
64059                     drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart);
64060                 }
64061             }
64062         }
64063         if (!drmp3_seek_to_start_of_stream(pMP3)) {
64064             return DRMP3_FALSE;
64065         }
64066         if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) {
64067             return DRMP3_FALSE;
64068         }
64069     }
64070     *pSeekPointCount = seekPointCount;
64071     return DRMP3_TRUE;
64072 }
64073 DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints)
64074 {
64075     if (pMP3 == NULL) {
64076         return DRMP3_FALSE;
64077     }
64078     if (seekPointCount == 0 || pSeekPoints == NULL) {
64079         pMP3->seekPointCount = 0;
64080         pMP3->pSeekPoints = NULL;
64081     } else {
64082         pMP3->seekPointCount = seekPointCount;
64083         pMP3->pSeekPoints = pSeekPoints;
64084     }
64085     return DRMP3_TRUE;
64086 }
64087 static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
64088 {
64089     drmp3_uint64 totalFramesRead = 0;
64090     drmp3_uint64 framesCapacity = 0;
64091     float* pFrames = NULL;
64092     float temp[4096];
64093     DRMP3_ASSERT(pMP3 != NULL);
64094     for (;;) {
64095         drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
64096         drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp);
64097         if (framesJustRead == 0) {
64098             break;
64099         }
64100         if (framesCapacity < totalFramesRead + framesJustRead) {
64101             drmp3_uint64 oldFramesBufferSize;
64102             drmp3_uint64 newFramesBufferSize;
64103             drmp3_uint64 newFramesCap;
64104             float* pNewFrames;
64105             newFramesCap = framesCapacity * 2;
64106             if (newFramesCap < totalFramesRead + framesJustRead) {
64107                 newFramesCap = totalFramesRead + framesJustRead;
64108             }
64109             oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float);
64110             newFramesBufferSize = newFramesCap   * pMP3->channels * sizeof(float);
64111             if (newFramesBufferSize > DRMP3_SIZE_MAX) {
64112                 break;
64113             }
64114             pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
64115             if (pNewFrames == NULL) {
64116                 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
64117                 break;
64118             }
64119             pFrames = pNewFrames;
64120             framesCapacity = newFramesCap;
64121         }
64122         DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(float)));
64123         totalFramesRead += framesJustRead;
64124         if (framesJustRead != framesToReadRightNow) {
64125             break;
64126         }
64127     }
64128     if (pConfig != NULL) {
64129         pConfig->channels   = pMP3->channels;
64130         pConfig->sampleRate = pMP3->sampleRate;
64131     }
64132     drmp3_uninit(pMP3);
64133     if (pTotalFrameCount) {
64134         *pTotalFrameCount = totalFramesRead;
64135     }
64136     return pFrames;
64137 }
64138 static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
64139 {
64140     drmp3_uint64 totalFramesRead = 0;
64141     drmp3_uint64 framesCapacity = 0;
64142     drmp3_int16* pFrames = NULL;
64143     drmp3_int16 temp[4096];
64144     DRMP3_ASSERT(pMP3 != NULL);
64145     for (;;) {
64146         drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
64147         drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp);
64148         if (framesJustRead == 0) {
64149             break;
64150         }
64151         if (framesCapacity < totalFramesRead + framesJustRead) {
64152             drmp3_uint64 newFramesBufferSize;
64153             drmp3_uint64 oldFramesBufferSize;
64154             drmp3_uint64 newFramesCap;
64155             drmp3_int16* pNewFrames;
64156             newFramesCap = framesCapacity * 2;
64157             if (newFramesCap < totalFramesRead + framesJustRead) {
64158                 newFramesCap = totalFramesRead + framesJustRead;
64159             }
64160             oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16);
64161             newFramesBufferSize = newFramesCap   * pMP3->channels * sizeof(drmp3_int16);
64162             if (newFramesBufferSize > DRMP3_SIZE_MAX) {
64163                 break;
64164             }
64165             pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
64166             if (pNewFrames == NULL) {
64167                 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
64168                 break;
64169             }
64170             pFrames = pNewFrames;
64171             framesCapacity = newFramesCap;
64172         }
64173         DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(drmp3_int16)));
64174         totalFramesRead += framesJustRead;
64175         if (framesJustRead != framesToReadRightNow) {
64176             break;
64177         }
64178     }
64179     if (pConfig != NULL) {
64180         pConfig->channels   = pMP3->channels;
64181         pConfig->sampleRate = pMP3->sampleRate;
64182     }
64183     drmp3_uninit(pMP3);
64184     if (pTotalFrameCount) {
64185         *pTotalFrameCount = totalFramesRead;
64186     }
64187     return pFrames;
64188 }
64189 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)
64190 {
64191     drmp3 mp3;
64192     if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
64193         return NULL;
64194     }
64195     return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
64196 }
64197 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)
64198 {
64199     drmp3 mp3;
64200     if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
64201         return NULL;
64202     }
64203     return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
64204 }
64205 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)
64206 {
64207     drmp3 mp3;
64208     if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
64209         return NULL;
64210     }
64211     return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
64212 }
64213 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)
64214 {
64215     drmp3 mp3;
64216     if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
64217         return NULL;
64218     }
64219     return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
64220 }
64221 #ifndef DR_MP3_NO_STDIO
64222 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)
64223 {
64224     drmp3 mp3;
64225     if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
64226         return NULL;
64227     }
64228     return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
64229 }
64230 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)
64231 {
64232     drmp3 mp3;
64233     if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
64234         return NULL;
64235     }
64236     return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
64237 }
64238 #endif
64239 DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
64240 {
64241     if (pAllocationCallbacks != NULL) {
64242         return drmp3__malloc_from_callbacks(sz, pAllocationCallbacks);
64243     } else {
64244         return drmp3__malloc_default(sz, NULL);
64245     }
64246 }
64247 DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
64248 {
64249     if (pAllocationCallbacks != NULL) {
64250         drmp3__free_from_callbacks(p, pAllocationCallbacks);
64251     } else {
64252         drmp3__free_default(p, NULL);
64253     }
64254 }
64255 #endif
64256 /* dr_mp3_c end */
64257 #endif  /* DRMP3_IMPLEMENTATION */
64258 #endif  /* MA_NO_MP3 */
64259
64260
64261 /* End globally disabled warnings. */
64262 #if defined(_MSC_VER)
64263     #pragma warning(pop)
64264 #endif
64265
64266 #endif  /* miniaudio_c */
64267 #endif  /* MINIAUDIO_IMPLEMENTATION */
64268
64269 /*
64270 RELEASE NOTES - VERSION 0.10.x
64271 ==============================
64272 Version 0.10 includes major API changes and refactoring, mostly concerned with the data conversion system. Data conversion is performed internally to convert
64273 audio data between the format requested when initializing the `ma_device` object and the format of the internal device used by the backend. The same applies
64274 to the `ma_decoder` object. The previous design has several design flaws and missing features which necessitated a complete redesign.
64275
64276
64277 Changes to Data Conversion
64278 --------------------------
64279 The previous data conversion system used callbacks to deliver input data for conversion. This design works well in some specific situations, but in other
64280 situations it has some major readability and maintenance issues. The decision was made to replace this with a more iterative approach where you just pass in a
64281 pointer to the input data directly rather than dealing with a callback.
64282
64283 The following are the data conversion APIs that have been removed and their replacements:
64284
64285   - ma_format_converter -> ma_convert_pcm_frames_format()
64286   - ma_channel_router   -> ma_channel_converter
64287   - ma_src              -> ma_resampler
64288   - ma_pcm_converter    -> ma_data_converter
64289
64290 The previous conversion APIs accepted a callback in their configs. There are no longer any callbacks to deal with. Instead you just pass the data into the
64291 `*_process_pcm_frames()` function as a pointer to a buffer.
64292
64293 The simplest aspect of data conversion is sample format conversion. To convert between two formats, just call `ma_convert_pcm_frames_format()`. Channel
64294 conversion is also simple which you can do with `ma_channel_converter` via `ma_channel_converter_process_pcm_frames()`.
64295
64296 Resampling is more complicated because the number of output frames that are processed is different to the number of input frames that are consumed. When you
64297 call `ma_resampler_process_pcm_frames()` you need to pass in the number of input frames available for processing and the number of output frames you want to
64298 output. Upon returning they will receive the number of input frames that were consumed and the number of output frames that were generated.
64299
64300 The `ma_data_converter` API is a wrapper around format, channel and sample rate conversion and handles all of the data conversion you'll need which probably
64301 makes it the best option if you need to do data conversion.
64302
64303 In addition to changes to the API design, a few other changes have been made to the data conversion pipeline:
64304
64305   - The sinc resampler has been removed. This was completely broken and never actually worked properly.
64306   - The linear resampler now uses low-pass filtering to remove aliasing. The quality of the low-pass filter can be controlled via the resampler config with the
64307     `lpfOrder` option, which has a maximum value of MA_MAX_FILTER_ORDER.
64308   - Data conversion now supports s16 natively which runs through a fixed point pipeline. Previously everything needed to be converted to floating point before
64309     processing, whereas now both s16 and f32 are natively supported. Other formats still require conversion to either s16 or f32 prior to processing, however
64310     `ma_data_converter` will handle this for you.
64311
64312
64313 Custom Memory Allocators
64314 ------------------------
64315 miniaudio has always supported macro level customization for memory allocation via MA_MALLOC, MA_REALLOC and MA_FREE, however some scenarios require more
64316 flexibility by allowing a user data pointer to be passed to the custom allocation routines. Support for this has been added to version 0.10 via the
64317 `ma_allocation_callbacks` structure. Anything making use of heap allocations has been updated to accept this new structure.
64318
64319 The `ma_context_config` structure has been updated with a new member called `allocationCallbacks`. Leaving this set to it's defaults returned by
64320 `ma_context_config_init()` will cause it to use MA_MALLOC, MA_REALLOC and MA_FREE. Likewise, The `ma_decoder_config` structure has been updated in the same
64321 way, and leaving everything as-is after `ma_decoder_config_init()` will cause it to use the same defaults.
64322
64323 The following APIs have been updated to take a pointer to a `ma_allocation_callbacks` object. Setting this parameter to NULL will cause it to use defaults.
64324 Otherwise they will use the relevant callback in the structure.
64325
64326   - ma_malloc()
64327   - ma_realloc()
64328   - ma_free()
64329   - ma_aligned_malloc()
64330   - ma_aligned_free()
64331   - ma_rb_init() / ma_rb_init_ex()
64332   - ma_pcm_rb_init() / ma_pcm_rb_init_ex()
64333
64334 Note that you can continue to use MA_MALLOC, MA_REALLOC and MA_FREE as per normal. These will continue to be used by default if you do not specify custom
64335 allocation callbacks.
64336
64337
64338 Buffer and Period Configuration Changes
64339 ---------------------------------------
64340 The way in which the size of the internal buffer and periods are specified in the device configuration have changed. In previous versions, the config variables
64341 `bufferSizeInFrames` and `bufferSizeInMilliseconds` defined the size of the entire buffer, with the size of a period being the size of this variable divided by
64342 the period count. This became confusing because people would expect the value of `bufferSizeInFrames` or `bufferSizeInMilliseconds` to independantly determine
64343 latency, when in fact it was that value divided by the period count that determined it. These variables have been removed and replaced with new ones called
64344 `periodSizeInFrames` and `periodSizeInMilliseconds`.
64345
64346 These new configuration variables work in the same way as their predecessors in that if one is set to 0, the other will be used, but the main difference is
64347 that you now set these to you desired latency rather than the size of the entire buffer. The benefit of this is that it's much easier and less confusing to
64348 configure latency.
64349
64350 The following unused APIs have been removed:
64351
64352     ma_get_default_buffer_size_in_milliseconds()
64353     ma_get_default_buffer_size_in_frames()
64354
64355 The following macros have been removed:
64356
64357     MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_LOW_LATENCY
64358     MA_BASE_BUFFER_SIZE_IN_MILLISECONDS_CONSERVATIVE
64359
64360
64361 Other API Changes
64362 -----------------
64363 Other less major API changes have also been made in version 0.10.
64364
64365 `ma_device_set_stop_callback()` has been removed. If you require a stop callback, you must now set it via the device config just like the data callback.
64366
64367 The `ma_sine_wave` API has been replaced with a more general API called `ma_waveform`. This supports generation of different types of waveforms, including
64368 sine, square, triangle and sawtooth. Use `ma_waveform_init()` in place of `ma_sine_wave_init()` to initialize the waveform object. This takes a configuration
64369 object called `ma_waveform_config` which defines the properties of the waveform. Use `ma_waveform_config_init()` to initialize a `ma_waveform_config` object.
64370 Use `ma_waveform_read_pcm_frames()` in place of `ma_sine_wave_read_f32()` and `ma_sine_wave_read_f32_ex()`.
64371
64372 `ma_convert_frames()` and `ma_convert_frames_ex()` have been changed. Both of these functions now take a new parameter called `frameCountOut` which specifies
64373 the size of the output buffer in PCM frames. This has been added for safety. In addition to this, the parameters for `ma_convert_frames_ex()` have changed to
64374 take a pointer to a `ma_data_converter_config` object to specify the input and output formats to convert between. This was done to make it more flexible, to
64375 prevent the parameter list getting too long, and to prevent API breakage whenever a new conversion property is added.
64376
64377 `ma_calculate_frame_count_after_src()` has been renamed to `ma_calculate_frame_count_after_resampling()` for consistency with the new `ma_resampler` API.
64378
64379
64380 Filters
64381 -------
64382 The following filters have been added:
64383
64384     |-------------|-------------------------------------------------------------------|
64385     | API         | Description                                                       |
64386     |-------------|-------------------------------------------------------------------|
64387     | ma_biquad   | Biquad filter (transposed direct form 2)                          |
64388     | ma_lpf1     | First order low-pass filter                                       |
64389     | ma_lpf2     | Second order low-pass filter                                      |
64390     | ma_lpf      | High order low-pass filter (Butterworth)                          |
64391     | ma_hpf1     | First order high-pass filter                                      |
64392     | ma_hpf2     | Second order high-pass filter                                     |
64393     | ma_hpf      | High order high-pass filter (Butterworth)                         |
64394     | ma_bpf2     | Second order band-pass filter                                     |
64395     | ma_bpf      | High order band-pass filter                                       |
64396     | ma_peak2    | Second order peaking filter                                       |
64397     | ma_notch2   | Second order notching filter                                      |
64398     | ma_loshelf2 | Second order low shelf filter                                     |
64399     | ma_hishelf2 | Second order high shelf filter                                    |
64400     |-------------|-------------------------------------------------------------------|
64401
64402 These filters all support 32-bit floating point and 16-bit signed integer formats natively. Other formats need to be converted beforehand.
64403
64404
64405 Sine, Square, Triangle and Sawtooth Waveforms
64406 ---------------------------------------------
64407 Previously miniaudio supported only sine wave generation. This has now been generalized to support sine, square, triangle and sawtooth waveforms. The old
64408 `ma_sine_wave` API has been removed and replaced with the `ma_waveform` API. Use `ma_waveform_config_init()` to initialize a config object, and then pass it
64409 into `ma_waveform_init()`. Then use `ma_waveform_read_pcm_frames()` to read PCM data.
64410
64411
64412 Noise Generation
64413 ----------------
64414 A noise generation API has been added. This is used via the `ma_noise` API. Currently white, pink and Brownian noise is supported. The `ma_noise` API is
64415 similar to the waveform API. Use `ma_noise_config_init()` to initialize a config object, and then pass it into `ma_noise_init()` to initialize a `ma_noise`
64416 object. Then use `ma_noise_read_pcm_frames()` to read PCM data.
64417
64418
64419 Miscellaneous Changes
64420 ---------------------
64421 The MA_NO_STDIO option has been removed. This would disable file I/O APIs, however this has proven to be too hard to maintain for it's perceived value and was
64422 therefore removed.
64423
64424 Internal functions have all been made static where possible. If you get warnings about unused functions, please submit a bug report.
64425
64426 The `ma_device` structure is no longer defined as being aligned to MA_SIMD_ALIGNMENT. This resulted in a possible crash when allocating a `ma_device` object on
64427 the heap, but not aligning it to MA_SIMD_ALIGNMENT. This crash would happen due to the compiler seeing the alignment specified on the structure and assuming it
64428 was always aligned as such and thinking it was safe to emit alignment-dependant SIMD instructions. Since miniaudio's philosophy is for things to just work,
64429 this has been removed from all structures.
64430
64431 Results codes have been overhauled. Unnecessary result codes have been removed, and some have been renumbered for organisation purposes. If you are are binding
64432 maintainer you will need to update your result codes. Support has also been added for retrieving a human readable description of a given result code via the
64433 `ma_result_description()` API.
64434
64435 ALSA: The automatic format conversion, channel conversion and resampling performed by ALSA is now disabled by default as they were causing some compatibility
64436 issues with certain devices and configurations. These can be individually enabled via the device config:
64437
64438     ```c
64439     deviceConfig.alsa.noAutoFormat   = MA_TRUE;
64440     deviceConfig.alsa.noAutoChannels = MA_TRUE;
64441     deviceConfig.alsa.noAutoResample = MA_TRUE;
64442     ```
64443 */
64444
64445 /*
64446 RELEASE NOTES - VERSION 0.9.x
64447 =============================
64448 Version 0.9 includes major API changes, centered mostly around full-duplex and the rebrand to "miniaudio". Before I go into detail about the major changes I
64449 would like to apologize. I know it's annoying dealing with breaking API changes, but I think it's best to get these changes out of the way now while the
64450 library is still relatively young and unknown.
64451
64452 There's been a lot of refactoring with this release so there's a good chance a few bugs have been introduced. I apologize in advance for this. You may want to
64453 hold off on upgrading for the short term if you're worried. If mini_al v0.8.14 works for you, and you don't need full-duplex support, you can avoid upgrading
64454 (though you won't be getting future bug fixes).
64455
64456
64457 Rebranding to "miniaudio"
64458 -------------------------
64459 The decision was made to rename mini_al to miniaudio. Don't worry, it's the same project. The reason for this is simple:
64460
64461 1) Having the word "audio" in the title makes it immediately clear that the library is related to audio; and
64462 2) I don't like the look of the underscore.
64463
64464 This rebrand has necessitated a change in namespace from "mal" to "ma". I know this is annoying, and I apologize, but it's better to get this out of the road
64465 now rather than later. Also, since there are necessary API changes for full-duplex support I think it's better to just get the namespace change over and done
64466 with at the same time as the full-duplex changes. I'm hoping this will be the last of the major API changes. Fingers crossed!
64467
64468 The implementation define is now "#define MINIAUDIO_IMPLEMENTATION". You can also use "#define MA_IMPLEMENTATION" if that's your preference.
64469
64470
64471 Full-Duplex Support
64472 -------------------
64473 The major feature added to version 0.9 is full-duplex. This has necessitated a few API changes.
64474
64475 1) The data callback has now changed. Previously there was one type of callback for playback and another for capture. I wanted to avoid a third callback just
64476    for full-duplex so the decision was made to break this API and unify the callbacks. Now, there is just one callback which is the same for all three modes
64477    (playback, capture, duplex). The new callback looks like the following:
64478
64479        void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
64480
64481    This callback allows you to move data straight out of the input buffer and into the output buffer in full-duplex mode. In playback-only mode, pInput will be
64482    null. Likewise, pOutput will be null in capture-only mode. The sample count is no longer returned from the callback since it's not necessary for miniaudio
64483    anymore.
64484
64485 2) The device config needed to change in order to support full-duplex. Full-duplex requires the ability to allow the client to choose a different PCM format
64486    for the playback and capture sides. The old ma_device_config object simply did not allow this and needed to change. With these changes you now specify the
64487    device ID, format, channels, channel map and share mode on a per-playback and per-capture basis (see example below). The sample rate must be the same for
64488    playback and capture.
64489
64490    Since the device config API has changed I have also decided to take the opportunity to simplify device initialization. Now, the device ID, device type and
64491    callback user data are set in the config. ma_device_init() is now simplified down to taking just the context, device config and a pointer to the device
64492    object being initialized. The rationale for this change is that it just makes more sense to me that these are set as part of the config like everything
64493    else.
64494
64495    Example device initialization:
64496
64497        ma_device_config config = ma_device_config_init(ma_device_type_duplex);   // Or ma_device_type_playback or ma_device_type_capture.
64498        config.playback.pDeviceID = &myPlaybackDeviceID; // Or NULL for the default playback device.
64499        config.playback.format    = ma_format_f32;
64500        config.playback.channels  = 2;
64501        config.capture.pDeviceID  = &myCaptureDeviceID;  // Or NULL for the default capture device.
64502        config.capture.format     = ma_format_s16;
64503        config.capture.channels   = 1;
64504        config.sampleRate         = 44100;
64505        config.dataCallback       = data_callback;
64506        config.pUserData          = &myUserData;
64507
64508        result = ma_device_init(&myContext, &config, &device);
64509        if (result != MA_SUCCESS) {
64510            ... handle error ...
64511        }
64512
64513    Note that the "onDataCallback" member of ma_device_config has been renamed to "dataCallback". Also, "onStopCallback" has been renamed to "stopCallback".
64514
64515 This is the first pass for full-duplex and there is a known bug. You will hear crackling on the following backends when sample rate conversion is required for
64516 the playback device:
64517   - Core Audio
64518   - JACK
64519   - AAudio
64520   - OpenSL
64521   - WebAudio
64522
64523 In addition to the above, not all platforms have been absolutely thoroughly tested simply because I lack the hardware for such thorough testing. If you
64524 experience a bug, an issue report on GitHub or an email would be greatly appreciated (and a sample program that reproduces the issue if possible).
64525
64526
64527 Other API Changes
64528 -----------------
64529 In addition to the above, the following API changes have been made:
64530
64531 - The log callback is no longer passed to ma_context_config_init(). Instead you need to set it manually after initialization.
64532 - The onLogCallback member of ma_context_config has been renamed to "logCallback".
64533 - The log callback now takes a logLevel parameter. The new callback looks like: void log_callback(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
64534   - You can use ma_log_level_to_string() to convert the logLevel to human readable text if you want to log it.
64535 - Some APIs have been renamed:
64536   - mal_decoder_read()          -> ma_decoder_read_pcm_frames()
64537   - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
64538   - mal_sine_wave_read()        -> ma_sine_wave_read_f32()
64539   - mal_sine_wave_read_ex()     -> ma_sine_wave_read_f32_ex()
64540 - Some APIs have been removed:
64541   - mal_device_get_buffer_size_in_bytes()
64542   - mal_device_set_recv_callback()
64543   - mal_device_set_send_callback()
64544   - mal_src_set_input_sample_rate()
64545   - mal_src_set_output_sample_rate()
64546 - Error codes have been rearranged. If you're a binding maintainer you will need to update.
64547 - The ma_backend enums have been rearranged to priority order. The rationale for this is to simplify automatic backend selection and to make it easier to see
64548   the priority. If you're a binding maintainer you will need to update.
64549 - ma_dsp has been renamed to ma_pcm_converter. The rationale for this change is that I'm expecting "ma_dsp" to conflict with some future planned high-level
64550   APIs.
64551 - For functions that take a pointer/count combo, such as ma_decoder_read_pcm_frames(), the parameter order has changed so that the pointer comes before the
64552   count. The rationale for this is to keep it consistent with things like memcpy().
64553
64554
64555 Miscellaneous Changes
64556 ---------------------
64557 The following miscellaneous changes have also been made.
64558
64559 - The AAudio backend has been added for Android 8 and above. This is Android's new "High-Performance Audio" API. (For the record, this is one of the nicest
64560   audio APIs out there, just behind the BSD audio APIs).
64561 - The WebAudio backend has been added. This is based on ScriptProcessorNode. This removes the need for SDL.
64562 - The SDL and OpenAL backends have been removed. These were originally implemented to add support for platforms for which miniaudio was not explicitly
64563   supported. These are no longer needed and have therefore been removed.
64564 - Device initialization now fails if the requested share mode is not supported. If you ask for exclusive mode, you either get an exclusive mode device, or an
64565   error. The rationale for this change is to give the client more control over how to handle cases when the desired shared mode is unavailable.
64566 - A lock-free ring buffer API has been added. There are two varients of this. "ma_rb" operates on bytes, whereas "ma_pcm_rb" operates on PCM frames.
64567 - The library is now licensed as a choice of Public Domain (Unlicense) _or_ MIT-0 (No Attribution) which is the same as MIT, but removes the attribution
64568   requirement. The rationale for this is to support countries that don't recognize public domain.
64569 */
64570
64571 /*
64572 REVISION HISTORY
64573 ================
64574 v0.10.33 - 2021-04-04
64575   - Core Audio: Fix a memory leak.
64576   - Core Audio: Fix a bug where the performance profile is not being used by playback devices.
64577   - JACK: Fix loading of 64-bit JACK on Windows.
64578   - Fix a calculation error and add a safety check to the following APIs to prevent a division by zero:
64579     - ma_calculate_buffer_size_in_milliseconds_from_frames()
64580     - ma_calculate_buffer_size_in_frames_from_milliseconds()
64581   - Fix compilation errors relating to c89atomic.
64582   - Update FLAC decoder.
64583
64584 v0.10.32 - 2021-02-23
64585   - WASAPI: Fix a deadlock in exclusive mode.
64586   - WASAPI: No longer return an error from ma_context_get_device_info() when an exclusive mode format
64587     cannot be retrieved.
64588   - WASAPI: Attempt to fix some bugs with device uninitialization.
64589   - PulseAudio: Yet another refactor, this time to remove the dependency on `pa_threaded_mainloop`.
64590   - Web Audio: Fix a bug on Chrome and any other browser using the same engine.
64591   - Web Audio: Automatically start the device on some user input if the device has been started. This
64592     is to work around Google's policy of not starting audio if no user input has yet been performed.
64593   - Fix a bug where thread handles are not being freed.
64594   - Fix some static analysis warnings in FLAC, WAV and MP3 decoders.
64595   - Fix a warning due to referencing _MSC_VER when it is undefined.
64596   - Update to latest version of c89atomic.
64597   - Internal refactoring to migrate over to the new backend callback system for the following backends:
64598     - PulseAudio
64599     - ALSA
64600     - Core Audio
64601     - AAudio
64602     - OpenSL|ES
64603     - OSS
64604     - audio(4)
64605     - sndio
64606
64607 v0.10.31 - 2021-01-17
64608   - Make some functions const correct.
64609   - Update ma_data_source_read_pcm_frames() to initialize pFramesRead to 0 for safety.
64610   - Add the MA_ATOMIC annotation for use with variables that should be used atomically and remove unnecessary volatile qualifiers.
64611   - Add support for enabling only specific backends at compile time. This is the reverse of the pre-existing system. With the new
64612     system, all backends are first disabled with `MA_ENABLE_ONLY_SPECIFIC_BACKENDS`, which is then followed with `MA_ENABLE_*`. The
64613     old system where you disable backends with `MA_NO_*` still exists and is still the default.
64614
64615 v0.10.30 - 2021-01-10
64616   - Fix a crash in ma_audio_buffer_read_pcm_frames().
64617   - Update spinlock APIs to take a volatile parameter as input.
64618   - Silence some unused parameter warnings.
64619   - Fix a warning on GCC when compiling as C++.
64620
64621 v0.10.29 - 2020-12-26
64622   - Fix some subtle multi-threading bugs on non-x86 platforms.
64623   - Fix a bug resulting in superfluous memory allocations when enumerating devices.
64624   - Core Audio: Fix a compilation error when compiling for iOS.
64625
64626 v0.10.28 - 2020-12-16
64627   - Fix a crash when initializing a POSIX thread.
64628   - OpenSL|ES: Respect the MA_NO_RUNTIME_LINKING option.
64629
64630 v0.10.27 - 2020-12-04
64631   - Add support for dynamically configuring some properties of `ma_noise` objects post-initialization.
64632   - Add support for configuring the channel mixing mode in the device config.
64633   - Fix a bug with simple channel mixing mode (drop or silence excess channels).
64634   - Fix some bugs with trying to access uninitialized variables.
64635   - Fix some errors with stopping devices for synchronous backends where the backend's stop callback would get fired twice.
64636   - Fix a bug in the decoder due to using an uninitialized variable.
64637   - Fix some data race errors.
64638
64639 v0.10.26 - 2020-11-24
64640   - WASAPI: Fix a bug where the exclusive mode format may not be retrieved correctly due to accessing freed memory.
64641   - Fix a bug with ma_waveform where glitching occurs after changing frequency.
64642   - Fix compilation with OpenWatcom.
64643   - Fix compilation with TCC.
64644   - Fix compilation with Digital Mars.
64645   - Fix compilation warnings.
64646   - Remove bitfields from public structures to aid in binding maintenance.
64647
64648 v0.10.25 - 2020-11-15
64649   - PulseAudio: Fix a bug where the stop callback isn't fired.
64650   - WebAudio: Fix an error that occurs when Emscripten increases the size of it's heap.
64651   - Custom Backends: Change the onContextInit and onDeviceInit callbacks to take a parameter which is a pointer to the config that was
64652     passed into ma_context_init() and ma_device_init(). This replaces the deviceType parameter of onDeviceInit.
64653   - Fix compilation warnings on older versions of GCC.
64654
64655 v0.10.24 - 2020-11-10
64656   - 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
64657     lower priority backend.
64658
64659 v0.10.23 - 2020-11-09
64660   - AAudio: Add support for configuring a playback stream's usage.
64661   - Fix a compilation error when all built-in asynchronous backends are disabled at compile time.
64662   - Fix compilation errors when compiling as C++.
64663
64664 v0.10.22 - 2020-11-08
64665   - Add support for custom backends.
64666   - Add support for detecting default devices during device enumeration and with `ma_context_get_device_info()`.
64667   - Refactor to the PulseAudio backend. This simplifies the implementation and fixes a capture bug.
64668   - ALSA: Fix a bug in `ma_context_get_device_info()` where the PCM handle is left open in the event of an error.
64669   - Core Audio: Further improvements to sample rate selection.
64670   - Core Audio: Fix some bugs with capture mode.
64671   - OpenSL: Add support for configuring stream types and recording presets.
64672   - AAudio: Add support for configuring content types and input presets.
64673   - Fix bugs in `ma_decoder_init_file*()` where the file handle is not closed after a decoding error.
64674   - Fix some compilation warnings on GCC and Clang relating to the Speex resampler.
64675   - Fix a compilation error for the Linux build when the ALSA and JACK backends are both disabled.
64676   - Fix a compilation error for the BSD build.
64677   - Fix some compilation errors on older versions of GCC.
64678   - Add documentation for `MA_NO_RUNTIME_LINKING`.
64679
64680 v0.10.21 - 2020-10-30
64681   - Add ma_is_backend_enabled() and ma_get_enabled_backends() for retrieving enabled backends at run-time.
64682   - WASAPI: Fix a copy and paste bug relating to loopback mode.
64683   - Core Audio: Fix a bug when using multiple contexts.
64684   - Core Audio: Fix a compilation warning.
64685   - Core Audio: Improvements to sample rate selection.
64686   - Core Audio: Improvements to format/channels/rate selection when requesting defaults.
64687   - Core Audio: Add notes regarding the Apple notarization process.
64688   - Fix some bugs due to null pointer dereferences.
64689
64690 v0.10.20 - 2020-10-06
64691   - Fix build errors with UWP.
64692   - Minor documentation updates.
64693
64694 v0.10.19 - 2020-09-22
64695   - WASAPI: Return an error when exclusive mode is requested, but the native format is not supported by miniaudio.
64696   - Fix a bug where ma_decoder_seek_to_pcm_frames() never returns MA_SUCCESS even though it was successful.
64697   - Store the sample rate in the `ma_lpf` and `ma_hpf` structures.
64698
64699 v0.10.18 - 2020-08-30
64700   - Fix build errors with VC6.
64701   - Fix a bug in channel converter for s32 format.
64702   - 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
64703     config. This fixes an issue where the optimized mono expansion path would never get used.
64704   - Use a more appropriate default format for FLAC decoders. This will now use ma_format_s16 when the FLAC is encoded as 16-bit.
64705   - Update FLAC decoder.
64706   - Update links to point to the new repository location (https://github.com/mackron/miniaudio).
64707
64708 v0.10.17 - 2020-08-28
64709   - Fix an error where the WAV codec is incorrectly excluded from the build depending on which compile time options are set.
64710   - Fix a bug in ma_audio_buffer_read_pcm_frames() where it isn't returning the correct number of frames processed.
64711   - Fix compilation error on Android.
64712   - Core Audio: Fix a bug with full-duplex mode.
64713   - Add ma_decoder_get_cursor_in_pcm_frames().
64714   - Update WAV codec.
64715
64716 v0.10.16 - 2020-08-14
64717   - WASAPI: Fix a potential crash due to using an uninitialized variable.
64718   - OpenSL: Enable runtime linking.
64719   - OpenSL: Fix a multithreading bug when initializing and uninitializing multiple contexts at the same time.
64720   - iOS: Improvements to device enumeration.
64721   - Fix a crash in ma_data_source_read_pcm_frames() when the output frame count parameter is NULL.
64722   - Fix a bug in ma_data_source_read_pcm_frames() where looping doesn't work.
64723   - Fix some compilation warnings on Windows when both DirectSound and WinMM are disabled.
64724   - Fix some compilation warnings when no decoders are enabled.
64725   - Add ma_audio_buffer_get_available_frames().
64726   - Add ma_decoder_get_available_frames().
64727   - Add sample rate to ma_data_source_get_data_format().
64728   - Change volume APIs to take 64-bit frame counts.
64729   - Updates to documentation.
64730
64731 v0.10.15 - 2020-07-15
64732   - Fix a bug when converting bit-masked channel maps to miniaudio channel maps. This affects the WASAPI and OpenSL backends.
64733
64734 v0.10.14 - 2020-07-14
64735   - Fix compilation errors on Android.
64736   - Fix compilation errors with -march=armv6.
64737   - Updates to the documentation.
64738
64739 v0.10.13 - 2020-07-11
64740   - Fix some potential buffer overflow errors with channel maps when channel counts are greater than MA_MAX_CHANNELS.
64741   - Fix compilation error on Emscripten.
64742   - Silence some unused function warnings.
64743   - Increase the default buffer size on the Web Audio backend. This fixes glitching issues on some browsers.
64744   - Bring FLAC decoder up-to-date with dr_flac.
64745   - Bring MP3 decoder up-to-date with dr_mp3.
64746
64747 v0.10.12 - 2020-07-04
64748   - Fix compilation errors on the iOS build.
64749
64750 v0.10.11 - 2020-06-28
64751   - Fix some bugs with device tracking on Core Audio.
64752   - Updates to documentation.
64753
64754 v0.10.10 - 2020-06-26
64755   - Add include guard for the implementation section.
64756   - Mark ma_device_sink_info_callback() as static.
64757   - Fix compilation errors with MA_NO_DECODING and MA_NO_ENCODING.
64758   - Fix compilation errors with MA_NO_DEVICE_IO
64759
64760 v0.10.9 - 2020-06-24
64761   - 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
64762     longer required. Decoding of WAV, FLAC and MP3 should be supported seamlessly without any additional libraries. Decoders can be excluded from the build
64763     with the following options:
64764     - MA_NO_WAV
64765     - MA_NO_FLAC
64766     - MA_NO_MP3
64767     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
64768     the implementation of miniaudio, or update dr_wav, dr_flac and/or dr_mp3.
64769   - Changes to the internal atomics library. This has been replaced with c89atomic.h which is embedded within this file.
64770   - Fix a bug when a decoding backend reports configurations outside the limits of miniaudio's decoder abstraction.
64771   - Fix the UWP build.
64772   - Fix the Core Audio build.
64773   - Fix the -std=c89 build on GCC.
64774
64775 v0.10.8 - 2020-06-22
64776   - Remove dependency on ma_context from mutexes.
64777   - Change ma_data_source_read_pcm_frames() to return a result code and output the frames read as an output parameter.
64778   - Change ma_data_source_seek_pcm_frames() to return a result code and output the frames seeked as an output parameter.
64779   - Change ma_audio_buffer_unmap() to return MA_AT_END when the end has been reached. This should be considered successful.
64780   - Change playback.pDeviceID and capture.pDeviceID to constant pointers in ma_device_config.
64781   - 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
64782     IO for the loading and reading of raw audio data. Passing in NULL for the VFS will use defaults. New APIs:
64783     - ma_decoder_init_vfs()
64784     - ma_decoder_init_vfs_wav()
64785     - ma_decoder_init_vfs_flac()
64786     - ma_decoder_init_vfs_mp3()
64787     - ma_decoder_init_vfs_vorbis()
64788     - ma_decoder_init_vfs_w()
64789     - ma_decoder_init_vfs_wav_w()
64790     - ma_decoder_init_vfs_flac_w()
64791     - ma_decoder_init_vfs_mp3_w()
64792     - ma_decoder_init_vfs_vorbis_w()
64793   - Add support for memory mapping to ma_data_source.
64794     - ma_data_source_map()
64795     - ma_data_source_unmap()
64796   - 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.
64797   - Add initial implementation of ma_yield() which is useful for spin locks which will be used in some upcoming work.
64798   - Add documentation for log levels.
64799   - The ma_event API has been made public in preparation for some uncoming work.
64800   - 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.
64801   - Fix some bugs with the linear resampler when dynamically changing the sample rate.
64802   - Fix compilation errors with MA_NO_DEVICE_IO.
64803   - Fix some warnings with GCC and -std=c89.
64804   - Fix some formatting warnings with GCC and -Wall and -Wpedantic.
64805   - Fix some warnings with VC6.
64806   - Minor optimization to ma_copy_pcm_frames(). This is now a no-op when the input and output buffers are the same.
64807
64808 v0.10.7 - 2020-05-25
64809   - Fix a compilation error in the C++ build.
64810   - Silence a warning.
64811
64812 v0.10.6 - 2020-05-24
64813   - Change ma_clip_samples_f32() and ma_clip_pcm_frames_f32() to take a 64-bit sample/frame count.
64814   - Change ma_zero_pcm_frames() to clear to 128 for ma_format_u8.
64815   - Add ma_silence_pcm_frames() which replaces ma_zero_pcm_frames(). ma_zero_pcm_frames() will be removed in version 0.11.
64816   - Add support for u8, s24 and s32 formats to ma_channel_converter.
64817   - Add compile-time and run-time version querying.
64818     - MA_VERSION_MINOR
64819     - MA_VERSION_MAJOR
64820     - MA_VERSION_REVISION
64821     - MA_VERSION_STRING
64822     - ma_version()
64823     - ma_version_string()
64824   - Add ma_audio_buffer for reading raw audio data directly from memory.
64825   - Fix a bug in shuffle mode in ma_channel_converter.
64826   - Fix compilation errors in certain configurations for ALSA and PulseAudio.
64827   - The data callback now initializes the output buffer to 128 when the playback sample format is ma_format_u8.
64828
64829 v0.10.5 - 2020-05-05
64830   - Change ma_zero_pcm_frames() to take a 64-bit frame count.
64831   - Add ma_copy_pcm_frames().
64832   - Add MA_NO_GENERATION build option to exclude the `ma_waveform` and `ma_noise` APIs from the build.
64833   - Add support for formatted logging to the VC6 build.
64834   - Fix a crash in the linear resampler when LPF order is 0.
64835   - Fix compilation errors and warnings with older versions of Visual Studio.
64836   - Minor documentation updates.
64837
64838 v0.10.4 - 2020-04-12
64839   - Fix a data conversion bug when converting from the client format to the native device format.
64840
64841 v0.10.3 - 2020-04-07
64842   - Bring up to date with breaking changes to dr_mp3.
64843   - Remove MA_NO_STDIO. This was causing compilation errors and the maintenance cost versus practical benefit is no longer worthwhile.
64844   - Fix a bug with data conversion where it was unnecessarily converting to s16 or f32 and then straight back to the original format.
64845   - Fix compilation errors and warnings with Visual Studio 2005.
64846   - ALSA: Disable ALSA's automatic data conversion by default and add configuration options to the device config:
64847     - alsa.noAutoFormat
64848     - alsa.noAutoChannels
64849     - alsa.noAutoResample
64850   - WASAPI: Add some overrun recovery for ma_device_type_capture devices.
64851
64852 v0.10.2 - 2020-03-22
64853   - Decorate some APIs with MA_API which were missed in the previous version.
64854   - Fix a bug in ma_linear_resampler_set_rate() and ma_linear_resampler_set_rate_ratio().
64855
64856 v0.10.1 - 2020-03-17
64857   - Add MA_API decoration. This can be customized by defining it before including miniaudio.h.
64858   - Fix a bug where opening a file would return a success code when in fact it failed.
64859   - Fix compilation errors with Visual Studio 6 and 2003.
64860   - Fix warnings on macOS.
64861
64862 v0.10.0 - 2020-03-07
64863   - API CHANGE: Refactor data conversion APIs
64864     - ma_format_converter has been removed. Use ma_convert_pcm_frames_format() instead.
64865     - ma_channel_router has been replaced with ma_channel_converter.
64866     - ma_src has been replaced with ma_resampler
64867     - ma_pcm_converter has been replaced with ma_data_converter
64868   - API CHANGE: Add support for custom memory allocation callbacks. The following APIs have been updated to take an extra parameter for the allocation
64869     callbacks:
64870     - ma_malloc()
64871     - ma_realloc()
64872     - ma_free()
64873     - ma_aligned_malloc()
64874     - ma_aligned_free()
64875     - ma_rb_init() / ma_rb_init_ex()
64876     - ma_pcm_rb_init() / ma_pcm_rb_init_ex()
64877   - API CHANGE: Simplify latency specification in device configurations. The bufferSizeInFrames and bufferSizeInMilliseconds parameters have been replaced with
64878     periodSizeInFrames and periodSizeInMilliseconds respectively. The previous variables defined the size of the entire buffer, whereas the new ones define the
64879     size of a period. The following APIs have been removed since they are no longer relevant:
64880     - ma_get_default_buffer_size_in_milliseconds()
64881     - ma_get_default_buffer_size_in_frames()
64882   - 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
64883     callback.
64884   - API CHANGE: The ma_sine_wave API has been replaced with ma_waveform. The following APIs have been removed:
64885     - ma_sine_wave_init()
64886     - ma_sine_wave_read_f32()
64887     - ma_sine_wave_read_f32_ex()
64888   - 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
64889     reordered.
64890   - 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
64891     convert between.
64892   - API CHANGE: ma_calculate_frame_count_after_src() has been renamed to ma_calculate_frame_count_after_resampling().
64893   - Add support for the following filters:
64894     - Biquad (ma_biquad)
64895     - First order low-pass (ma_lpf1)
64896     - Second order low-pass (ma_lpf2)
64897     - Low-pass with configurable order (ma_lpf)
64898     - First order high-pass (ma_hpf1)
64899     - Second order high-pass (ma_hpf2)
64900     - High-pass with configurable order (ma_hpf)
64901     - Second order band-pass (ma_bpf2)
64902     - Band-pass with configurable order (ma_bpf)
64903     - Second order peaking EQ (ma_peak2)
64904     - Second order notching (ma_notch2)
64905     - Second order low shelf (ma_loshelf2)
64906     - Second order high shelf (ma_hishelf2)
64907   - Add waveform generation API (ma_waveform) with support for the following:
64908     - Sine
64909     - Square
64910     - Triangle
64911     - Sawtooth
64912   - Add noise generation API (ma_noise) with support for the following:
64913     - White
64914     - Pink
64915     - Brownian
64916   - Add encoding API (ma_encoder). This only supports outputting to WAV files via dr_wav.
64917   - Add ma_result_description() which is used to retrieve a human readable description of a given result code.
64918   - Result codes have been changed. Binding maintainers will need to update their result code constants.
64919   - More meaningful result codes are now returned when a file fails to open.
64920   - Internal functions have all been made static where possible.
64921   - Fix potential crash when ma_device object's are not aligned to MA_SIMD_ALIGNMENT.
64922   - 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.
64923   - Fix bugs in some backends where the device is not drained properly in ma_device_stop().
64924   - Improvements to documentation.
64925
64926 v0.9.10 - 2020-01-15
64927   - Fix compilation errors due to #if/#endif mismatches.
64928   - WASAPI: Fix a bug where automatic stream routing is being performed for devices that are initialized with an explicit device ID.
64929   - iOS: Fix a crash on device uninitialization.
64930
64931 v0.9.9 - 2020-01-09
64932   - Fix compilation errors with MinGW.
64933   - Fix compilation errors when compiling on Apple platforms.
64934   - WASAPI: Add support for disabling hardware offloading.
64935   - WASAPI: Add support for disabling automatic stream routing.
64936   - Core Audio: Fix bugs in the case where the internal device uses deinterleaved buffers.
64937   - Core Audio: Add support for controlling the session category (AVAudioSessionCategory) and options (AVAudioSessionCategoryOptions).
64938   - JACK: Fix bug where incorrect ports are connected.
64939
64940 v0.9.8 - 2019-10-07
64941   - WASAPI: Fix a potential deadlock when starting a full-duplex device.
64942   - WASAPI: Enable automatic resampling by default. Disable with config.wasapi.noAutoConvertSRC.
64943   - Core Audio: Fix bugs with automatic stream routing.
64944   - Add support for controlling whether or not the content of the output buffer passed in to the data callback is pre-initialized
64945     to zero. By default it will be initialized to zero, but this can be changed by setting noPreZeroedOutputBuffer in the device
64946     config. Setting noPreZeroedOutputBuffer to true will leave the contents undefined.
64947   - Add support for clipping samples after the data callback has returned. This only applies when the playback sample format is
64948     configured as ma_format_f32. If you are doing clipping yourself, you can disable this overhead by setting noClip to true in
64949     the device config.
64950   - Add support for master volume control for devices.
64951     - 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.
64952     - Use ma_device_set_master_gain_db() to set the volume in decibels where 0 is full volume and < 0 reduces the volume.
64953   - Fix warnings emitted by GCC when `__inline__` is undefined or defined as nothing.
64954
64955 v0.9.7 - 2019-08-28
64956   - Add support for loopback mode (WASAPI only).
64957     - To use this, set the device type to ma_device_type_loopback, and then fill out the capture section of the device config.
64958     - If you need to capture from a specific output device, set the capture device ID to that of a playback device.
64959   - Fix a crash when an error is posted in ma_device_init().
64960   - Fix a compilation error when compiling for ARM architectures.
64961   - Fix a bug with the audio(4) backend where the device is incorrectly being opened in non-blocking mode.
64962   - Fix memory leaks in the Core Audio backend.
64963   - Minor refactoring to the WinMM, ALSA, PulseAudio, OSS, audio(4), sndio and null backends.
64964
64965 v0.9.6 - 2019-08-04
64966   - Add support for loading decoders using a wchar_t string for file paths.
64967   - Don't trigger an assert when ma_device_start() is called on a device that is already started. This will now log a warning
64968     and return MA_INVALID_OPERATION. The same applies for ma_device_stop().
64969   - Try fixing an issue with PulseAudio taking a long time to start playback.
64970   - Fix a bug in ma_convert_frames() and ma_convert_frames_ex().
64971   - Fix memory leaks in the WASAPI backend.
64972   - Fix a compilation error with Visual Studio 2010.
64973
64974 v0.9.5 - 2019-05-21
64975   - Add logging to ma_dlopen() and ma_dlsym().
64976   - Add ma_decoder_get_length_in_pcm_frames().
64977   - Fix a bug with capture on the OpenSL|ES backend.
64978   - Fix a bug with the ALSA backend where a device would not restart after being stopped.
64979
64980 v0.9.4 - 2019-05-06
64981   - Add support for C89. With this change, miniaudio should compile clean with GCC/Clang with "-std=c89 -ansi -pedantic" and
64982     Microsoft compilers back to VC6. Other compilers should also work, but have not been tested.
64983
64984 v0.9.3 - 2019-04-19
64985   - Fix compiler errors on GCC when compiling with -std=c99.
64986
64987 v0.9.2 - 2019-04-08
64988   - Add support for per-context user data.
64989   - Fix a potential bug with context configs.
64990   - Fix some bugs with PulseAudio.
64991
64992 v0.9.1 - 2019-03-17
64993   - Fix a bug where the output buffer is not getting zeroed out before calling the data callback. This happens when
64994     the device is running in passthrough mode (not doing any data conversion).
64995   - Fix an issue where the data callback is getting called too frequently on the WASAPI and DirectSound backends.
64996   - Fix error on the UWP build.
64997   - Fix a build error on Apple platforms.
64998
64999 v0.9 - 2019-03-06
65000   - Rebranded to "miniaudio". All namespaces have been renamed from "mal" to "ma".
65001   - API CHANGE: ma_device_init() and ma_device_config_init() have changed significantly:
65002     - The device type, device ID and user data pointer have moved from ma_device_init() to the config.
65003     - All variations of ma_device_config_init_*() have been removed in favor of just ma_device_config_init().
65004     - ma_device_config_init() now takes only one parameter which is the device type. All other properties need
65005       to be set on the returned object directly.
65006     - The onDataCallback and onStopCallback members of ma_device_config have been renamed to "dataCallback"
65007       and "stopCallback".
65008     - The ID of the physical device is now split into two: one for the playback device and the other for the
65009       capture device. This is required for full-duplex. These are named "pPlaybackDeviceID" and "pCaptureDeviceID".
65010   - API CHANGE: The data callback has changed. It now uses a unified callback for all device types rather than
65011     being separate for each. It now takes two pointers - one containing input data and the other output data. This
65012     design in required for full-duplex. The return value is now void instead of the number of frames written. The
65013     new callback looks like the following:
65014         void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
65015   - API CHANGE: Remove the log callback parameter from ma_context_config_init(). With this change,
65016     ma_context_config_init() now takes no parameters and the log callback is set via the structure directly. The
65017     new policy for config initialization is that only mandatory settings are passed in to *_config_init(). The
65018     "onLog" member of ma_context_config has been renamed to "logCallback".
65019   - API CHANGE: Remove ma_device_get_buffer_size_in_bytes().
65020   - API CHANGE: Rename decoding APIs to "pcm_frames" convention.
65021     - mal_decoder_read()          -> ma_decoder_read_pcm_frames()
65022     - mal_decoder_seek_to_frame() -> ma_decoder_seek_to_pcm_frame()
65023   - API CHANGE: Rename sine wave reading APIs to f32 convention.
65024     - mal_sine_wave_read()    -> ma_sine_wave_read_f32()
65025     - mal_sine_wave_read_ex() -> ma_sine_wave_read_f32_ex()
65026   - API CHANGE: Remove some deprecated APIs
65027     - mal_device_set_recv_callback()
65028     - mal_device_set_send_callback()
65029     - mal_src_set_input_sample_rate()
65030     - mal_src_set_output_sample_rate()
65031   - API CHANGE: Add log level to the log callback. New signature:
65032     - void on_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message)
65033   - API CHANGE: Changes to result codes. Constants have changed and unused codes have been removed. If you're
65034     a binding mainainer you will need to update your result code constants.
65035   - API CHANGE: Change the order of the ma_backend enums to priority order. If you are a binding maintainer, you
65036     will need to update.
65037   - API CHANGE: Rename mal_dsp to ma_pcm_converter. All functions have been renamed from mal_dsp_*() to
65038     ma_pcm_converter_*(). All structures have been renamed from mal_dsp* to ma_pcm_converter*.
65039   - API CHANGE: Reorder parameters of ma_decoder_read_pcm_frames() to be consistent with the new parameter order scheme.
65040   - The resampling algorithm has been changed from sinc to linear. The rationale for this is that the sinc implementation
65041     is too inefficient right now. This will hopefully be improved at a later date.
65042   - Device initialization will no longer fall back to shared mode if exclusive mode is requested but is unusable.
65043     With this change, if you request an device in exclusive mode, but exclusive mode is not supported, it will not
65044     automatically fall back to shared mode. The client will need to reinitialize the device in shared mode if that's
65045     what they want.
65046   - Add ring buffer API. This is ma_rb and ma_pcm_rb, the difference being that ma_rb operates on bytes and
65047     ma_pcm_rb operates on PCM frames.
65048   - Add Web Audio backend. This is used when compiling with Emscripten. The SDL backend, which was previously
65049     used for web support, will be removed in a future version.
65050   - Add AAudio backend (Android Audio). This is the new priority backend for Android. Support for AAudio starts
65051     with Android 8. OpenSL|ES is used as a fallback for older versions of Android.
65052   - Remove OpenAL and SDL backends.
65053   - Fix a possible deadlock when rapidly stopping the device after it has started.
65054   - Update documentation.
65055   - Change licensing to a choice of public domain _or_ MIT-0 (No Attribution).
65056
65057 v0.8.14 - 2018-12-16
65058   - Core Audio: Fix a bug where the device state is not set correctly after stopping.
65059   - Add support for custom weights to the channel router.
65060   - Update decoders to use updated APIs in dr_flac, dr_mp3 and dr_wav.
65061
65062 v0.8.13 - 2018-12-04
65063   - Core Audio: Fix a bug with channel mapping.
65064   - Fix a bug with channel routing where the back/left and back/right channels have the wrong weight.
65065
65066 v0.8.12 - 2018-11-27
65067   - Drop support for SDL 1.2. The Emscripten build now requires "-s USE_SDL=2".
65068   - Fix a linking error with ALSA.
65069   - Fix a bug on iOS where the device name is not set correctly.
65070
65071 v0.8.11 - 2018-11-21
65072   - iOS bug fixes.
65073   - Minor tweaks to PulseAudio.
65074
65075 v0.8.10 - 2018-10-21
65076   - Core Audio: Fix a hang when uninitializing a device.
65077   - Fix a bug where an incorrect value is returned from mal_device_stop().
65078
65079 v0.8.9 - 2018-09-28
65080   - Fix a bug with the SDL backend where device initialization fails.
65081
65082 v0.8.8 - 2018-09-14
65083   - Fix Linux build with the ALSA backend.
65084   - Minor documentation fix.
65085
65086 v0.8.7 - 2018-09-12
65087   - Fix a bug with UWP detection.
65088
65089 v0.8.6 - 2018-08-26
65090   - Automatically switch the internal device when the default device is unplugged. Note that this is still in the
65091     early stages and not all backends handle this the same way. As of this version, this will not detect a default
65092     device switch when changed from the operating system's audio preferences (unless the backend itself handles
65093     this automatically). This is not supported in exclusive mode.
65094   - WASAPI and Core Audio: Add support for stream routing. When the application is using a default device and the
65095     user switches the default device via the operating system's audio preferences, miniaudio will automatically switch
65096     the internal device to the new default. This is not supported in exclusive mode.
65097   - WASAPI: Add support for hardware offloading via IAudioClient2. Only supported on Windows 8 and newer.
65098   - WASAPI: Add support for low-latency shared mode via IAudioClient3. Only supported on Windows 10 and newer.
65099   - Add support for compiling the UWP build as C.
65100   - mal_device_set_recv_callback() and mal_device_set_send_callback() have been deprecated. You must now set this
65101     when the device is initialized with mal_device_init*(). These will be removed in version 0.9.0.
65102
65103 v0.8.5 - 2018-08-12
65104   - Add support for specifying the size of a device's buffer in milliseconds. You can still set the buffer size in
65105     frames if that suits you. When bufferSizeInFrames is 0, bufferSizeInMilliseconds will be used. If both are non-0
65106     then bufferSizeInFrames will take priority. If both are set to 0 the default buffer size is used.
65107   - Add support for the audio(4) backend to OpenBSD.
65108   - Fix a bug with the ALSA backend that was causing problems on Raspberry Pi. This significantly improves the
65109     Raspberry Pi experience.
65110   - Fix a bug where an incorrect number of samples is returned from sinc resampling.
65111   - Add support for setting the value to be passed to internal calls to CoInitializeEx().
65112   - WASAPI and WinMM: Stop the device when it is unplugged.
65113
65114 v0.8.4 - 2018-08-06
65115   - Add sndio backend for OpenBSD.
65116   - Add audio(4) backend for NetBSD.
65117   - Drop support for the OSS backend on everything except FreeBSD and DragonFly BSD.
65118   - Formats are now native-endian (were previously little-endian).
65119   - Mark some APIs as deprecated:
65120     - mal_src_set_input_sample_rate() and mal_src_set_output_sample_rate() are replaced with mal_src_set_sample_rate().
65121     - mal_dsp_set_input_sample_rate() and mal_dsp_set_output_sample_rate() are replaced with mal_dsp_set_sample_rate().
65122   - Fix a bug when capturing using the WASAPI backend.
65123   - Fix some aliasing issues with resampling, specifically when increasing the sample rate.
65124   - Fix warnings.
65125
65126 v0.8.3 - 2018-07-15
65127   - Fix a crackling bug when resampling in capture mode.
65128   - Core Audio: Fix a bug where capture does not work.
65129   - ALSA: Fix a bug where the worker thread can get stuck in an infinite loop.
65130   - PulseAudio: Fix a bug where mal_context_init() succeeds when PulseAudio is unusable.
65131   - JACK: Fix a bug where mal_context_init() succeeds when JACK is unusable.
65132
65133 v0.8.2 - 2018-07-07
65134   - Fix a bug on macOS with Core Audio where the internal callback is not called.
65135
65136 v0.8.1 - 2018-07-06
65137   - Fix compilation errors and warnings.
65138
65139 v0.8 - 2018-07-05
65140   - Changed MAL_IMPLEMENTATION to MINI_AL_IMPLEMENTATION for consistency with other libraries. The old
65141     way is still supported for now, but you should update as it may be removed in the future.
65142   - API CHANGE: Replace device enumeration APIs. mal_enumerate_devices() has been replaced with
65143     mal_context_get_devices(). An additional low-level device enumration API has been introduced called
65144     mal_context_enumerate_devices() which uses a callback to report devices.
65145   - API CHANGE: Rename mal_get_sample_size_in_bytes() to mal_get_bytes_per_sample() and add
65146     mal_get_bytes_per_frame().
65147   - API CHANGE: Replace mal_device_config.preferExclusiveMode with mal_device_config.shareMode.
65148     - This new config can be set to mal_share_mode_shared (default) or mal_share_mode_exclusive.
65149   - API CHANGE: Remove excludeNullDevice from mal_context_config.alsa.
65150   - API CHANGE: Rename MAL_MAX_SAMPLE_SIZE_IN_BYTES to MAL_MAX_PCM_SAMPLE_SIZE_IN_BYTES.
65151   - API CHANGE: Change the default channel mapping to the standard Microsoft mapping.
65152   - API CHANGE: Remove backend-specific result codes.
65153   - API CHANGE: Changes to the format conversion APIs (mal_pcm_f32_to_s16(), etc.)
65154   - Add support for Core Audio (Apple).
65155   - Add support for PulseAudio.
65156     - This is the highest priority backend on Linux (higher priority than ALSA) since it is commonly
65157       installed by default on many of the popular distros and offer's more seamless integration on
65158       platforms where PulseAudio is used. In addition, if PulseAudio is installed and running (which
65159       is extremely common), it's better to just use PulseAudio directly rather than going through the
65160       "pulse" ALSA plugin (which is what the "default" ALSA device is likely set to).
65161   - Add support for JACK.
65162   - Remove dependency on asound.h for the ALSA backend. This means the ALSA development packages are no
65163     longer required to build miniaudio.
65164   - Remove dependency on dsound.h for the DirectSound backend. This fixes build issues with some
65165     distributions of MinGW.
65166   - Remove dependency on audioclient.h for the WASAPI backend. This fixes build issues with some
65167     distributions of MinGW.
65168   - Add support for dithering to format conversion.
65169   - Add support for configuring the priority of the worker thread.
65170   - Add a sine wave generator.
65171   - Improve efficiency of sample rate conversion.
65172   - Introduce the notion of standard channel maps. Use mal_get_standard_channel_map().
65173   - Introduce the notion of default device configurations. A default config uses the same configuration
65174     as the backend's internal device, and as such results in a pass-through data transmission pipeline.
65175   - Add support for passing in NULL for the device config in mal_device_init(), which uses a default
65176     config. This requires manually calling mal_device_set_send/recv_callback().
65177   - Add support for decoding from raw PCM data (mal_decoder_init_raw(), etc.)
65178   - Make mal_device_init_ex() more robust.
65179   - Make some APIs more const-correct.
65180   - Fix errors with SDL detection on Apple platforms.
65181   - Fix errors with OpenAL detection.
65182   - Fix some memory leaks.
65183   - Fix a bug with opening decoders from memory.
65184   - Early work on SSE2, AVX2 and NEON optimizations.
65185   - Miscellaneous bug fixes.
65186   - Documentation updates.
65187
65188 v0.7 - 2018-02-25
65189   - API CHANGE: Change mal_src_read_frames() and mal_dsp_read_frames() to use 64-bit sample counts.
65190   - Add decoder APIs for loading WAV, FLAC, Vorbis and MP3 files.
65191   - Allow opening of devices without a context.
65192     - In this case the context is created and managed internally by the device.
65193   - Change the default channel mapping to the same as that used by FLAC.
65194   - Fix build errors with macOS.
65195
65196 v0.6c - 2018-02-12
65197   - Fix build errors with BSD/OSS.
65198
65199 v0.6b - 2018-02-03
65200   - Fix some warnings when compiling with Visual C++.
65201
65202 v0.6a - 2018-01-26
65203   - Fix errors with channel mixing when increasing the channel count.
65204   - Improvements to the build system for the OpenAL backend.
65205   - Documentation fixes.
65206
65207 v0.6 - 2017-12-08
65208   - API CHANGE: Expose and improve mutex APIs. If you were using the mutex APIs before this version you'll
65209     need to update.
65210   - API CHANGE: SRC and DSP callbacks now take a pointer to a mal_src and mal_dsp object respectively.
65211   - API CHANGE: Improvements to event and thread APIs. These changes make these APIs more consistent.
65212   - Add support for SDL and Emscripten.
65213   - Simplify the build system further for when development packages for various backends are not installed.
65214     With this change, when the compiler supports __has_include, backends without the relevant development
65215     packages installed will be ignored. This fixes the build for old versions of MinGW.
65216   - Fixes to the Android build.
65217   - Add mal_convert_frames(). This is a high-level helper API for performing a one-time, bulk conversion of
65218     audio data to a different format.
65219   - Improvements to f32 -> u8/s16/s24/s32 conversion routines.
65220   - Fix a bug where the wrong value is returned from mal_device_start() for the OpenSL backend.
65221   - Fixes and improvements for Raspberry Pi.
65222   - Warning fixes.
65223
65224 v0.5 - 2017-11-11
65225   - API CHANGE: The mal_context_init() function now takes a pointer to a mal_context_config object for
65226     configuring the context. The works in the same kind of way as the device config. The rationale for this
65227     change is to give applications better control over context-level properties, add support for backend-
65228     specific configurations, and support extensibility without breaking the API.
65229   - API CHANGE: The alsa.preferPlugHW device config variable has been removed since it's not really useful for
65230     anything anymore.
65231   - ALSA: By default, device enumeration will now only enumerate over unique card/device pairs. Applications
65232     can enable verbose device enumeration by setting the alsa.useVerboseDeviceEnumeration context config
65233     variable.
65234   - ALSA: When opening a device in shared mode (the default), the dmix/dsnoop plugin will be prioritized. If
65235     this fails it will fall back to the hw plugin. With this change the preferExclusiveMode config is now
65236     honored. Note that this does not happen when alsa.useVerboseDeviceEnumeration is set to true (see above)
65237     which is by design.
65238   - ALSA: Add support for excluding the "null" device using the alsa.excludeNullDevice context config variable.
65239   - ALSA: Fix a bug with channel mapping which causes an assertion to fail.
65240   - Fix errors with enumeration when pInfo is set to NULL.
65241   - OSS: Fix a bug when starting a device when the client sends 0 samples for the initial buffer fill.
65242
65243 v0.4 - 2017-11-05
65244   - API CHANGE: The log callback is now per-context rather than per-device and as is thus now passed to
65245     mal_context_init(). The rationale for this change is that it allows applications to capture diagnostic
65246     messages at the context level. Previously this was only available at the device level.
65247   - API CHANGE: The device config passed to mal_device_init() is now const.
65248   - Added support for OSS which enables support on BSD platforms.
65249   - Added support for WinMM (waveOut/waveIn).
65250   - Added support for UWP (Universal Windows Platform) applications. Currently C++ only.
65251   - Added support for exclusive mode for selected backends. Currently supported on WASAPI.
65252   - POSIX builds no longer require explicit linking to libpthread (-lpthread).
65253   - ALSA: Explicit linking to libasound (-lasound) is no longer required.
65254   - ALSA: Latency improvements.
65255   - ALSA: Use MMAP mode where available. This can be disabled with the alsa.noMMap config.
65256   - ALSA: Use "hw" devices instead of "plughw" devices by default. This can be disabled with the
65257     alsa.preferPlugHW config.
65258   - WASAPI is now the highest priority backend on Windows platforms.
65259   - Fixed an error with sample rate conversion which was causing crackling when capturing.
65260   - Improved error handling.
65261   - Improved compiler support.
65262   - Miscellaneous bug fixes.
65263
65264 v0.3 - 2017-06-19
65265   - API CHANGE: Introduced the notion of a context. The context is the highest level object and is required for
65266     enumerating and creating devices. Now, applications must first create a context, and then use that to
65267     enumerate and create devices. The reason for this change is to ensure device enumeration and creation is
65268     tied to the same backend. In addition, some backends are better suited to this design.
65269   - API CHANGE: Removed the rewinding APIs because they're too inconsistent across the different backends, hard
65270     to test and maintain, and just generally unreliable.
65271   - Added helper APIs for initializing mal_device_config objects.
65272   - Null Backend: Fixed a crash when recording.
65273   - Fixed build for UWP.
65274   - Added support for f32 formats to the OpenSL|ES backend.
65275   - Added initial implementation of the WASAPI backend.
65276   - Added initial implementation of the OpenAL backend.
65277   - Added support for low quality linear sample rate conversion.
65278   - Added early support for basic channel mapping.
65279
65280 v0.2 - 2016-10-28
65281   - API CHANGE: Add user data pointer as the last parameter to mal_device_init(). The rationale for this
65282     change is to ensure the logging callback has access to the user data during initialization.
65283   - API CHANGE: Have device configuration properties be passed to mal_device_init() via a structure. Rationale:
65284     1) The number of parameters is just getting too much.
65285     2) It makes it a bit easier to add new configuration properties in the future. In particular, there's a
65286        chance there will be support added for backend-specific properties.
65287   - Dropped support for f64, A-law and Mu-law formats since they just aren't common enough to justify the
65288     added maintenance cost.
65289   - DirectSound: Increased the default buffer size for capture devices.
65290   - Added initial implementation of the OpenSL|ES backend.
65291
65292 v0.1 - 2016-10-21
65293   - Initial versioned release.
65294 */
65295
65296
65297 /*
65298 This software is available as a choice of the following licenses. Choose
65299 whichever you prefer.
65300
65301 ===============================================================================
65302 ALTERNATIVE 1 - Public Domain (www.unlicense.org)
65303 ===============================================================================
65304 This is free and unencumbered software released into the public domain.
65305
65306 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
65307 software, either in source code form or as a compiled binary, for any purpose,
65308 commercial or non-commercial, and by any means.
65309
65310 In jurisdictions that recognize copyright laws, the author or authors of this
65311 software dedicate any and all copyright interest in the software to the public
65312 domain. We make this dedication for the benefit of the public at large and to
65313 the detriment of our heirs and successors. We intend this dedication to be an
65314 overt act of relinquishment in perpetuity of all present and future rights to
65315 this software under copyright law.
65316
65317 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65318 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65319 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65320 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
65321 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
65322 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
65323
65324 For more information, please refer to <http://unlicense.org/>
65325
65326 ===============================================================================
65327 ALTERNATIVE 2 - MIT No Attribution
65328 ===============================================================================
65329 Copyright 2020 David Reid
65330
65331 Permission is hereby granted, free of charge, to any person obtaining a copy of
65332 this software and associated documentation files (the "Software"), to deal in
65333 the Software without restriction, including without limitation the rights to
65334 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
65335 of the Software, and to permit persons to whom the Software is furnished to do
65336 so.
65337
65338 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65339 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
65340 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
65341 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
65342 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65343 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65344 SOFTWARE.
65345 */