Files
miniaudio/docs/manual/index.html
T
2020-10-30 20:28:57 +10:00

3163 lines
114 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>miniaudio - A single file audio playback and capture library.</title>
<meta name="description" content="miniaudio is a single file audio playback and capture library written in C.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="../../img/favicon.png">
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-81135233-2"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-81135233-2');
</script>
<style>
body {
font-family:sans-serif;
font-size:11pt;
line-height:18pt;
background-color:#003800;
}
h1,h2 {
color:#333;
line-height:0.2em;
margin-bottom:0;
padding:0;
}
h1.man {
margin-top:2em;
}
h2.man {
margin-top:1.5em;
}
a {
text-decoration:none;
color:#28f;
}
a:hover {
text-decoration:underline;
color:#26d;
}
.a-download {
text-decoration:none;
color:#ddd;
border:solid 1px #000;
border-radius:4px;
padding:16px 32px;
background-color:#003800;
}
.a-download:hover {
background-color:#003000;
text-decoration:none;
color:#ddd;
}
.a-sublink {
font-size:11pt;
}
#preview {
font-family:monospace;
font-size:10pt;
text-align:left;
}
.footer-links {
margin: 0px;
margin-bottom: 10px;
padding: 0px;
}
.footer-links li {
display: inline;
padding: 0 2px;
}
.footer-links li:first-child {
padding-left: 0;
}
.feature-header {
color:#666;
font-size: 24pt;
font-weight:bold;
}
.feature-header2 {
color:#444;
font-size: 1.5em;
font-weight:bold;
/*margin-bottom:1em;*/
line-height: 1em;
text-align:left;
}
.header-link-table {
}
.header-link-table td {
padding-right:1em;
vertical-align:center;
line-height:0;
/*border:solid 1px #f00;*/
}
.header-link-table a {
/*color:#e0d7cf;*/
color:#dddddd;
text-decoration:none;
}
.header-link-table a:hover {
color:#ffffff;
}
.footer-link {
color:#e0d7cf;
text-decoration:none;
}
.footer-link:hover {
color:#ffffff;
}
.mobile-main-link {
text-align:left;
background-color:#e0d7cf;
color:#036;
border-bottom:solid 1px #333;
padding-left:16px;
}
.mobile-main-link a {
display:block;
padding-top:8px;
padding-bottom:8px;
color:#036;
width:100%;
height:100%;
max-width:100%;
}
table.doc {
border:solid 0px #333;
border-collapse:collapse;
}
th.doc, td.doc {
padding:0.5em;
}
th.doc {
border:solid 1px #003800;
background-color:#003800;
color:#FFF;
text-align:left;
}
td.doc {
border:solid 1px #666;
}
td.doc p, th.doc p {
padding:0;
margin:0;
}
a.doc-navigation {
display:block;
padding:0.5em;
color:#003800;
border-bottom:solid 1px #bbbbbb;
}
a.doc-navigation:hover {
color:#fff;
background-color:#003800;
text-decoration:none;
/*border-bottom:solid 1px #003800;*/
}
/*
a.doc-navigation:hover {
background-color:#c5ecc5;
text-decoration:none;
}
*/
a.doc-navigation-active {
background-color:#cccccc;
}
a.doc-navigation-active:hover {
color:#003800;
background-color:#cccccc;
}
a.doc-navigation-l1 {
padding:0.1em;
padding-left:1.5em;
}
a.doc-navigation-l2 {
padding:0.1em;
padding-left:3em;
}
a.doc-navigation-l3 {
padding:0.1em;
padding-left:4em;
}
a.doc-navigation-l4 {
padding:0.1em;
padding-left:5em;
}
</style>
</head>
<body style="margin:0; padding:0">
<div style="background-color:#003800; color:#bfa792;">
<div style="max-width:100%; width:100%; margin:0 auto;">
<table class="header-link-table" style="border-collapse:collapse; border-spacing:0; padding:0; padding-right:1em;">
<tr>
<td style="padding:0.75em; width:100%; text-align:left;">
<table class="header-link-table" style="border-collapse:collapse; margin:0; padding:0">
<tr>
<td style="vertical-align:bottom; padding:0em; padding-right:2em;"><a href="../../index.html"><img src="../../img/logo1_large_white.png" style="height:24px; min-width:100%;"></a></td>
<td><a href="index.html">Documentation</a></td>
<td><a href="../examples/index.html">Examples</a></td>
</tr>
</table>
</td>
<td style="padding:0.1em; width:25%; text-align:right; vertical-align:center;">
<a href="https://discord.gg/9vpqbjU"><img src="../../img/Discord-Logo-White.svg" style="margin:0; padding:0; height:32px; width:32px;"></a>
</td>
<td style="padding:0.1em; width:25%; text-align:right; vertical-align:center;">
<a href="https://twitter.com/mackron"><img src="../../img/twitter_white.png" style="margin:0; padding:0; height:32px; width:32px;"></a>
</td>
<td style="padding:0.1em; padding-right:1em; width:25%; text-align:right; vertical-align:center;">
<a href="https://github.com/mackron/miniaudio"><img src="../../img/github_white.png" style="margin:0; padding:0; height:24px; width:24px;"></a>
</td>
</tr>
</table>
</div>
</div>
<div style="background-color:#fff; padding-bottom:0em; border-top:solid 1px #003800; background-color:#eee;">
<table border="0" style="margin:0 auto; width:100%; border-collapse:collapse; border:solid 0px #000; table-layout:fixed;"><tr>
<td valign="top" style="width:20em; padding:0; margin:0; border-right:solid 0px #000;"><div style="position:relative; height:100%; width:100%; border:solid 0px #000; padding:0; margin:0;">
<a href="../index.html" class="doc-navigation">Documentation Home</a><a href="index.html" class="doc-navigation doc-navigation-active">Programming Manual</a><a href="#Introduction" class="doc-navigation doc-navigation-l1">Introduction</a><a href="#Building" class="doc-navigation doc-navigation-l1">Building</a><a href="#Definitions" class="doc-navigation doc-navigation-l1">Definitions</a><a href="#Decoding" class="doc-navigation doc-navigation-l1">Decoding</a><a href="#Encoding" class="doc-navigation doc-navigation-l1">Encoding</a><a href="#DataConversion" class="doc-navigation doc-navigation-l1">Data Conversion</a><a href="#Filtering" class="doc-navigation doc-navigation-l1">Filtering</a><a href="#WaveformandNoiseGeneration" class="doc-navigation doc-navigation-l1">Waveform and Noise Generation</a><a href="#AudioBuffers" class="doc-navigation doc-navigation-l1">Audio Buffers</a><a href="#RingBuffers" class="doc-navigation doc-navigation-l1">Ring Buffers</a><a href="#Backends" class="doc-navigation doc-navigation-l1">Backends</a><a href="#MiscellaneousNotes" class="doc-navigation doc-navigation-l1">Miscellaneous Notes</a><a href="../examples/index.html" class="doc-navigation">Examples</a><a href="../api/index.html" class="doc-navigation" style="border-bottom:none;">API Reference</a></div></td><td valign="top" style="padding:1em; border-left:solid 1px #bbb;">
<div style="text-align:center; padding:1em; padding-bottom:2em;"><div style="text-align:center; overflow:hidden;"><img src="../../img/logo1_large.png" style="width:auto; height:auto; min-height:70px; overflow:hidden;"></div><div style="padding-top:1em; font-weight:bold; font-size:2em; color:#444;">Programming Manual</div><div style="padding-top:0.75em; text-align:center;"><a href="../examples/index.html">Examples</a> - <a href="../api/index.html">API Reference</a> - <a href="https://github.com/mackron/miniaudio">Source Code</a></div></div>
<p>
</p>
<h1 id="Introduction" class="man">1. Introduction</h1>
<p>
miniaudio is a single file library for audio playback and capture. To use it, do the following in one .c file:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#666666">#define</span> MINIAUDIO_IMPLEMENTATION
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;miniaudio.h&quot;</span>
</pre></div><p>
You can do <span style="font-family:monospace;">#include &quot;miniaudio.h&quot;</span> in other parts of the program just like any other header.
</p>
<p>
miniaudio uses the concept of a &quot;device&quot; as the abstraction for physical devices. The idea is that you choose a physical device to emit or capture audio from,
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
initializing the device.
</p>
<p>
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
the callback, the size of the internal buffer and the ID of the device you want to emit or capture audio from.
</p>
<p>
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
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,
but you could allocate it on the heap if that suits your situation better.
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0033ff">void</span> data_callback(<span style="color:#0099cc">ma_device</span>* pDevice, <span style="color:#0033ff">void</span>* pOutput, <span style="color:#0033ff">const</span> <span style="color:#0033ff">void</span>* pInput, <span style="color:#0099cc">ma_uint32</span> frameCount)
{
<span style="color:#009900">// In playback mode copy data to pOutput. In capture mode read data from pInput. In full-duplex mode, both</span>
<span style="color:#009900">// pOutput and pInput will be valid and you can move data from pInput into pOutput. Never process more than</span>
<span style="color:#009900">// frameCount frames.</span>
}
<span style="color:#0033ff">int</span> main()
{
<span style="color:#0099cc">ma_device_config</span> config = ma_device_config_init(ma_device_type_playback);
config.playback.format = ma_format_f32; <span style="color:#009900">// Set to ma_format_unknown to use the device&#39;s native format.</span>
config.playback.channels = 2; <span style="color:#009900">// Set to 0 to use the device&#39;s native channel count.</span>
config.sampleRate = 48000; <span style="color:#009900">// Set to 0 to use the device&#39;s native sample rate.</span>
config.dataCallback = data_callback; <span style="color:#009900">// This function will be called when miniaudio needs more data.</span>
config.pUserData = pMyCustomData; <span style="color:#009900">// Can be accessed from the device object (device.pUserData).</span>
<span style="color:#0099cc">ma_device</span> device;
<span style="color:#0033ff">if</span> (ma_device_init(NULL, &amp;config, &amp;device) != MA_SUCCESS) {
<span style="color:#0033ff">return</span> -1; <span style="color:#009900">// Failed to initialize the device.</span>
}
ma_device_start(&amp;device); <span style="color:#009900">// The device is sleeping by default so you&#39;ll need to start it manually.</span>
<span style="color:#009900">// Do something here. Probably your program&#39;s main loop.</span>
ma_device_uninit(&amp;device); <span style="color:#009900">// This will stop the device so no need to do that manually.</span>
<span style="color:#0033ff">return</span> 0;
}
</pre></div><p>
In the example above, <span style="font-family:monospace;">data_callback()</span> is where audio data is written and read from the device. The idea is in playback mode you cause sound to be emitted
from the speakers by writing audio data to the output buffer (<span style="font-family:monospace;">pOutput</span> in the example). In capture mode you read data from the input buffer (<span style="font-family:monospace;">pInput</span>) to
extract sound captured by the microphone. The <span style="font-family:monospace;">frameCount</span> parameter tells you how many frames can be written to the output buffer and read from the input
buffer. A &quot;frame&quot; 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.
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
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
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
for the second frame, etc.
</p>
<p>
The configuration of the device is defined by the <span style="font-family:monospace;">ma_device_config</span> structure. The config object is always initialized with <span style="font-family:monospace;">ma_device_config_init()</span>. It&#39;s
important to always initialize the config with this function as it initializes it with logical defaults and ensures your program doesn&#39;t break when new members
are added to the <span style="font-family:monospace;">ma_device_config</span> structure. The example above uses a fairly simple and standard device configuration. The call to <span style="font-family:monospace;">ma_device_config_init()</span>
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
backends). The <span style="font-family:monospace;">config.playback.format</span> member sets the sample format which can be one of the following (all formats are native-endian):
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Symbol</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
<th class="doc" valign="top"><p>
Range</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_f32</p>
</td>
<td class="doc" valign="top"><p>
32-bit floating point</p>
</td>
<td class="doc" valign="top"><p>
[-1, 1]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_s16</p>
</td>
<td class="doc" valign="top"><p>
16-bit signed integer</p>
</td>
<td class="doc" valign="top"><p>
[-32768, 32767]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_s24</p>
</td>
<td class="doc" valign="top"><p>
24-bit signed integer (tightly packed)</p>
</td>
<td class="doc" valign="top"><p>
[-8388608, 8388607]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_s32</p>
</td>
<td class="doc" valign="top"><p>
32-bit signed integer</p>
</td>
<td class="doc" valign="top"><p>
[-2147483648, 2147483647]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_u8</p>
</td>
<td class="doc" valign="top"><p>
8-bit unsigned integer</p>
</td>
<td class="doc" valign="top"><p>
[0, 255]</p>
</td>
</tr>
</table></div><p>
The <span style="font-family:monospace;">config.playback.channels</span> member sets the number of channels to use with the device. The channel count cannot exceed MA_MAX_CHANNELS. The
<span style="font-family:monospace;">config.sampleRate</span> member sets the sample rate (which must be the same for both playback and capture in full-duplex configurations). This is usually set to
44100 or 48000, but can be set to anything. It&#39;s recommended to keep this between 8000 and 384000, however.
</p>
<p>
Note that leaving the format, channel count and/or sample rate at their default values will result in the internal device&#39;s native configuration being used
which is useful if you want to avoid the overhead of miniaudio&#39;s automatic data conversion.
</p>
<p>
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
not passed into the callback as a parameter, but is instead set to the <span style="font-family:monospace;">pUserData</span> member of <span style="font-family:monospace;">ma_device</span> which you can access directly since all miniaudio
structures are transparent.
</p>
<p>
Initializing the device is done with <span style="font-family:monospace;">ma_device_init()</span>. This will return a result code telling you what went wrong, if anything. On success it will return
<span style="font-family:monospace;">MA_SUCCESS</span>. After initialization is complete the device will be in a stopped state. To start it, use <span style="font-family:monospace;">ma_device_start()</span>. Uninitializing the device will stop
it, which is what the example above does, but you can also stop the device with <span style="font-family:monospace;">ma_device_stop()</span>. To resume the device simply call <span style="font-family:monospace;">ma_device_start()</span> again.
Note that it&#39;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
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:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
ma_device_init()
ma_device_init_ex()
ma_device_uninit()
ma_device_start()
ma_device_stop()
</pre></div><p>
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
are a few other things you shouldn&#39;t do in the callback depending on your requirements, however this isn&#39;t so much a thread-safety thing, but rather a
real-time processing thing which is beyond the scope of this introduction.
</p>
<p>
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
from <span style="font-family:monospace;">ma_device_type_playback</span> to <span style="font-family:monospace;">ma_device_type_capture</span> when setting up the config, like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_device_config</span> config = ma_device_config_init(ma_device_type_capture);
config.capture.format = MY_FORMAT;
config.capture.channels = MY_CHANNEL_COUNT;
</pre></div><p>
In the data callback you just read from the input buffer (<span style="font-family:monospace;">pInput</span> in the example above) and leave the output buffer alone (it will be set to NULL when the
device type is set to <span style="font-family:monospace;">ma_device_type_capture</span>).
</p>
<p>
These are the available device types and how you should handle the buffers in the callback:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Device Type</p>
</th>
<th class="doc" valign="top"><p>
Callback Behavior</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_device_type_playback</p>
</td>
<td class="doc" valign="top"><p>
Write to output buffer, leave input buffer untouched.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_device_type_capture</p>
</td>
<td class="doc" valign="top"><p>
Read from input buffer, leave output buffer untouched.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_device_type_duplex</p>
</td>
<td class="doc" valign="top"><p>
Read from input buffer, write to output buffer.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_device_type_loopback</p>
</td>
<td class="doc" valign="top"><p>
Read from input buffer, leave output buffer untouched.</p>
</td>
</tr>
</table></div><p>
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
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
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
will need to convert the data yourself. There are functions available to help you do this which will be explained later.
</p>
<p>
The example above did not specify a physical device to connect to which means it will use the operating system&#39;s default device. If you have multiple physical
devices connected and you want to use a specific one you will need to specify the device ID in the configuration, like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
config.playback.pDeviceID = pMyPlaybackDeviceID; <span style="color:#009900">// Only if requesting a playback or duplex device.</span>
config.capture.pDeviceID = pMyCaptureDeviceID; <span style="color:#009900">// Only if requesting a capture, duplex or loopback device.</span>
</pre></div><p>
To retrieve the device ID you will need to perform device enumeration, however this requires the use of a new concept called the &quot;context&quot;. Conceptually
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
and to perform operations outside the scope of an individual device. Mainly it is used for performing run-time linking against backend libraries, initializing
backends and enumerating devices. The example below shows how to enumerate devices.
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_context</span> context;
<span style="color:#0033ff">if</span> (ma_context_init(NULL, 0, NULL, &amp;context) != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
<span style="color:#0099cc">ma_device_info</span>* pPlaybackInfos;
<span style="color:#0099cc">ma_uint32</span> playbackCount;
<span style="color:#0099cc">ma_device_info</span>* pCaptureInfos;
<span style="color:#0099cc">ma_uint32</span> captureCount;
<span style="color:#0033ff">if</span> (ma_context_get_devices(&amp;context, &amp;pPlaybackInfos, &amp;playbackCount, &amp;pCaptureInfos, &amp;captureCount) != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
<span style="color:#009900">// Loop over each device info and do something with it. Here we just print the name with their index. You may want</span>
<span style="color:#009900">// to give the user the opportunity to choose which device they&#39;d prefer.</span>
<span style="color:#0033ff">for</span> (<span style="color:#0099cc">ma_uint32</span> iDevice = 0; iDevice &lt; playbackCount; iDevice += 1) {
printf(<span style="color:#cc3300">&quot;%d - %s\n&quot;</span>, iDevice, pPlaybackInfos[iDevice].name);
}
<span style="color:#0099cc">ma_device_config</span> config = ma_device_config_init(ma_device_type_playback);
config.playback.pDeviceID = &amp;pPlaybackInfos[chosenPlaybackDeviceIndex].id;
config.playback.format = MY_FORMAT;
config.playback.channels = MY_CHANNEL_COUNT;
config.sampleRate = MY_SAMPLE_RATE;
config.dataCallback = data_callback;
config.pUserData = pMyCustomData;
<span style="color:#0099cc">ma_device</span> device;
<span style="color:#0033ff">if</span> (ma_device_init(&amp;context, &amp;config, &amp;device) != MA_SUCCESS) {
<span style="color:#009900">// Error</span>
}
...
ma_device_uninit(&amp;device);
ma_context_uninit(&amp;context);
</pre></div><p>
The first thing we do in this example is initialize a <span style="font-family:monospace;">ma_context</span> object with <span style="font-family:monospace;">ma_context_init()</span>. The first parameter is a pointer to a list of <span style="font-family:monospace;">ma_backend</span>
values which are used to override the default backend priorities. When this is NULL, as in this example, miniaudio&#39;s default priorities are used. The second
parameter is the number of backends listed in the array pointed to by the first parameter. The third parameter is a pointer to a <span style="font-family:monospace;">ma_context_config</span> object
which can be NULL, in which case defaults are used. The context configuration is used for setting the logging callback, custom memory allocation callbacks,
user-defined data and some backend-specific configurations.
</p>
<p>
Once the context has been initialized you can enumerate devices. In the example above we use the simpler <span style="font-family:monospace;">ma_context_get_devices()</span>, however you can also use a
callback for handling devices by using <span style="font-family:monospace;">ma_context_enumerate_devices()</span>. When using <span style="font-family:monospace;">ma_context_get_devices()</span> you provide a pointer to a pointer that will,
upon output, be set to a pointer to a buffer containing a list of <span style="font-family:monospace;">ma_device_info</span> structures. You also provide a pointer to an unsigned integer that will
receive the number of items in the returned buffer. Do not free the returned buffers as their memory is managed internally by miniaudio.
</p>
<p>
The <span style="font-family:monospace;">ma_device_info</span> structure contains an <span style="font-family:monospace;">id</span> member which is the ID you pass to the device config. It also contains the name of the device which is useful
for presenting a list of devices to the user via the UI.
</p>
<p>
When creating your own context you will want to pass it to <span style="font-family:monospace;">ma_device_init()</span> when initializing the device. Passing in NULL, like we do in the first example,
will result in miniaudio creating the context for you, which you don&#39;t want to do since you&#39;ve already created a context. Note that internally the context is
only tracked by it&#39;s pointer which means you must not change the location of the <span style="font-family:monospace;">ma_context</span> object. If this is an issue, consider using <span style="font-family:monospace;">malloc()</span> to
allocate memory for the context.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h1 id="Building" class="man">2. Building</h1>
<p>
miniaudio should work cleanly out of the box without the need to download or install any dependencies. See below for platform-specific details.
</p>
<p>
</p>
<p>
</p>
<h2 id="Windows" class="man">2.1. Windows</h2>
<p>
The Windows build should compile cleanly on all popular compilers without the need to configure any include paths nor link to any libraries.
</p>
<p>
</p>
<h2 id="macOSandiOS" class="man">2.2. macOS and iOS</h2>
<p>
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
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
requires linking to <span style="font-family:monospace;">-lpthread</span> and <span style="font-family:monospace;">-lm</span>.
</p>
<p>
Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple&#39;s notarization process. To fix this there are two options. The
first is to use the <span style="font-family:monospace;">MA_NO_RUNTIME_LINKING</span> option, like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#666666">#ifdef</span> __APPLE__
<span style="color:#666666">#define</span> MA_NO_RUNTIME_LINKING
<span style="color:#666666">#endif</span>
<span style="color:#666666">#define</span> MINIAUDIO_IMPLEMENTATION
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;miniaudio.h&quot;</span>
</pre></div><p>
This will require linking with <span style="font-family:monospace;">-framework CoreFoundation -framework CoreAudio -framework AudioUnit</span>. Alternatively, if you would rather keep using runtime
linking you can add the following to your entitlements.xcent file:
</p>
<p>
</p>
<div style="font-family:monospace; margin:1em 0em;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
&lt;key&gt;com.apple.security.cs.allow-dyld-environment-variables&lt;/key&gt;
&lt;true/&gt;
&lt;key&gt;com.apple.security.cs.allow-unsigned-executable-memory&lt;/key&gt;
&lt;true/&gt;
</pre></div><p>
</p>
<p>
</p>
<h2 id="Linux" class="man">2.3. Linux</h2>
<p>
The Linux build only requires linking to <span style="font-family:monospace;">-ldl</span>, <span style="font-family:monospace;">-lpthread</span> and <span style="font-family:monospace;">-lm</span>. You do not need any development packages.
</p>
<p>
</p>
<h2 id="BSD" class="man">2.4. BSD</h2>
<p>
The BSD build only requires linking to <span style="font-family:monospace;">-lpthread</span> and <span style="font-family:monospace;">-lm</span>. NetBSD uses audio(4), OpenBSD uses sndio and FreeBSD uses OSS.
</p>
<p>
</p>
<h2 id="Android" class="man">2.5. Android</h2>
<p>
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
starts with Android 8 which means older versions will fall back to OpenSL|ES which requires API level 16+.
</p>
<p>
</p>
<h2 id="Emscripten" class="man">2.6. Emscripten</h2>
<p>
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.
</p>
<p>
</p>
<p>
</p>
<h2 id="BuildOptions" class="man">2.7. Build Options</h2>
<p>
<span style="font-family:monospace;">#define</span> these options before including miniaudio.h.
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Option</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_WASAPI</p>
</td>
<td class="doc" valign="top"><p>
Disables the WASAPI backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_DSOUND</p>
</td>
<td class="doc" valign="top"><p>
Disables the DirectSound backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_WINMM</p>
</td>
<td class="doc" valign="top"><p>
Disables the WinMM backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_ALSA</p>
</td>
<td class="doc" valign="top"><p>
Disables the ALSA backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_PULSEAUDIO</p>
</td>
<td class="doc" valign="top"><p>
Disables the PulseAudio backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_JACK</p>
</td>
<td class="doc" valign="top"><p>
Disables the JACK backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_COREAUDIO</p>
</td>
<td class="doc" valign="top"><p>
Disables the Core Audio backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_SNDIO</p>
</td>
<td class="doc" valign="top"><p>
Disables the sndio backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_AUDIO4</p>
</td>
<td class="doc" valign="top"><p>
Disables the audio(4) backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_OSS</p>
</td>
<td class="doc" valign="top"><p>
Disables the OSS backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_AAUDIO</p>
</td>
<td class="doc" valign="top"><p>
Disables the AAudio backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_OPENSL</p>
</td>
<td class="doc" valign="top"><p>
Disables the OpenSL</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_WEBAUDIO</p>
</td>
<td class="doc" valign="top"><p>
Disables the Web Audio backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_NULL</p>
</td>
<td class="doc" valign="top"><p>
Disables the null backend.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_DECODING</p>
</td>
<td class="doc" valign="top"><p>
Disables decoding APIs.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_ENCODING</p>
</td>
<td class="doc" valign="top"><p>
Disables encoding APIs.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_WAV</p>
</td>
<td class="doc" valign="top"><p>
Disables the built-in WAV decoder and encoder.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_FLAC</p>
</td>
<td class="doc" valign="top"><p>
Disables the built-in FLAC decoder.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_MP3</p>
</td>
<td class="doc" valign="top"><p>
Disables the built-in MP3 decoder.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_DEVICE_IO
</p>
</td>
<td class="doc" valign="top"><p>
Disables playback and recording. This will disable ma_context and ma_device APIs. This is useful if you only want to use
miniaudio&#39;s data conversion and/or decoding APIs.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_THREADING
</p>
<p>
</p>
<p>
</p>
</td>
<td class="doc" valign="top"><p>
Disables the ma_thread, ma_mutex, ma_semaphore and ma_event APIs. This option is useful if you only need to use miniaudio for
data conversion, decoding and/or encoding. Some families of APIs require threading which means the following options must also
be set:
</p>
<div style="font-family:monospace; margin:1em 0em;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
MA_NO_DEVICE_IO
</pre></div></td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_GENERATION</p>
</td>
<td class="doc" valign="top"><p>
Disables generation APIs such a ma_waveform and ma_noise.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_SSE2</p>
</td>
<td class="doc" valign="top"><p>
Disables SSE2 optimizations.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_AVX2</p>
</td>
<td class="doc" valign="top"><p>
Disables AVX2 optimizations.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_AVX512</p>
</td>
<td class="doc" valign="top"><p>
Disables AVX-512 optimizations.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_NO_NEON</p>
</td>
<td class="doc" valign="top"><p>
Disables NEON optimizations.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_LOG_LEVEL [level]
</p>
<p>
</p>
<p>
</p>
<p>
</p>
</td>
<td class="doc" valign="top"><p>
Sets the logging level. Set level to one of the following:
</p>
<div style="font-family:monospace; margin:1em 0em;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
MA_LOG_LEVEL_VERBOSE
MA_LOG_LEVEL_INFO
MA_LOG_LEVEL_WARNING
MA_LOG_LEVEL_ERROR
</pre></div></td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_DEBUG_OUTPUT</p>
</td>
<td class="doc" valign="top"><p>
Enable printf() debug output.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_COINIT_VALUE</p>
</td>
<td class="doc" valign="top"><p>
Windows only. The value to pass to internal calls to <span style="font-family:monospace;">CoInitializeEx()</span>. Defaults to <span style="font-family:monospace;">COINIT_MULTITHREADED</span>.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_API</p>
</td>
<td class="doc" valign="top"><p>
Controls how public APIs should be decorated. Defaults to <span style="font-family:monospace;">extern</span>.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MA_DLL
</p>
</td>
<td class="doc" valign="top"><p>
If set, configures MA_API to either import or export APIs depending on whether or not the implementation is being defined. If
defining the implementation, MA_API will be configured to export. Otherwise it will be configured to import. This has no effect
if MA_API is defined externally.</p>
</td>
</tr>
</table></div><p>
</p>
<h1 id="Definitions" class="man">3. Definitions</h1>
<p>
This section defines common terms used throughout miniaudio. Unfortunately there is often ambiguity in the use of terms throughout the audio space, so this
section is intended to clarify how miniaudio uses each term.
</p>
<p>
</p>
<h2 id="Sample" class="man">3.1. Sample</h2>
<p>
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.
</p>
<p>
</p>
<h2 id="Frame/PCMFrame" class="man">3.2. Frame / PCM Frame</h2>
<p>
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
is 6 samples, etc. The terms &quot;frame&quot; and &quot;PCM frame&quot; are the same thing in miniaudio. Note that this is different to a compressed frame. If ever miniaudio
needs to refer to a compressed frame, such as a FLAC frame, it will always clarify what it&#39;s referring to with something like &quot;FLAC frame&quot;.
</p>
<p>
</p>
<h2 id="Channel" class="man">3.3. Channel</h2>
<p>
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
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
a complex audio stream that&#39;s mixed with other channels to produce the final mix - this is completely different to miniaudio&#39;s use of the term &quot;channel&quot; and
should not be confused.
</p>
<p>
</p>
<h2 id="SampleRate" class="man">3.4. Sample Rate</h2>
<p>
The sample rate in miniaudio is always expressed in Hz, such as 44100, 48000, etc. It&#39;s the number of PCM frames that are processed per second.
</p>
<p>
</p>
<h2 id="Formats" class="man">3.5. Formats</h2>
<p>
Throughout miniaudio you will see references to different sample formats:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Symbol</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
<th class="doc" valign="top"><p>
Range</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_f32</p>
</td>
<td class="doc" valign="top"><p>
32-bit floating point</p>
</td>
<td class="doc" valign="top"><p>
[-1, 1]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_s16</p>
</td>
<td class="doc" valign="top"><p>
16-bit signed integer</p>
</td>
<td class="doc" valign="top"><p>
[-32768, 32767]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_s24</p>
</td>
<td class="doc" valign="top"><p>
24-bit signed integer (tightly packed)</p>
</td>
<td class="doc" valign="top"><p>
[-8388608, 8388607]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_s32</p>
</td>
<td class="doc" valign="top"><p>
32-bit signed integer</p>
</td>
<td class="doc" valign="top"><p>
[-2147483648, 2147483647]</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_format_u8</p>
</td>
<td class="doc" valign="top"><p>
8-bit unsigned integer</p>
</td>
<td class="doc" valign="top"><p>
[0, 255]</p>
</td>
</tr>
</table></div><p>
All formats are native-endian.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h1 id="Decoding" class="man">4. Decoding</h1>
<p>
The <span style="font-family:monospace;">ma_decoder</span> API is used for reading audio files. The following formats are supported:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Format</p>
</th>
<th class="doc" valign="top"><p>
Decoding Backend</p>
</th>
<th class="doc" valign="top"><p>
Built-In</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
WAV</p>
</td>
<td class="doc" valign="top"><p>
dr_wav</p>
</td>
<td class="doc" valign="top"><p>
Yes</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
MP3</p>
</td>
<td class="doc" valign="top"><p>
dr_mp3</p>
</td>
<td class="doc" valign="top"><p>
Yes</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
FLAC</p>
</td>
<td class="doc" valign="top"><p>
dr_flac</p>
</td>
<td class="doc" valign="top"><p>
Yes</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Vorbis</p>
</td>
<td class="doc" valign="top"><p>
stb_vorbis</p>
</td>
<td class="doc" valign="top"><p>
No</p>
</td>
</tr>
</table></div><p>
Vorbis is supported via stb_vorbis which can be enabled by including the header section before the implementation of miniaudio, like the following:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#666666">#define</span> STB_VORBIS_HEADER_ONLY
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;extras/stb_vorbis.c&quot;</span> <span style="color:#009900">// Enables Vorbis decoding.</span>
<span style="color:#666666">#define</span> MINIAUDIO_IMPLEMENTATION
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;miniaudio.h&quot;</span>
<span style="color:#009900">// The stb_vorbis implementation must come after the implementation of miniaudio.</span>
<span style="color:#666666">#undef</span> STB_VORBIS_HEADER_ONLY
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;extras/stb_vorbis.c&quot;</span>
</pre></div><p>
A copy of stb_vorbis is included in the &quot;extras&quot; folder in the miniaudio repository (<a href="https://github.com/mackron/miniaudio">https://github.com/mackron/miniaudio</a>).
</p>
<p>
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
following options before the miniaudio implementation:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#666666">#define</span> MA_NO_WAV
<span style="color:#666666">#define</span> MA_NO_MP3
<span style="color:#666666">#define</span> MA_NO_FLAC
</pre></div><p>
Disabling built-in decoding libraries is useful if you use these libraries independantly of the <span style="font-family:monospace;">ma_decoder</span> API.
</p>
<p>
A decoder can be initialized from a file with <span style="font-family:monospace;">ma_decoder_init_file()</span>, a block of memory with <span style="font-family:monospace;">ma_decoder_init_memory()</span>, or from data delivered via callbacks
with <span style="font-family:monospace;">ma_decoder_init()</span>. Here is an example for loading a decoder from a file:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_decoder</span> decoder;
<span style="color:#0099cc">ma_result</span> result = ma_decoder_init_file(<span style="color:#cc3300">&quot;MySong.mp3&quot;</span>, NULL, &amp;decoder);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#0033ff">return</span> false; <span style="color:#009900">// An error occurred.</span>
}
...
ma_decoder_uninit(&amp;decoder);
</pre></div><p>
When initializing a decoder, you can optionally pass in a pointer to a ma_decoder_config object (the NULL argument in the example above) which allows you to
configure the output format, channel count, sample rate and channel map:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_decoder_config</span> config = ma_decoder_config_init(ma_format_f32, 2, 48000);
</pre></div><p>
When passing in NULL for decoder config in <span style="font-family:monospace;">ma_decoder_init*()</span>, the output format will be the same as that defined by the decoding backend.
</p>
<p>
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
PCM frames it means you&#39;ve reached the end:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_uint64</span> framesRead = ma_decoder_read_pcm_frames(pDecoder, pFrames, framesToRead);
<span style="color:#0033ff">if</span> (framesRead &lt; framesToRead) {
<span style="color:#009900">// Reached the end.</span>
}
</pre></div><p>
You can also seek to a specific frame like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_result</span> result = ma_decoder_seek_to_pcm_frame(pDecoder, targetFrame);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#0033ff">return</span> false; <span style="color:#009900">// An error occurred.</span>
}
</pre></div><p>
If you want to loop back to the start, you can simply seek back to the first PCM frame:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
ma_decoder_seek_to_pcm_frame(pDecoder, 0);
</pre></div><p>
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
is already known. In this case you can use the <span style="font-family:monospace;">_wav</span>, <span style="font-family:monospace;">_mp3</span>, etc. varients of the aforementioned initialization APIs:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
ma_decoder_init_wav()
ma_decoder_init_mp3()
ma_decoder_init_memory_wav()
ma_decoder_init_memory_mp3()
ma_decoder_init_file_wav()
ma_decoder_init_file_mp3()
etc.
</pre></div><p>
The <span style="font-family:monospace;">ma_decoder_init_file()</span> API will try using the file extension to determine which decoding backend to prefer.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h1 id="Encoding" class="man">5. Encoding</h1>
<p>
The <span style="font-family:monospace;">ma_encoding</span> 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
implementation section of miniaudio. This can be disabled by specifying the following option before the implementation of miniaudio:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#666666">#define</span> MA_NO_WAV
</pre></div><p>
An encoder can be initialized to write to a file with <span style="font-family:monospace;">ma_encoder_init_file()</span> or from data delivered via callbacks with <span style="font-family:monospace;">ma_encoder_init()</span>. Below is an
example for initializing an encoder to output to a file.
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_encoder_config</span> config = ma_encoder_config_init(ma_resource_format_wav, FORMAT, CHANNELS, SAMPLE_RATE);
<span style="color:#0099cc">ma_encoder</span> encoder;
<span style="color:#0099cc">ma_result</span> result = ma_encoder_init_file(<span style="color:#cc3300">&quot;my_file.wav&quot;</span>, &amp;config, &amp;encoder);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error</span>
}
...
ma_encoder_uninit(&amp;encoder);
</pre></div><p>
When initializing an encoder you must specify a config which is initialized with <span style="font-family:monospace;">ma_encoder_config_init()</span>. Here you must specify the file type, the output
sample format, output channel count and output sample rate. The following file types are supported:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Enum</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_resource_format_wav</p>
</td>
<td class="doc" valign="top"><p>
WAV</p>
</td>
</tr>
</table></div><p>
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
you will need to convert it before outputting any audio data. To output audio data, use <span style="font-family:monospace;">ma_encoder_write_pcm_frames()</span>, like in the example below:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
framesWritten = ma_encoder_write_pcm_frames(&amp;encoder, pPCMFramesToWrite, framesToWrite);
</pre></div><p>
Encoders must be uninitialized with <span style="font-family:monospace;">ma_encoder_uninit()</span>.
</p>
<p>
</p>
<p>
</p>
<h1 id="DataConversion" class="man">6. Data Conversion</h1>
<p>
A data conversion API is included with miniaudio which supports the majority of data conversion requirements. This supports conversion between sample formats,
channel counts (with channel mapping) and sample rates.
</p>
<p>
</p>
<p>
</p>
<h2 id="SampleFormatConversion" class="man">6.1. Sample Format Conversion</h2>
<p>
Conversion between sample formats is achieved with the <span style="font-family:monospace;">ma_pcm_*_to_*()</span>, <span style="font-family:monospace;">ma_pcm_convert()</span> and <span style="font-family:monospace;">ma_convert_pcm_frames_format()</span> APIs. Use <span style="font-family:monospace;">ma_pcm_*_to_*()</span>
to convert between two specific formats. Use <span style="font-family:monospace;">ma_pcm_convert()</span> to convert based on a <span style="font-family:monospace;">ma_format</span> variable. Use <span style="font-family:monospace;">ma_convert_pcm_frames_format()</span> to convert
PCM frames where you want to specify the frame count and channel count as a variable instead of the total sample count.
</p>
<p>
</p>
<p>
</p>
<h2 id="Dithering" class="man">6.1.1. Dithering</h2>
<p>
Dithering can be set using the ditherMode parameter.
</p>
<p>
The different dithering modes include the following, in order of efficiency:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Type</p>
</th>
<th class="doc" valign="top"><p>
Enum Token</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
None</p>
</td>
<td class="doc" valign="top"><p>
ma_dither_mode_none</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Rectangle</p>
</td>
<td class="doc" valign="top"><p>
ma_dither_mode_rectangle</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Triangle</p>
</td>
<td class="doc" valign="top"><p>
ma_dither_mode_triangle</p>
</td>
</tr>
</table></div><p>
Note that even if the dither mode is set to something other than <span style="font-family:monospace;">ma_dither_mode_none</span>, it will be ignored for conversions where dithering is not needed.
Dithering is available for the following conversions:
</p>
<p>
</p>
<div style="font-family:monospace; margin:1em 0em;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
s16 -&gt; u8
s24 -&gt; u8
s32 -&gt; u8
f32 -&gt; u8
s24 -&gt; s16
s32 -&gt; s16
f32 -&gt; s16
</pre></div><p>
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.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h2 id="ChannelConversion" class="man">6.2. Channel Conversion</h2>
<p>
Channel conversion is used for channel rearrangement and conversion from one channel count to another. The <span style="font-family:monospace;">ma_channel_converter</span> API is used for channel
conversion. Below is an example of initializing a simple channel converter which converts from mono to stereo.
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_channel_converter_config</span> config = ma_channel_converter_config_init(
ma_format, <span style="color:#009900">// Sample format</span>
1, <span style="color:#009900">// Input channels</span>
NULL, <span style="color:#009900">// Input channel map</span>
2, <span style="color:#009900">// Output channels</span>
NULL, <span style="color:#009900">// Output channel map</span>
ma_channel_mix_mode_default); <span style="color:#009900">// The mixing algorithm to use when combining channels.</span>
result = ma_channel_converter_init(&amp;config, &amp;converter);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
</pre></div><p>
To perform the conversion simply call <span style="font-family:monospace;">ma_channel_converter_process_pcm_frames()</span> like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_result</span> result = ma_channel_converter_process_pcm_frames(&amp;converter, pFramesOut, pFramesIn, frameCount);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
</pre></div><p>
It is up to the caller to ensure the output buffer is large enough to accomodate the new PCM frames.
</p>
<p>
Input and output PCM frames are always interleaved. Deinterleaved layouts are not supported.
</p>
<p>
</p>
<p>
</p>
<h2 id="ChannelMapping" class="man">6.2.1. Channel Mapping</h2>
<p>
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
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
channel map contains the same channel positions with the exception that they&#39;re in a different order, a simple shuffling of the channels will be performed. If,
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
specified when initializing the <span style="font-family:monospace;">ma_channel_converter_config</span> object.
</p>
<p>
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
channel is simply averaged and copied to the mono channel.
</p>
<p>
In more complicated cases blending is used. The <span style="font-family:monospace;">ma_channel_mix_mode_simple</span> mode will drop excess channels and silence extra channels. For example, converting
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.
</p>
<p>
The <span style="font-family:monospace;">ma_channel_mix_mode_rectangle</span> mode uses spacial locality based on a rectangle to compute a simple distribution between input and output. Imagine sitting
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
of the front and left walls.
</p>
<p>
Finally, the <span style="font-family:monospace;">ma_channel_mix_mode_custom_weights</span> mode can be used to use custom user-defined weights. Custom weights can be passed in as the last parameter of
<span style="font-family:monospace;">ma_channel_converter_config_init()</span>.
</p>
<p>
Predefined channel maps can be retrieved with <span style="font-family:monospace;">ma_get_standard_channel_map()</span>. This takes a <span style="font-family:monospace;">ma_standard_channel_map</span> enum as it&#39;s first parameter, which can
be one of the following:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Name</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_default</p>
</td>
<td class="doc" valign="top"><p>
Default channel map used by miniaudio. See below.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_microsoft</p>
</td>
<td class="doc" valign="top"><p>
Channel map used by Microsoft&#39;s bitfield channel maps.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_alsa</p>
</td>
<td class="doc" valign="top"><p>
Default ALSA channel map.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_rfc3551</p>
</td>
<td class="doc" valign="top"><p>
RFC 3551. Based on AIFF.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_flac</p>
</td>
<td class="doc" valign="top"><p>
FLAC channel map.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_vorbis</p>
</td>
<td class="doc" valign="top"><p>
Vorbis channel map.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_sound4</p>
</td>
<td class="doc" valign="top"><p>
FreeBSD&#39;s sound(4).</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_sndio</p>
</td>
<td class="doc" valign="top"><p>
sndio channel map. <a href="http://www.sndio.org/tips.html">http://www.sndio.org/tips.html</a>.</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_standard_channel_map_webaudio</p>
</td>
<td class="doc" valign="top"><p>
<a href="https://webaudio.github.io/web-audio-api/#ChannelOrdering">https://webaudio.github.io/web-audio-api/#ChannelOrdering</a></p>
</td>
</tr>
</table></div><p>
Below are the channel maps used by default in miniaudio (ma_standard_channel_map_default):
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Channel Count</p>
</th>
<th class="doc" valign="top"><p>
Mapping</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
1 (Mono)</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_MONO</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
2 (Stereo)
</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_FRONT_LEFT <br>
1: MA_CHANNEL_FRONT_RIGHT</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
3
</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_FRONT_LEFT <br>
1: MA_CHANNEL_FRONT_RIGHT <br>
2: MA_CHANNEL_FRONT_CENTER</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
4 (Surround)
</p>
<p>
</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_FRONT_LEFT <br>
1: MA_CHANNEL_FRONT_RIGHT <br>
2: MA_CHANNEL_FRONT_CENTER <br>
3: MA_CHANNEL_BACK_CENTER</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
5
</p>
<p>
</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_FRONT_LEFT <br>
1: MA_CHANNEL_FRONT_RIGHT <br>
2: MA_CHANNEL_FRONT_CENTER <br>
3: MA_CHANNEL_BACK_LEFT <br>
4: MA_CHANNEL_BACK_RIGHT</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
6 (5.1)
</p>
<p>
</p>
<p>
</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_FRONT_LEFT <br>
1: MA_CHANNEL_FRONT_RIGHT <br>
2: MA_CHANNEL_FRONT_CENTER <br>
3: MA_CHANNEL_LFE <br>
4: MA_CHANNEL_SIDE_LEFT <br>
5: MA_CHANNEL_SIDE_RIGHT</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
7
</p>
<p>
</p>
<p>
</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_FRONT_LEFT <br>
1: MA_CHANNEL_FRONT_RIGHT <br>
2: MA_CHANNEL_FRONT_CENTER <br>
3: MA_CHANNEL_LFE <br>
4: MA_CHANNEL_BACK_CENTER <br>
4: MA_CHANNEL_SIDE_LEFT <br>
5: MA_CHANNEL_SIDE_RIGHT</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
8 (7.1)
</p>
<p>
</p>
<p>
</p>
<p>
</p>
</td>
<td class="doc" valign="top"><p>
0: MA_CHANNEL_FRONT_LEFT <br>
1: MA_CHANNEL_FRONT_RIGHT <br>
2: MA_CHANNEL_FRONT_CENTER <br>
3: MA_CHANNEL_LFE <br>
4: MA_CHANNEL_BACK_LEFT <br>
5: MA_CHANNEL_BACK_RIGHT <br>
6: MA_CHANNEL_SIDE_LEFT <br>
7: MA_CHANNEL_SIDE_RIGHT</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Other
</p>
</td>
<td class="doc" valign="top"><p>
All channels set to 0. This
is equivalent to the same
mapping as the device.</p>
</td>
</tr>
</table></div><p>
</p>
<p>
</p>
<h2 id="Resampling" class="man">6.3. Resampling</h2>
<p>
Resampling is achieved with the <span style="font-family:monospace;">ma_resampler</span> object. To create a resampler object, do something like the following:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_resampler_config</span> config = ma_resampler_config_init(
ma_format_s16,
channels,
sampleRateIn,
sampleRateOut,
ma_resample_algorithm_linear);
<span style="color:#0099cc">ma_resampler</span> resampler;
<span style="color:#0099cc">ma_result</span> result = ma_resampler_init(&amp;config, &amp;resampler);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// An error occurred...</span>
}
</pre></div><p>
Do the following to uninitialize the resampler:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
ma_resampler_uninit(&amp;resampler);
</pre></div><p>
The following example shows how data can be processed
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_uint64</span> frameCountIn = 1000;
<span style="color:#0099cc">ma_uint64</span> frameCountOut = 2000;
<span style="color:#0099cc">ma_result</span> result = ma_resampler_process_pcm_frames(&amp;resampler, pFramesIn, &amp;frameCountIn, pFramesOut, &amp;frameCountOut);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// An error occurred...</span>
}
<span style="color:#009900">// At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the</span>
<span style="color:#009900">// number of output frames written.</span>
</pre></div><p>
To initialize the resampler you first need to set up a config (<span style="font-family:monospace;">ma_resampler_config</span>) with <span style="font-family:monospace;">ma_resampler_config_init()</span>. You need to specify the sample format
you want to use, the number of channels, the input and output sample rate, and the algorithm.
</p>
<p>
The sample format can be either <span style="font-family:monospace;">ma_format_s16</span> or <span style="font-family:monospace;">ma_format_f32</span>. If you need a different format you will need to perform pre- and post-conversions yourself
where necessary. Note that the format is the same for both input and output. The format cannot be changed after initialization.
</p>
<p>
The resampler supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization.
</p>
<p>
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
only configuration property that can be changed after initialization.
</p>
<p>
The miniaudio resampler supports multiple algorithms:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Algorithm</p>
</th>
<th class="doc" valign="top"><p>
Enum Token</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
Linear</p>
</td>
<td class="doc" valign="top"><p>
ma_resample_algorithm_linear</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Speex</p>
</td>
<td class="doc" valign="top"><p>
ma_resample_algorithm_speex</p>
</td>
</tr>
</table></div><p>
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
it&#39;s license, the text of which can be found in it&#39;s source files in &quot;extras/speex_resampler&quot;. Details on how to opt-in to the Speex resampler is explained in
the Speex Resampler section below.
</p>
<p>
The algorithm cannot be changed after initialization.
</p>
<p>
Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process
frames, use <span style="font-family:monospace;">ma_resampler_process_pcm_frames()</span>. On input, this function takes the number of output frames you can fit in the output buffer and the number 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
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
buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek.
</p>
<p>
The sample rate can be changed dynamically on the fly. You can change this with explicit sample rates with <span style="font-family:monospace;">ma_resampler_set_rate()</span> and also with a decimal
ratio with <span style="font-family:monospace;">ma_resampler_set_rate_ratio()</span>. The ratio is in/out.
</p>
<p>
Sometimes it&#39;s useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with
<span style="font-family:monospace;">ma_resampler_get_required_input_frame_count()</span>. Likewise, it&#39;s sometimes useful to know exactly how many frames would be output given a certain number of
input frames. You can do this with <span style="font-family:monospace;">ma_resampler_get_expected_output_frame_count()</span>.
</p>
<p>
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
with <span style="font-family:monospace;">ma_resampler_get_input_latency()</span> and <span style="font-family:monospace;">ma_resampler_get_output_latency()</span>.
</p>
<p>
</p>
<p>
</p>
<h2 id="ResamplingAlgorithms" class="man">6.3.1. Resampling Algorithms</h2>
<p>
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,
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
for memory management.
</p>
<p>
</p>
<p>
</p>
<h2 id="LinearResampling" class="man">6.3.1.1. Linear Resampling</h2>
<p>
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
may make it a suitable option depending on your requirements.
</p>
<p>
The linear resampler performs low-pass filtering before or after downsampling or upsampling, depending on the sample rates you&#39;re converting between. When
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
a fourth order low-pass filter will be applied. This can be configured via the <span style="font-family:monospace;">lpfOrder</span> configuration variable. Setting this to 0 will disable filtering.
</p>
<p>
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
can be controlled with the <span style="font-family:monospace;">lpfNyquistFactor</span> config variable. This defaults to 1, and should be in the range of 0..1, although a value of 0 does not make
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.
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
and is a purely perceptual configuration.
</p>
<p>
The API for the linear resampler is the same as the main resampler API, only it&#39;s called <span style="font-family:monospace;">ma_linear_resampler</span>.
</p>
<p>
</p>
<p>
</p>
<h2 id="SpeexResampling" class="man">6.3.1.2. Speex Resampling</h2>
<p>
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
domain, it is strictly opt-in and all of it&#39;s code is stored in separate files. If you opt-in to the Speex resampler you must consider the license text in it&#39;s
source files. To opt-in, you must first #include the following file before the implementation of miniaudio.h:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;extras/speex_resampler/ma_speex_resampler.h&quot;</span>
</pre></div><p>
Both the header and implementation is contained within the same file. The implementation can be included in your program like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#666666">#define</span> MINIAUDIO_SPEEX_RESAMPLER_IMPLEMENTATION
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;extras/speex_resampler/ma_speex_resampler.h&quot;</span>
</pre></div><p>
Note that even if you opt-in to the Speex backend, miniaudio won&#39;t use it unless you explicitly ask for it in the respective config of the object you are
initializing. If you try to use the Speex resampler without opting in, initialization of the <span style="font-family:monospace;">ma_resampler</span> object will fail with <span style="font-family:monospace;">MA_NO_BACKEND</span>.
</p>
<p>
The only configuration option to consider with the Speex resampler is the <span style="font-family:monospace;">speex.quality</span> config variable. This is a value between 0 and 10, with 0 being
the fastest with the poorest quality and 10 being the slowest with the highest quality. The default value is 3.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h2 id="GeneralDataConversion" class="man">6.4. General Data Conversion</h2>
<p>
The <span style="font-family:monospace;">ma_data_converter</span> API can be used to wrap sample format conversion, channel conversion and resampling into one operation. This is what miniaudio uses
internally to convert between the format requested when the device was initialized and the format of the backend&#39;s native device. The API for general data
conversion is very similar to the resampling API. Create a <span style="font-family:monospace;">ma_data_converter</span> object like this:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_data_converter_config</span> config = ma_data_converter_config_init(
inputFormat,
outputFormat,
inputChannels,
outputChannels,
inputSampleRate,
outputSampleRate
);
<span style="color:#0099cc">ma_data_converter</span> converter;
<span style="color:#0099cc">ma_result</span> result = ma_data_converter_init(&amp;config, &amp;converter);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// An error occurred...</span>
}
</pre></div><p>
In the example above we use <span style="font-family:monospace;">ma_data_converter_config_init()</span> to initialize the config, however there&#39;s many more properties that can be configured, such as
channel maps and resampling quality. Something like the following may be more suitable depending on your requirements:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_data_converter_config</span> config = ma_data_converter_config_init_default();
config.formatIn = inputFormat;
config.formatOut = outputFormat;
config.channelsIn = inputChannels;
config.channelsOut = outputChannels;
config.sampleRateIn = inputSampleRate;
config.sampleRateOut = outputSampleRate;
ma_get_standard_channel_map(ma_standard_channel_map_flac, config.channelCountIn, config.channelMapIn);
config.resampling.linear.lpfOrder = MA_MAX_FILTER_ORDER;
</pre></div><p>
Do the following to uninitialize the data converter:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
ma_data_converter_uninit(&amp;converter);
</pre></div><p>
The following example shows how data can be processed
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_uint64</span> frameCountIn = 1000;
<span style="color:#0099cc">ma_uint64</span> frameCountOut = 2000;
<span style="color:#0099cc">ma_result</span> result = ma_data_converter_process_pcm_frames(&amp;converter, pFramesIn, &amp;frameCountIn, pFramesOut, &amp;frameCountOut);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// An error occurred...</span>
}
<span style="color:#009900">// At this point, frameCountIn contains the number of input frames that were consumed and frameCountOut contains the number</span>
<span style="color:#009900">// of output frames written.</span>
</pre></div><p>
The data converter supports multiple channels and is always interleaved (both input and output). The channel count cannot be changed after initialization.
</p>
<p>
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
configuration property that can be changed after initialization, but only if the <span style="font-family:monospace;">resampling.allowDynamicSampleRate</span> member of <span style="font-family:monospace;">ma_data_converter_config</span> is
set to MA_TRUE. To change the sample rate, use <span style="font-family:monospace;">ma_data_converter_set_rate()</span> or <span style="font-family:monospace;">ma_data_converter_set_rate_ratio()</span>. The ratio must be in/out. The resampling
algorithm cannot be changed after initialization.
</p>
<p>
Processing always happens on a per PCM frame basis and always assumes interleaved input and output. De-interleaved processing is not supported. To process
frames, use <span style="font-family:monospace;">ma_data_converter_process_pcm_frames()</span>. On input, this function takes the number of output frames you can fit in the output buffer and the number
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
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
buffer of zeros. The output buffer can also be NULL, in which case the processing will be treated as seek.
</p>
<p>
Sometimes it&#39;s useful to know exactly how many input frames will be required to output a specific number of frames. You can calculate this with
<span style="font-family:monospace;">ma_data_converter_get_required_input_frame_count()</span>. Likewise, it&#39;s sometimes useful to know exactly how many frames would be output given a certain number of
input frames. You can do this with <span style="font-family:monospace;">ma_data_converter_get_expected_output_frame_count()</span>.
</p>
<p>
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
input rate and the output rate with <span style="font-family:monospace;">ma_data_converter_get_input_latency()</span> and <span style="font-family:monospace;">ma_data_converter_get_output_latency()</span>.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h1 id="Filtering" class="man">7. Filtering</h1>
<p>
</p>
<h2 id="BiquadFiltering" class="man">7.1. Biquad Filtering</h2>
<p>
Biquad filtering is achieved with the <span style="font-family:monospace;">ma_biquad</span> API. Example:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_biquad_config</span> config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2);
<span style="color:#0099cc">ma_result</span> result = ma_biquad_init(&amp;config, &amp;biquad);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
...
ma_biquad_process_pcm_frames(&amp;biquad, pFramesOut, pFramesIn, frameCount);
</pre></div><p>
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
a2. The a0 coefficient is required and coefficients must not be pre-normalized.
</p>
<p>
Supported formats are <span style="font-family:monospace;">ma_format_s16</span> and <span style="font-family:monospace;">ma_format_f32</span>. If you need to use a different format you need to convert it yourself beforehand. When using
<span style="font-family:monospace;">ma_format_s16</span> the biquad filter will use fixed point arithmetic. When using <span style="font-family:monospace;">ma_format_f32</span>, floating point arithmetic will be used.
</p>
<p>
Input and output frames are always interleaved.
</p>
<p>
Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
ma_biquad_process_pcm_frames(&amp;biquad, pMyData, pMyData, frameCount);
</pre></div><p>
If you need to change the values of the coefficients, but maintain the values in the registers you can do so with <span style="font-family:monospace;">ma_biquad_reinit()</span>. This is useful if you
need to change the properties of the filter while keeping the values of registers valid to avoid glitching. Do not use <span style="font-family:monospace;">ma_biquad_init()</span> for this as it will
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
result in an error.
</p>
<p>
</p>
<p>
</p>
<h2 id="Low-PassFiltering" class="man">7.2. Low-Pass Filtering</h2>
<p>
Low-pass filtering is achieved with the following APIs:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
API</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_lpf1</p>
</td>
<td class="doc" valign="top"><p>
First order low-pass filter</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_lpf2</p>
</td>
<td class="doc" valign="top"><p>
Second order low-pass filter</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_lpf</p>
</td>
<td class="doc" valign="top"><p>
High order low-pass filter (Butterworth)</p>
</td>
</tr>
</table></div><p>
Low-pass filter example:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_lpf_config</span> config = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order);
<span style="color:#0099cc">ma_result</span> result = ma_lpf_init(&amp;config, &amp;lpf);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
...
ma_lpf_process_pcm_frames(&amp;lpf, pFramesOut, pFramesIn, frameCount);
</pre></div><p>
Supported formats are <span style="font-family:monospace;">ma_format_s16</span> and<span style="font-family:monospace;"> ma_format_f32</span>. If you need to use a different format you need to convert it yourself beforehand. Input and output
frames are always interleaved.
</p>
<p>
Filtering can be applied in-place by passing in the same pointer for both the input and output buffers, like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
ma_lpf_process_pcm_frames(&amp;lpf, pMyData, pMyData, frameCount);
</pre></div><p>
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.
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0033ff">for</span> (iFilter = 0; iFilter &lt; filterCount; iFilter += 1) {
ma_lpf2_process_pcm_frames(&amp;lpf2[iFilter], pMyData, pMyData, frameCount);
}
</pre></div><p>
If you need to change the configuration of the filter, but need to maintain the state of internal registers you can do so with <span style="font-family:monospace;">ma_lpf_reinit()</span>. This may be
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
count after initialization is invalid and will result in an error.
</p>
<p>
The <span style="font-family:monospace;">ma_lpf</span> object supports a configurable order, but if you only need a first order filter you may want to consider using <span style="font-family:monospace;">ma_lpf1</span>. Likewise, if you only
need a second order filter you can use <span style="font-family:monospace;">ma_lpf2</span>. The advantage of this is that they&#39;re lighter weight and a bit more efficient.
</p>
<p>
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
will be applied, followed by a series of second order filters in a chain.
</p>
<p>
</p>
<p>
</p>
<h2 id="High-PassFiltering" class="man">7.3. High-Pass Filtering</h2>
<p>
High-pass filtering is achieved with the following APIs:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
API</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_hpf1</p>
</td>
<td class="doc" valign="top"><p>
First order high-pass filter</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_hpf2</p>
</td>
<td class="doc" valign="top"><p>
Second order high-pass filter</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_hpf</p>
</td>
<td class="doc" valign="top"><p>
High order high-pass filter (Butterworth)</p>
</td>
</tr>
</table></div><p>
High-pass filters work exactly the same as low-pass filters, only the APIs are called <span style="font-family:monospace;">ma_hpf1</span>, <span style="font-family:monospace;">ma_hpf2</span> and <span style="font-family:monospace;">ma_hpf</span>. See example code for low-pass filters
for example usage.
</p>
<p>
</p>
<p>
</p>
<h2 id="Band-PassFiltering" class="man">7.4. Band-Pass Filtering</h2>
<p>
Band-pass filtering is achieved with the following APIs:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
API</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_bpf2</p>
</td>
<td class="doc" valign="top"><p>
Second order band-pass filter</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_bpf</p>
</td>
<td class="doc" valign="top"><p>
High order band-pass filter</p>
</td>
</tr>
</table></div><p>
Band-pass filters work exactly the same as low-pass filters, only the APIs are called <span style="font-family:monospace;">ma_bpf2</span> and <span style="font-family:monospace;">ma_hpf</span>. See example code for low-pass filters for example
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
filters.
</p>
<p>
</p>
<p>
</p>
<h2 id="NotchFiltering" class="man">7.5. Notch Filtering</h2>
<p>
Notch filtering is achieved with the following APIs:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
API</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_notch2</p>
</td>
<td class="doc" valign="top"><p>
Second order notching filter</p>
</td>
</tr>
</table></div><p>
</p>
<h2 id="PeakingEQFiltering" class="man">7.6. Peaking EQ Filtering</h2>
<p>
Peaking filtering is achieved with the following APIs:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
API</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_peak2</p>
</td>
<td class="doc" valign="top"><p>
Second order peaking filter</p>
</td>
</tr>
</table></div><p>
</p>
<h2 id="LowShelfFiltering" class="man">7.7. Low Shelf Filtering</h2>
<p>
Low shelf filtering is achieved with the following APIs:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
API</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_loshelf2</p>
</td>
<td class="doc" valign="top"><p>
Second order low shelf filter</p>
</td>
</tr>
</table></div><p>
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.
</p>
<p>
</p>
<p>
</p>
<h2 id="HighShelfFiltering" class="man">7.8. High Shelf Filtering</h2>
<p>
High shelf filtering is achieved with the following APIs:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
API</p>
</th>
<th class="doc" valign="top"><p>
Description</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_hishelf2</p>
</td>
<td class="doc" valign="top"><p>
Second order high shelf filter</p>
</td>
</tr>
</table></div><p>
The high shelf filter has the same API as the low shelf filter, only you would use <span style="font-family:monospace;">ma_hishelf</span> instead of <span style="font-family:monospace;">ma_loshelf</span>. Where a low shelf filter is used to
adjust the volume of low frequencies, the high shelf filter does the same thing for high frequencies.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h1 id="WaveformandNoiseGeneration" class="man">8. Waveform and Noise Generation</h1>
<p>
</p>
<h2 id="Waveforms" class="man">8.1. Waveforms</h2>
<p>
miniaudio supports generation of sine, square, triangle and sawtooth waveforms. This is achieved with the <span style="font-family:monospace;">ma_waveform</span> API. Example:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_waveform_config</span> config = ma_waveform_config_init(
FORMAT,
CHANNELS,
SAMPLE_RATE,
ma_waveform_type_sine,
amplitude,
frequency);
<span style="color:#0099cc">ma_waveform</span> waveform;
<span style="color:#0099cc">ma_result</span> result = ma_waveform_init(&amp;config, &amp;waveform);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
...
ma_waveform_read_pcm_frames(&amp;waveform, pOutput, frameCount);
</pre></div><p>
The amplitude, frequency and sample rate can be changed dynamically with <span style="font-family:monospace;">ma_waveform_set_amplitude()</span>, <span style="font-family:monospace;">ma_waveform_set_frequency()</span> and
<span style="font-family:monospace;">ma_waveform_set_sample_rate()</span> respectively.
</p>
<p>
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
ramp, for example.
</p>
<p>
Below are the supported waveform types:
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Enum Name</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_waveform_type_sine</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_waveform_type_square</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_waveform_type_triangle</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_waveform_type_sawtooth</p>
</td>
</tr>
</table></div><p>
</p>
<p>
</p>
<h2 id="Noise" class="man">8.2. Noise</h2>
<p>
miniaudio supports generation of white, pink and Brownian noise via the <span style="font-family:monospace;">ma_noise</span> API. Example:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_noise_config</span> config = ma_noise_config_init(
FORMAT,
CHANNELS,
ma_noise_type_white,
SEED,
amplitude);
<span style="color:#0099cc">ma_noise</span> noise;
<span style="color:#0099cc">ma_result</span> result = ma_noise_init(&amp;config, &amp;noise);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
...
ma_noise_read_pcm_frames(&amp;noise, pOutput, frameCount);
</pre></div><p>
The noise API uses simple LCG random number generation. It supports a custom seed which is useful for things like automated testing requiring reproducibility.
Setting the seed to zero will default to MA_DEFAULT_LCG_SEED.
</p>
<p>
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
side. To instead have each channel use the same random value, set the <span style="font-family:monospace;">duplicateChannels</span> member of the noise config to true, like so:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
config.duplicateChannels = MA_TRUE;
</pre></div><p>
Below are the supported noise types.
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Enum Name</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_noise_type_white</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_noise_type_pink</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ma_noise_type_brownian</p>
</td>
</tr>
</table></div><p>
</p>
<p>
</p>
<h1 id="AudioBuffers" class="man">9. Audio Buffers</h1>
<p>
miniaudio supports reading from a buffer of raw audio data via the <span style="font-family:monospace;">ma_audio_buffer</span> API. This can read from memory that&#39;s managed by the application, but
can also handle the memory management for you internally. Memory management is flexible and should support most use cases.
</p>
<p>
Audio buffers are initialised using the standard configuration system used everywhere in miniaudio:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_audio_buffer_config</span> config = ma_audio_buffer_config_init(
format,
channels,
sizeInFrames,
pExistingData,
&amp;allocationCallbacks);
<span style="color:#0099cc">ma_audio_buffer</span> buffer;
result = ma_audio_buffer_init(&amp;config, &amp;buffer);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error.</span>
}
...
ma_audio_buffer_uninit(&amp;buffer);
</pre></div><p>
In the example above, the memory pointed to by <span style="font-family:monospace;">pExistingData</span> will _not_ be copied and is how an application can do self-managed memory allocation. If you
would rather make a copy of the data, use <span style="font-family:monospace;">ma_audio_buffer_init_copy()</span>. To uninitialize the buffer, use <span style="font-family:monospace;">ma_audio_buffer_uninit()</span>.
</p>
<p>
Sometimes it can be convenient to allocate the memory for the <span style="font-family:monospace;">ma_audio_buffer</span> structure _and_ the raw audio data in a contiguous block of memory. That is,
the raw audio data will be located immediately after the <span style="font-family:monospace;">ma_audio_buffer</span> structure. To do this, use <span style="font-family:monospace;">ma_audio_buffer_alloc_and_init()</span>:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_audio_buffer_config</span> config = ma_audio_buffer_config_init(
format,
channels,
sizeInFrames,
pExistingData,
&amp;allocationCallbacks);
<span style="color:#0099cc">ma_audio_buffer</span>* pBuffer
result = ma_audio_buffer_alloc_and_init(&amp;config, &amp;pBuffer);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error</span>
}
...
ma_audio_buffer_uninit_and_free(&amp;buffer);
</pre></div><p>
If you initialize the buffer with <span style="font-family:monospace;">ma_audio_buffer_alloc_and_init()</span> you should uninitialize it with <span style="font-family:monospace;">ma_audio_buffer_uninit_and_free()</span>. In the example above,
the memory pointed to by <span style="font-family:monospace;">pExistingData</span> will be copied into the buffer, which is contrary to the behavior of <span style="font-family:monospace;">ma_audio_buffer_init()</span>.
</p>
<p>
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 (<span style="font-family:monospace;">loop</span>) can be
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
means the end has been reached. This should never happen if the <span style="font-family:monospace;">loop</span> parameter is set to true. If you want to manually loop back to the start, you can do so
with with <span style="font-family:monospace;">ma_audio_buffer_seek_to_pcm_frame(pAudioBuffer, 0)</span>. Below is an example for reading data from an audio buffer.
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_uint64</span> framesRead = ma_audio_buffer_read_pcm_frames(pAudioBuffer, pFramesOut, desiredFrameCount, isLooping);
<span style="color:#0033ff">if</span> (framesRead &lt; desiredFrameCount) {
<span style="color:#009900">// If not looping, this means the end has been reached. This should never happen in looping mode with valid input.</span>
}
</pre></div><p>
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
pointer to a segment of data:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0033ff">void</span>* pMappedFrames;
<span style="color:#0099cc">ma_uint64</span> frameCount = frameCountToTryMapping;
<span style="color:#0099cc">ma_result</span> result = ma_audio_buffer_map(pAudioBuffer, &amp;pMappedFrames, &amp;frameCount);
<span style="color:#0033ff">if</span> (result == MA_SUCCESS) {
<span style="color:#009900">// Map was successful. The value in frameCount will be how many frames were _actually_ mapped, which may be</span>
<span style="color:#009900">// less due to the end of the buffer being reached.</span>
ma_copy_pcm_frames(pFramesOut, pMappedFrames, frameCount, pAudioBuffer-&gt;format, pAudioBuffer-&gt;channels);
<span style="color:#009900">// You must unmap the buffer.</span>
ma_audio_buffer_unmap(pAudioBuffer, frameCount);
}
</pre></div><p>
When you use memory mapping, the read cursor is increment by the frame count passed in to <span style="font-family:monospace;">ma_audio_buffer_unmap()</span>. If you decide not to process every frame
you can pass in a value smaller than the value returned by <span style="font-family:monospace;">ma_audio_buffer_map()</span>. The disadvantage to using memory mapping is that it does not handle looping
for you. You can determine if the buffer is at the end for the purpose of looping with <span style="font-family:monospace;">ma_audio_buffer_at_end()</span> or by inspecting the return value of
<span style="font-family:monospace;">ma_audio_buffer_unmap()</span> and checking if it equals <span style="font-family:monospace;">MA_AT_END</span>. You should not treat <span style="font-family:monospace;">MA_AT_END</span> as an error when returned by <span style="font-family:monospace;">ma_audio_buffer_unmap()</span>.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h1 id="RingBuffers" class="man">10. Ring Buffers</h1>
<p>
miniaudio supports lock free (single producer, single consumer) ring buffers which are exposed via the <span style="font-family:monospace;">ma_rb</span> and <span style="font-family:monospace;">ma_pcm_rb</span> APIs. The <span style="font-family:monospace;">ma_rb</span> API operates
on bytes, whereas the <span style="font-family:monospace;">ma_pcm_rb</span> operates on PCM frames. They are otherwise identical as <span style="font-family:monospace;">ma_pcm_rb</span> is just a wrapper around <span style="font-family:monospace;">ma_rb</span>.
</p>
<p>
Unlike most other APIs in miniaudio, ring buffers support both interleaved and deinterleaved streams. The caller can also allocate their own backing memory for
the ring buffer to use internally for added flexibility. Otherwise the ring buffer will manage it&#39;s internal memory for you.
</p>
<p>
The examples below use the PCM frame variant of the ring buffer since that&#39;s most likely the one you will want to use. To initialize a ring buffer, do
something like the following:
</p>
<p>
</p>
<div style="font-family:monospace; border:solid 1px #003800; border-left:solid 0.5em #003800; margin:1em 0em; width:100%;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
<span style="color:#0099cc">ma_pcm_rb</span> rb;
<span style="color:#0099cc">ma_result</span> result = ma_pcm_rb_init(FORMAT, CHANNELS, BUFFER_SIZE_IN_FRAMES, NULL, NULL, &amp;rb);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#009900">// Error</span>
}
</pre></div><p>
The <span style="font-family:monospace;">ma_pcm_rb_init()</span> function takes the sample format and channel count as parameters because it&#39;s the PCM varient of the ring buffer API. For the regular
ring buffer that operates on bytes you would call <span style="font-family:monospace;">ma_rb_init()</span> which leaves these out and just takes the size of the buffer in bytes instead of frames. The
fourth parameter is an optional pre-allocated buffer and the fifth parameter is a pointer to a <span style="font-family:monospace;">ma_allocation_callbacks</span> structure for custom memory allocation
routines. Passing in <span style="font-family:monospace;">NULL</span> for this results in <span style="font-family:monospace;">MA_MALLOC()</span> and <span style="font-family:monospace;">MA_FREE()</span> being used.
</p>
<p>
Use <span style="font-family:monospace;">ma_pcm_rb_init_ex()</span> if you need a deinterleaved buffer. The data for each sub-buffer is offset from each other based on the stride. To manage your
sub-buffers you can use <span style="font-family:monospace;">ma_pcm_rb_get_subbuffer_stride()</span>, <span style="font-family:monospace;">ma_pcm_rb_get_subbuffer_offset()</span> and <span style="font-family:monospace;">ma_pcm_rb_get_subbuffer_ptr()</span>.
</p>
<p>
Use &#39;ma_pcm_rb_acquire_read()<span style="font-family:monospace;"> and </span>ma_pcm_rb_acquire_write()` to retrieve a pointer to a section of the ring buffer. You specify the number of frames you
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
a loop, it will be clamped to the end of the buffer. Therefore, the number of frames you&#39;re given may be less than the number you requested.
</p>
<p>
After calling <span style="font-family:monospace;">ma_pcm_rb_acquire_read()</span> or <span style="font-family:monospace;">ma_pcm_rb_acquire_write()</span>, you do your work on the buffer and then &quot;commit&quot; it with <span style="font-family:monospace;">ma_pcm_rb_commit_read()</span> or
<span style="font-family:monospace;">ma_pcm_rb_commit_write()</span>. 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
call to <span style="font-family:monospace;">ma_pcm_rb_acquire_read()</span> or <span style="font-family:monospace;">ma_pcm_rb_acquire_write()</span> and is only used for validation. The number of frames passed to <span style="font-family:monospace;">ma_pcm_rb_commit_read()</span> and
<span style="font-family:monospace;">ma_pcm_rb_commit_write()</span> is what&#39;s used to increment the pointers.
</p>
<p>
If you want to correct for drift between the write pointer and the read pointer you can use a combination of <span style="font-family:monospace;">ma_pcm_rb_pointer_distance()</span>,
<span style="font-family:monospace;">ma_pcm_rb_seek_read()</span> and <span style="font-family:monospace;">ma_pcm_rb_seek_write()</span>. Note that you can only move the pointers forward, and you should only move the read pointer forward via
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
there is too little space between the pointers, move the write pointer forward.
</p>
<p>
You can use a ring buffer at the byte level instead of the PCM frame level by using the <span style="font-family:monospace;">ma_rb</span> API. This is exactly the same, only you will use the <span style="font-family:monospace;">ma_rb</span>
functions instead of <span style="font-family:monospace;">ma_pcm_rb</span> and instead of frame counts you will pass around byte counts.
</p>
<p>
The maximum size of the buffer in bytes is <span style="font-family:monospace;">0x7FFFFFFF-(MA_SIMD_ALIGNMENT-1)</span> due to the most significant bit being used to encode a loop flag and the internally
managed buffers always being aligned to MA_SIMD_ALIGNMENT.
</p>
<p>
Note that the ring buffer is only thread safe when used by a single consumer thread and single producer thread.
</p>
<p>
</p>
<p>
</p>
<p>
</p>
<h1 id="Backends" class="man">11. Backends</h1>
<p>
The following backends are supported by miniaudio.
</p>
<p>
</p>
<div style="overflow:hidden;"><table class="doc"><tr>
<th class="doc" valign="top"><p>
Name</p>
</th>
<th class="doc" valign="top"><p>
Enum Name</p>
</th>
<th class="doc" valign="top"><p>
Supported Operating Systems</p>
</th>
</tr>
<tr>
<td class="doc" valign="top"><p>
WASAPI</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_wasapi</p>
</td>
<td class="doc" valign="top"><p>
Windows Vista+</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
DirectSound</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_dsound</p>
</td>
<td class="doc" valign="top"><p>
Windows XP+</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
WinMM</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_winmm</p>
</td>
<td class="doc" valign="top"><p>
Windows XP+ (may work on older versions, but untested)</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Core Audio</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_coreaudio</p>
</td>
<td class="doc" valign="top"><p>
macOS, iOS</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
ALSA</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_alsa</p>
</td>
<td class="doc" valign="top"><p>
Linux</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
PulseAudio</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_pulseaudio</p>
</td>
<td class="doc" valign="top"><p>
Cross Platform (disabled on Windows, BSD and Android)</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
JACK</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_jack</p>
</td>
<td class="doc" valign="top"><p>
Cross Platform (disabled on BSD and Android)</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
sndio</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_sndio</p>
</td>
<td class="doc" valign="top"><p>
OpenBSD</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
audio(4)</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_audio4</p>
</td>
<td class="doc" valign="top"><p>
NetBSD, OpenBSD</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
OSS</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_oss</p>
</td>
<td class="doc" valign="top"><p>
FreeBSD</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
AAudio</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_aaudio</p>
</td>
<td class="doc" valign="top"><p>
Android 8+</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
OpenSL ES</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_opensl</p>
</td>
<td class="doc" valign="top"><p>
Android (API level 16+)</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Web Audio</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_webaudio</p>
</td>
<td class="doc" valign="top"><p>
Web (via Emscripten)</p>
</td>
</tr>
<tr>
<td class="doc" valign="top"><p>
Null</p>
</td>
<td class="doc" valign="top"><p>
ma_backend_null</p>
</td>
<td class="doc" valign="top"><p>
Cross Platform (not used on Web)</p>
</td>
</tr>
</table></div><p>
Some backends have some nuance details you may want to be aware of.
</p>
<p>
</p>
<h2 id="WASAPI" class="man">11.1. WASAPI</h2>
<ul>
<li style="overflow:hidden;">
Low-latency shared mode will be disabled when using an application-defined sample rate which is different to the device&#39;s native sample rate. To work around
this, set <span style="font-family:monospace;">wasapi.noAutoConvertSRC</span> to true in the device config. This is due to IAudioClient3_InitializeSharedAudioStream() failing when the
<span style="font-family:monospace;">AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM</span> flag is specified. Setting wasapi.noAutoConvertSRC will result in miniaudio&#39;s internal resampler being used instead
which will in turn enable the use of low-latency shared mode.
</li>
</ul>
<h2 id="PulseAudio" class="man">11.2. PulseAudio</h2>
<ul>
<li style="overflow:hidden;">
If you experience bad glitching/noise on Arch Linux, consider this fix from the Arch wiki:
<a href="https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling">https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Glitches,_skips_or_crackling</a>. Alternatively, consider using a different backend such as ALSA.
</li>
</ul>
<h2 id="Android" class="man">11.3. Android</h2>
<ul>
<li style="overflow:hidden;">
To capture audio on Android, remember to add the RECORD_AUDIO permission to your manifest: <span style="font-family:monospace;">&lt;uses-permission android:name=&quot;android.permission.RECORD_AUDIO&quot; /&gt;</span>
</li>
<li style="overflow:hidden;">
With OpenSL|ES, only a single ma_context can be active at any given time. This is due to a limitation with OpenSL|ES.
</li>
<li style="overflow:hidden;">
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
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().
</li>
<li style="overflow:hidden;">
The backend API will perform resampling where possible. The reason for this as opposed to using miniaudio&#39;s built-in resampler is to take advantage of any
potential device-specific optimizations the driver may implement.
</li>
</ul>
<h2 id="UWP" class="man">11.4. UWP</h2>
<ul>
<li style="overflow:hidden;">
UWP only supports default playback and capture devices.
</li>
<li style="overflow:hidden;">
UWP requires the Microphone capability to be enabled in the application&#39;s manifest (Package.appxmanifest):
</li>
</ul>
<div style="font-family:monospace; margin:1em 0em;"><pre style="margin:0.5em 1em; padding:0; line-height:125%; overflow-x:auto;">
&lt;Package ...&gt;
...
&lt;Capabilities&gt;
&lt;DeviceCapability Name=<span style="color:#cc3300">&quot;microphone&quot;</span> /&gt;
&lt;/Capabilities&gt;
&lt;/Package&gt;
</pre></div><p>
</p>
<h2 id="WebAudio/Emscripten" class="man">11.5. Web Audio / Emscripten</h2>
<ul>
<li style="overflow:hidden;">
You cannot use <span style="font-family:monospace;">-std=c*</span> compiler flags, nor <span style="font-family:monospace;">-ansi</span>. This only applies to the Emscripten build.
</li>
<li style="overflow:hidden;">
The first time a context is initialized it will create a global object called &quot;miniaudio&quot; whose primary purpose is to act as a factory for device objects.
</li>
<li style="overflow:hidden;">
Currently the Web Audio backend uses ScriptProcessorNode&#39;s, but this may need to change later as they&#39;ve been deprecated.
</li>
<li style="overflow:hidden;">
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
has additional details: <a href="https://developers.google.com/web/updates/2017/09/autoplay-policy-changes">https://developers.google.com/web/updates/2017/09/autoplay-policy-changes</a>. Starting the device may fail if you try to start playback
without first handling some kind of user input.
</li>
</ul>
<p>
</p>
<p>
</p>
<h1 id="MiscellaneousNotes" class="man">12. Miscellaneous Notes</h1>
<ul>
<li style="overflow:hidden;">
Automatic stream routing is enabled on a per-backend basis. Support is explicitly enabled for WASAPI and Core Audio, however other backends such as
PulseAudio may naturally support it, though not all have been tested.
</li>
<li style="overflow:hidden;">
The contents of the output buffer passed into the data callback will always be pre-initialized to zero unless the <span style="font-family:monospace;">noPreZeroedOutputBuffer</span> config variable
in <span style="font-family:monospace;">ma_device_config</span> is set to true, in which case it&#39;ll be undefined which will require you to write something to the entire buffer.
</li>
<li style="overflow:hidden;">
By default miniaudio will automatically clip samples. This only applies when the playback sample format is configured as <span style="font-family:monospace;">ma_format_f32</span>. If you are doing
clipping yourself, you can disable this overhead by setting <span style="font-family:monospace;">noClip</span> to true in the device config.
</li>
<li style="overflow:hidden;">
The sndio backend is currently only enabled on OpenBSD builds.
</li>
<li style="overflow:hidden;">
The audio(4) backend is supported on OpenBSD, but you may need to disable sndiod before you can use it.
</li>
<li style="overflow:hidden;">
Note that GCC and Clang requires <span style="font-family:monospace;">-msse2</span>, <span style="font-family:monospace;">-mavx2</span>, etc. for SIMD optimizations.
</li>
<li style="overflow:hidden;">
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.
</li>
</ul>
</td>
</tr></table>
</div>
<table style="margin:0 auto; padding:1em 0px; text-align:center;">
<tr>
<td style="vertical-align:center;"><a style="padding:0;" href="https://discord.gg/9vpqbjU"><img src="../../img/Discord-Logo-White.svg" style="padding:0; height:32px; width:32px;"></a></td>
<td style="vertical-align:center;"><a style="padding:0;" href="https://twitter.com/mackron"><img src="../../img/twitter_white.png" style="padding:0; height:32px; width:32px;"></a></td>
<td style="vertical-align:center;"><a style="padding:0;" href="https://github.com/mackron/miniaudio"><img src="../../img/github_white.png" style="padding:0; height:24px; width:24px;"></a></td>
</tr>
</table>
<div style="color:#e0d7cf; font-size:9pt; padding:2em 0px; text-align:center;">
Copyright &copy; 2020 David Reid<br/>
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
</div>
</body>
</html>