Files
miniaudio/docs/examples/hilo_interop.html
T
2026-01-20 06:01:56 +10:00

422 lines
18 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="../manual/index.html">Documentation</a></td>
<td><a href="index.html">Examples</a></td>
</tr>
</table>
</td>
<td style="padding:0.1em; width:25%; text-align:right; vertical-align:center;">
<a href="https://www.reddit.com/r/miniaudio"><img src="../../img/reddit_white.svg" style="margin:0; padding:0; height:40px; width:40px;"></a>
</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 rel="me" href="https://fosstodon.org/@mackron"><img src="../../img/mastodon_white.svg" style="margin:0; padding:0; height:24px; 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="../manual/index.html" class="doc-navigation">Programming Manual</a><a href="index.html" class="doc-navigation ">Examples</a><a href="custom_backend.html" class="doc-navigation doc-navigation-l1 ">Custom Backend</a><a href="custom_decoder.html" class="doc-navigation doc-navigation-l1 ">Custom Decoder</a><a href="custom_decoder_engine.html" class="doc-navigation doc-navigation-l1 ">Custom Decoder Engine</a><a href="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="duplex_effect.html" class="doc-navigation doc-navigation-l1 ">Duplex Effect</a><a href="engine_advanced.html" class="doc-navigation doc-navigation-l1 ">Engine Advanced</a><a href="engine_effects.html" class="doc-navigation doc-navigation-l1 ">Engine Effects</a><a href="engine_hello_world.html" class="doc-navigation doc-navigation-l1 ">Engine Hello World</a><a href="engine_sdl.html" class="doc-navigation doc-navigation-l1 ">Engine Sdl</a><a href="engine_steamaudio.html" class="doc-navigation doc-navigation-l1 ">Engine Steamaudio</a><a href="hilo_interop.html" class="doc-navigation doc-navigation-l1 doc-navigation-active">Hilo Interop</a><a href="node_graph.html" class="doc-navigation doc-navigation-l1 ">Node Graph</a><a href="resource_manager.html" class="doc-navigation doc-navigation-l1 ">Resource Manager</a><a href="resource_manager_advanced.html" class="doc-navigation doc-navigation-l1 ">Resource Manager Advanced</a><a href="simple_capture.html" class="doc-navigation doc-navigation-l1 ">Simple Capture</a><a href="simple_duplex.html" class="doc-navigation doc-navigation-l1 ">Simple Duplex</a><a href="simple_enumeration.html" class="doc-navigation doc-navigation-l1 ">Simple Enumeration</a><a href="simple_loopback.html" class="doc-navigation doc-navigation-l1 ">Simple Loopback</a><a href="simple_looping.html" class="doc-navigation doc-navigation-l1 ">Simple Looping</a><a href="simple_mixing.html" class="doc-navigation doc-navigation-l1 ">Simple Mixing</a><a href="simple_playback.html" class="doc-navigation doc-navigation-l1 ">Simple Playback</a><a href="simple_playback_sine.html" class="doc-navigation doc-navigation-l1 ">Simple Playback Sine</a><a href="simple_playback_sine.html" class="doc-navigation doc-navigation-l1 ">Simple Playback Sine</a><a href="simple_spatialization.html" class="doc-navigation doc-navigation-l1 ">Simple Spatialization</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;">
<h1>Hilo Interop</h1><p>
Demonstrates interop between the high-level and the low-level API.
</p>
<p>
In this example we are using <span style="font-family:monospace;">ma_device</span> (the low-level API) to capture data from the microphone
which we then play back through the engine as a sound. We use a ring buffer to act as the data
source for the sound.
</p>
<p>
This is just a very basic example to show the general idea on how this might be achieved. In
this example a ring buffer is being used as the intermediary data source, but you can use anything
that works best for your situation. So long as the data is captured from the microphone, and then
delivered to the sound (via a data source), you should be good to go.
</p>
<p>
A more robust example would probably not want to use a ring buffer directly as the data source.
Instead you would probably want to do a custom data source that handles underruns and overruns of
the ring buffer and deals with desyncs between capture and playback. In the future this example
may be updated to make use of a more advanced data source that handles all of this.</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; overflow-y:hidden;">
<span style="color:#666666">#include</span> <span style="color:#cc3300">&quot;../miniaudio.c&quot;</span>
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_pcm_rb</span> rb;
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_device</span> device;
<span style="color:#0033ff">static</span> ma_engine engine;
<span style="color:#0033ff">static</span> ma_sound sound; <span style="color:#009900">/* The sound will be the playback of the capture side. */</span>
<span style="color:#0033ff">void</span> capture_data_callback(<span style="color:#0099cc">ma_device</span>* pDevice, <span style="color:#0033ff">void</span>* pFramesOut, <span style="color:#0033ff">const</span> <span style="color:#0033ff">void</span>* pFramesIn, <span style="color:#0099cc">ma_uint32</span> frameCount)
{
<span style="color:#0099cc">ma_result</span> result;
<span style="color:#0099cc">ma_uint32</span> framesWritten;
(<span style="color:#0033ff">void</span>)pFramesOut;
<span style="color:#009900">/* We need to write to the ring buffer. Need to do this in a loop. */</span>
framesWritten = 0;
<span style="color:#0033ff">while</span> (framesWritten &lt; frameCount) {
<span style="color:#0033ff">void</span>* pMappedBuffer;
<span style="color:#0099cc">ma_uint32</span> framesToWrite = frameCount - framesWritten;
result = ma_pcm_rb_acquire_write(&amp;rb, &amp;framesToWrite, &amp;pMappedBuffer);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#0033ff">break</span>;
}
<span style="color:#0033ff">if</span> (framesToWrite == 0) {
<span style="color:#0033ff">break</span>;
}
<span style="color:#009900">/* Copy the data from the capture buffer to the ring buffer. */</span>
ma_copy_pcm_frames(pMappedBuffer, ma_offset_pcm_frames_const_ptr_f32((<span style="color:#0033ff">const</span> <span style="color:#0033ff">float</span>*)pFramesIn, framesWritten, pDevice-&gt;capture.channels), framesToWrite, pDevice-&gt;capture.format, pDevice-&gt;capture.channels);
result = ma_pcm_rb_commit_write(&amp;rb, framesToWrite);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
<span style="color:#0033ff">break</span>;
}
framesWritten += framesToWrite;
}
}
<span style="color:#0033ff">int</span> main(<span style="color:#0033ff">int</span> argc, <span style="color:#0033ff">char</span>** argv)
{
<span style="color:#0099cc">ma_result</span> result;
<span style="color:#0099cc">ma_device_config</span> deviceConfig;
<span style="color:#009900">/*
The first thing we&#39;ll do is set up the capture side. There are two parts to this. The first is
the device itself, and the other is the ring buffer. It doesn&#39;t matter what order we initialize
these in, so long as the ring buffer is created before the device is started so that the
callback can be guaranteed to have a valid destination. We&#39;ll initialize the device first, and
then use the format, channels and sample rate to initialize the ring buffer.
It&#39;s important that the sample format of the device is set to f32 because that&#39;s what the engine
uses internally.
*/</span>
<span style="color:#009900">/* Initialize the capture device. */</span>
deviceConfig = ma_device_config_init(ma_device_type_capture);
deviceConfig.capture.format = ma_format_f32;
deviceConfig.dataCallback = capture_data_callback;
result = ma_device_init(NULL, &amp;deviceConfig, &amp;device);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
printf(<span style="color:#cc3300">&quot;Failed to initialize capture device.&quot;</span>);
<span style="color:#0033ff">return</span> -1;
}
<span style="color:#009900">/* Initialize the ring buffer. */</span>
result = ma_pcm_rb_init(device.capture.format, device.capture.channels, device.capture.internalPeriodSizeInFrames * 5, NULL, NULL, &amp;rb);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
printf(<span style="color:#cc3300">&quot;Failed to initialize the ring buffer.&quot;</span>);
<span style="color:#0033ff">return</span> -1;
}
<span style="color:#009900">/*
Ring buffers don&#39;t require a sample rate for their normal operation, but we can associate it
with a sample rate. We&#39;ll want to do this so the engine can resample if necessary.
*/</span>
ma_pcm_rb_set_sample_rate(&amp;rb, device.sampleRate);
<span style="color:#009900">/*
At this point the capture side is set up and we can now set up the playback side. Here we are
using <span style="font-family:monospace;">ma_engine</span> and linking the captured data to a sound so it can be manipulated just like
any other sound in the world.
Note that we have not yet started the capture device. Since the captured data is tied to a
sound, we&#39;ll link the starting and stopping of the capture device to the starting and stopping
of the sound.
*/</span>
<span style="color:#009900">/* We&#39;ll get the engine up and running before we start the capture device. */</span>
result = ma_engine_init(NULL, &amp;engine);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
printf(<span style="color:#cc3300">&quot;Failed to initialize the engine.&quot;</span>);
<span style="color:#0033ff">return</span> -1;
}
<span style="color:#009900">/*
We can now create our sound. This is created from a data source, which in this example is a
ring buffer. The capture side will be writing data into the ring buffer, whereas the sound
will be reading from it.
*/</span>
result = ma_sound_init_from_data_source(&amp;engine, &amp;rb, 0, NULL, &amp;sound);
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
printf(<span style="color:#cc3300">&quot;Failed to initialize the sound.&quot;</span>);
<span style="color:#0033ff">return</span> -1;
}
<span style="color:#009900">/* Link the starting of the device and sound together. */</span>
ma_device_start(&amp;device);
ma_sound_start(&amp;sound);
printf(<span style="color:#cc3300">&quot;Press Enter to quit...\n&quot;</span>);
getchar();
ma_sound_uninit(&amp;sound);
ma_engine_uninit(&amp;engine);
ma_device_uninit(&amp;device);
ma_pcm_rb_uninit(&amp;rb);
(<span style="color:#0033ff">void</span>)argc;
(<span style="color:#0033ff">void</span>)argv;
<span style="color:#0033ff">return</span> 0;
}
</pre></div></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://www.reddit.com/r/miniaudio"><img src="../../img/reddit_white.svg" style="margin:0; padding:0; height:40px; width:40px;"></a></td>
<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 rel="me" style="vertical-align:center;"><a style="padding:0;" href="https://fosstodon.org/@mackron"><img src="../../img/mastodon_white.svg" style="padding:0; height:24px; 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; 2026 David Reid<br/>
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
</div>
</body>
</html>