mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Update website.
This commit is contained in:
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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 doc-navigation-active">Custom Backend</a><a href="custom_decoder.html" class="doc-navigation doc-navigation-l1 ">Custom Decoder</a><a href="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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;">
|
||||
<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 doc-navigation-active">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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Custom Backend</h1><p>
|
||||
This example show how a custom backend can be implemented.
|
||||
</p>
|
||||
@@ -551,7 +551,8 @@ ma_format ma_format_from_sdl(MA_SDL_AudioFormat format)
|
||||
|
||||
tempDeviceID = ((MA_PFN_SDL_OpenAudioDevice)pContextEx->sdl.SDL_OpenAudioDevice)(pDeviceName, (deviceType == ma_device_type_playback) ? 0 : 1, &desiredSpec, &obtainedSpec, MA_SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||
<span style="color:#0033ff">if</span> (tempDeviceID == 0) {
|
||||
<span style="color:#0033ff">return</span> ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, <span style="color:#cc3300">"Failed to open SDL device."</span>, MA_FAILED_TO_OPEN_BACKEND_DEVICE);
|
||||
ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, <span style="color:#cc3300">"Failed to open SDL device."</span>);
|
||||
<span style="color:#0033ff">return</span> MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
((MA_PFN_SDL_CloseAudioDevice)pContextEx->sdl.SDL_CloseAudioDevice)(tempDeviceID);
|
||||
@@ -658,7 +659,8 @@ ma_format ma_format_from_sdl(MA_SDL_AudioFormat format)
|
||||
|
||||
deviceID = ((MA_PFN_SDL_OpenAudioDevice)pContextEx->sdl.SDL_OpenAudioDevice)(pDeviceName, (pConfig->deviceType == ma_device_type_playback) ? 0 : 1, &desiredSpec, &obtainedSpec, MA_SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||
<span style="color:#0033ff">if</span> (deviceID == 0) {
|
||||
<span style="color:#0033ff">return</span> ma_post_error((<span style="color:#0099cc">ma_device</span>*)pDeviceEx, MA_LOG_LEVEL_ERROR, <span style="color:#cc3300">"Failed to open SDL2 device."</span>, MA_FAILED_TO_OPEN_BACKEND_DEVICE);
|
||||
ma_log_postf(ma_device_get_log((<span style="color:#0099cc">ma_device</span>*)pDeviceEx), MA_LOG_LEVEL_ERROR, <span style="color:#cc3300">"Failed to open SDL2 device."</span>);
|
||||
<span style="color:#0033ff">return</span> MA_FAILED_TO_OPEN_BACKEND_DEVICE;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">if</span> (pConfig->deviceType == ma_device_type_playback) {
|
||||
@@ -671,7 +673,7 @@ ma_format ma_format_from_sdl(MA_SDL_AudioFormat format)
|
||||
pDescriptor->format = ma_format_from_sdl(obtainedSpec.format);
|
||||
pDescriptor->channels = obtainedSpec.channels;
|
||||
pDescriptor->sampleRate = (<span style="color:#0099cc">ma_uint32</span>)obtainedSpec.freq;
|
||||
ma_get_standard_channel_map(ma_standard_channel_map_default, pDescriptor->channels, pDescriptor->channelMap);
|
||||
ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptor->channelMap, ma_countof(pDescriptor->channelMap), pDescriptor->channels);
|
||||
pDescriptor->periodSizeInFrames = obtainedSpec.samples;
|
||||
pDescriptor->periodCount = 1; <span style="color:#009900">/* SDL doesn't use the notion of period counts, so just set to 1. */</span>
|
||||
|
||||
@@ -903,7 +905,7 @@ Main program starts here.
|
||||
pSineWave = (<span style="color:#0099cc">ma_waveform</span>*)pDevice->pUserData;
|
||||
MA_ASSERT(pSineWave != NULL);
|
||||
|
||||
ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount);
|
||||
ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, NULL);
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">if</span> (pDevice-><span style="color:#0033ff">type</span> == ma_device_type_duplex) {
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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 doc-navigation-active">Custom Decoder</a><a href="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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;">
|
||||
<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 doc-navigation-active">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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Custom Decoder</h1><p>
|
||||
Demonstrates how to implement a custom decoder.
|
||||
</p>
|
||||
@@ -255,18 +255,12 @@ This example implements two custom decoders:
|
||||
</p>
|
||||
<ul style="overflow:hidden;">
|
||||
<li>
|
||||
</li>
|
||||
</ul>
|
||||
<ul style="overflow:hidden;">
|
||||
Vorbis via libvorbis</li>
|
||||
<li>
|
||||
Vorbis via libvorbis
|
||||
</li>
|
||||
<li>
|
||||
Opus via libopus
|
||||
|
||||
A </li>
|
||||
Opus via libopus</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
A custom decoder must implement a data source. In this example, the libvorbis data source is called
|
||||
<span style="font-family:monospace;">ma_libvorbis</span> and the Opus data source is called <span style="font-family:monospace;">ma_libopus</span>. These two objects are compatible
|
||||
with the <span style="font-family:monospace;">ma_data_source</span> APIs and can be taken straight from this example and used in real code.
|
||||
@@ -358,8 +352,7 @@ The <span style="font-family:monospace;">onInitFile</span>, <span style="font-fa
|
||||
ma_decoding_backend_init_file__libvorbis,
|
||||
NULL, <span style="color:#009900">/* onInitFileW() */</span>
|
||||
NULL, <span style="color:#009900">/* onInitMemory() */</span>
|
||||
ma_decoding_backend_uninit__libvorbis,
|
||||
ma_decoding_backend_get_channel_map__libvorbis
|
||||
ma_decoding_backend_uninit__libvorbis
|
||||
};
|
||||
|
||||
|
||||
@@ -435,8 +428,7 @@ The <span style="font-family:monospace;">onInitFile</span>, <span style="font-fa
|
||||
ma_decoding_backend_init_file__libopus,
|
||||
NULL, <span style="color:#009900">/* onInitFileW() */</span>
|
||||
NULL, <span style="color:#009900">/* onInitMemory() */</span>
|
||||
ma_decoding_backend_uninit__libopus,
|
||||
ma_decoding_backend_get_channel_map__libopus
|
||||
ma_decoding_backend_uninit__libopus
|
||||
};
|
||||
|
||||
|
||||
@@ -496,7 +488,7 @@ The <span style="font-family:monospace;">onInitFile</span>, <span style="font-fa
|
||||
|
||||
|
||||
<span style="color:#009900">/* Initialize the device. */</span>
|
||||
result = ma_data_source_get_data_format(&decoder, &format, &channels, &sampleRate);
|
||||
result = ma_data_source_get_data_format(&decoder, &format, &channels, &sampleRate, NULL, 0);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to retrieve decoder data format."</span>);
|
||||
ma_decoder_uninit(&decoder);
|
||||
|
||||
@@ -0,0 +1,496 @@
|
||||
<!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://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="../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 doc-navigation-active">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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Custom Decoder Engine</h1><p>
|
||||
Demonstrates how to implement a custom decoder and use it with the high level API.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This is the same as the custom_decoder example, only it's used with the high level engine API
|
||||
rather than the low level decoding API. You can use this to add support for Opus to your games, for
|
||||
example (via libopus).</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_VORBIS <span style="color:#009900">/* Disable the built-in Vorbis decoder to ensure the libvorbis decoder is picked. */</span>
|
||||
<span style="color:#666666">#define</span> MA_NO_OPUS <span style="color:#009900">/* Disable the (not yet implemented) built-in Opus decoder to ensure the libopus decoder is picked. */</span>
|
||||
<span style="color:#666666">#define</span> MINIAUDIO_IMPLEMENTATION
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300">"../miniaudio.h"</span>
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300">"../extras/miniaudio_libvorbis.h"</span>
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300">"../extras/miniaudio_libopus.h"</span>
|
||||
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300"><stdio.h></span>
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_result</span> ma_decoding_backend_init__libvorbis(<span style="color:#0033ff">void</span>* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, <span style="color:#0033ff">void</span>* pReadSeekTellUserData, <span style="color:#0033ff">const</span> ma_decoding_backend_config* pConfig, <span style="color:#0033ff">const</span> ma_allocation_callbacks* pAllocationCallbacks, <span style="color:#0099cc">ma_data_source</span>** ppBackend)
|
||||
{
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
ma_libvorbis* pVorbis;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
pVorbis = (ma_libvorbis*)ma_malloc(<span style="color:#0033ff">sizeof</span>(*pVorbis), pAllocationCallbacks);
|
||||
<span style="color:#0033ff">if</span> (pVorbis == NULL) {
|
||||
<span style="color:#0033ff">return</span> MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_libvorbis_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pVorbis);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_free(pVorbis, pAllocationCallbacks);
|
||||
<span style="color:#0033ff">return</span> result;
|
||||
}
|
||||
|
||||
*ppBackend = pVorbis;
|
||||
|
||||
<span style="color:#0033ff">return</span> MA_SUCCESS;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_result</span> ma_decoding_backend_init_file__libvorbis(<span style="color:#0033ff">void</span>* pUserData, <span style="color:#0033ff">const</span> <span style="color:#0033ff">char</span>* pFilePath, <span style="color:#0033ff">const</span> ma_decoding_backend_config* pConfig, <span style="color:#0033ff">const</span> ma_allocation_callbacks* pAllocationCallbacks, <span style="color:#0099cc">ma_data_source</span>** ppBackend)
|
||||
{
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
ma_libvorbis* pVorbis;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
pVorbis = (ma_libvorbis*)ma_malloc(<span style="color:#0033ff">sizeof</span>(*pVorbis), pAllocationCallbacks);
|
||||
<span style="color:#0033ff">if</span> (pVorbis == NULL) {
|
||||
<span style="color:#0033ff">return</span> MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_libvorbis_init_file(pFilePath, pConfig, pAllocationCallbacks, pVorbis);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_free(pVorbis, pAllocationCallbacks);
|
||||
<span style="color:#0033ff">return</span> result;
|
||||
}
|
||||
|
||||
*ppBackend = pVorbis;
|
||||
|
||||
<span style="color:#0033ff">return</span> MA_SUCCESS;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0033ff">void</span> ma_decoding_backend_uninit__libvorbis(<span style="color:#0033ff">void</span>* pUserData, <span style="color:#0099cc">ma_data_source</span>* pBackend, <span style="color:#0033ff">const</span> ma_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
ma_libvorbis* pVorbis = (ma_libvorbis*)pBackend;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
ma_libvorbis_uninit(pVorbis, pAllocationCallbacks);
|
||||
ma_free(pVorbis, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_result</span> ma_decoding_backend_get_channel_map__libvorbis(<span style="color:#0033ff">void</span>* pUserData, <span style="color:#0099cc">ma_data_source</span>* pBackend, <span style="color:#0099cc">ma_channel</span>* pChannelMap, size_t channelMapCap)
|
||||
{
|
||||
ma_libvorbis* pVorbis = (ma_libvorbis*)pBackend;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
<span style="color:#0033ff">return</span> ma_libvorbis_get_data_format(pVorbis, NULL, NULL, NULL, pChannelMap, channelMapCap);
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> ma_decoding_backend_vtable g_ma_decoding_backend_vtable_libvorbis =
|
||||
{
|
||||
ma_decoding_backend_init__libvorbis,
|
||||
ma_decoding_backend_init_file__libvorbis,
|
||||
NULL, <span style="color:#009900">/* onInitFileW() */</span>
|
||||
NULL, <span style="color:#009900">/* onInitMemory() */</span>
|
||||
ma_decoding_backend_uninit__libvorbis
|
||||
};
|
||||
|
||||
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_result</span> ma_decoding_backend_init__libopus(<span style="color:#0033ff">void</span>* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, <span style="color:#0033ff">void</span>* pReadSeekTellUserData, <span style="color:#0033ff">const</span> ma_decoding_backend_config* pConfig, <span style="color:#0033ff">const</span> ma_allocation_callbacks* pAllocationCallbacks, <span style="color:#0099cc">ma_data_source</span>** ppBackend)
|
||||
{
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
ma_libopus* pOpus;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
pOpus = (ma_libopus*)ma_malloc(<span style="color:#0033ff">sizeof</span>(*pOpus), pAllocationCallbacks);
|
||||
<span style="color:#0033ff">if</span> (pOpus == NULL) {
|
||||
<span style="color:#0033ff">return</span> MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_libopus_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pOpus);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_free(pOpus, pAllocationCallbacks);
|
||||
<span style="color:#0033ff">return</span> result;
|
||||
}
|
||||
|
||||
*ppBackend = pOpus;
|
||||
|
||||
<span style="color:#0033ff">return</span> MA_SUCCESS;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_result</span> ma_decoding_backend_init_file__libopus(<span style="color:#0033ff">void</span>* pUserData, <span style="color:#0033ff">const</span> <span style="color:#0033ff">char</span>* pFilePath, <span style="color:#0033ff">const</span> ma_decoding_backend_config* pConfig, <span style="color:#0033ff">const</span> ma_allocation_callbacks* pAllocationCallbacks, <span style="color:#0099cc">ma_data_source</span>** ppBackend)
|
||||
{
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
ma_libopus* pOpus;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
pOpus = (ma_libopus*)ma_malloc(<span style="color:#0033ff">sizeof</span>(*pOpus), pAllocationCallbacks);
|
||||
<span style="color:#0033ff">if</span> (pOpus == NULL) {
|
||||
<span style="color:#0033ff">return</span> MA_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
result = ma_libopus_init_file(pFilePath, pConfig, pAllocationCallbacks, pOpus);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_free(pOpus, pAllocationCallbacks);
|
||||
<span style="color:#0033ff">return</span> result;
|
||||
}
|
||||
|
||||
*ppBackend = pOpus;
|
||||
|
||||
<span style="color:#0033ff">return</span> MA_SUCCESS;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0033ff">void</span> ma_decoding_backend_uninit__libopus(<span style="color:#0033ff">void</span>* pUserData, <span style="color:#0099cc">ma_data_source</span>* pBackend, <span style="color:#0033ff">const</span> ma_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
ma_libopus* pOpus = (ma_libopus*)pBackend;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
ma_libopus_uninit(pOpus, pAllocationCallbacks);
|
||||
ma_free(pOpus, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_result</span> ma_decoding_backend_get_channel_map__libopus(<span style="color:#0033ff">void</span>* pUserData, <span style="color:#0099cc">ma_data_source</span>* pBackend, <span style="color:#0099cc">ma_channel</span>* pChannelMap, size_t channelMapCap)
|
||||
{
|
||||
ma_libopus* pOpus = (ma_libopus*)pBackend;
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pUserData;
|
||||
|
||||
<span style="color:#0033ff">return</span> ma_libopus_get_data_format(pOpus, NULL, NULL, NULL, pChannelMap, channelMapCap);
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> ma_decoding_backend_vtable g_ma_decoding_backend_vtable_libopus =
|
||||
{
|
||||
ma_decoding_backend_init__libopus,
|
||||
ma_decoding_backend_init_file__libopus,
|
||||
NULL, <span style="color:#009900">/* onInitFileW() */</span>
|
||||
NULL, <span style="color:#009900">/* onInitMemory() */</span>
|
||||
ma_decoding_backend_uninit__libopus
|
||||
};
|
||||
|
||||
|
||||
|
||||
<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;
|
||||
ma_resource_manager_config resourceManagerConfig;
|
||||
ma_resource_manager resourceManager;
|
||||
ma_engine_config engineConfig;
|
||||
ma_engine engine;
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Add your custom backend vtables here. The order in the array defines the order of priority. The
|
||||
vtables will be passed in to the resource manager config.
|
||||
*/</span>
|
||||
ma_decoding_backend_vtable* pCustomBackendVTables[] =
|
||||
{
|
||||
&g_ma_decoding_backend_vtable_libvorbis,
|
||||
&g_ma_decoding_backend_vtable_libopus
|
||||
};
|
||||
|
||||
|
||||
<span style="color:#0033ff">if</span> (argc < 2) {
|
||||
printf(<span style="color:#cc3300">"No input file.\n"</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Using custom decoding backends requires a resource manager. */</span>
|
||||
resourceManagerConfig = ma_resource_manager_config_init();
|
||||
resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables;
|
||||
resourceManagerConfig.customDecodingBackendCount = <span style="color:#0033ff">sizeof</span>(pCustomBackendVTables) / <span style="color:#0033ff">sizeof</span>(pCustomBackendVTables[0]);
|
||||
resourceManagerConfig.pCustomDecodingBackendUserData = NULL; <span style="color:#009900">/* <-- This will be passed in to the pUserData parameter of each function in the decoding backend vtables. */</span>
|
||||
|
||||
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize resource manager."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Once we have a resource manager we can create the engine. */</span>
|
||||
engineConfig = ma_engine_config_init();
|
||||
engineConfig.pResourceManager = &resourceManager;
|
||||
|
||||
result = ma_engine_init(&engineConfig, &engine);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize engine."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Now we can play our sound. */</span>
|
||||
result = ma_engine_play_sound(&engine, argv[1], NULL);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to play sound."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit..."</span>);
|
||||
getchar();
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,437 @@
|
||||
<!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://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="../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 doc-navigation-active">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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Data Source Chaining</h1><p>
|
||||
Demonstrates one way to chain together a number of data sources so they play back seamlessly
|
||||
without gaps.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This example uses the chaining system built into the <span style="font-family:monospace;">ma_data_source</span> API. It will take every sound
|
||||
passed onto the command line in order, and then loop back and start again. When looping a chain of
|
||||
data sources, you need only link the last data source back to the first one.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
To play a chain of data sources, you first need to set up your chain. To set the data source that
|
||||
should be played after another, you have two options:
|
||||
</p>
|
||||
<ul style="overflow:hidden;">
|
||||
<li>
|
||||
Set a pointer to a specific data source</li>
|
||||
<li>
|
||||
Set a callback that will fire when the next data source needs to be retrieved</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
The first option is good for simple scenarios. The second option is useful if you need to perform
|
||||
some action when the end of a sound is reached. This example will be using both.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
When reading data from a chain, you always read from the head data source. Internally miniaudio
|
||||
will track a pointer to the data source in the chain that is currently playing. If you don't
|
||||
consistently read from the head data source this state will become inconsistent and things won't
|
||||
work correctly. When using a chain, this pointer needs to be reset if you need to play the
|
||||
chain again from the start:
|
||||
</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_source_set_current(&headDataSource, &headDataSource);
|
||||
ma_data_source_seek_to_pcm_frame(&headDataSource, 0);
|
||||
</pre></div><p>
|
||||
|
||||
The code above is setting the "current" data source in the chain to the head data source, thereby
|
||||
starting the chain from the start again. It is also seeking the head data source back to the start
|
||||
so that playback starts from the start as expected. You do not need to seek non-head items back to
|
||||
the start as miniaudio will do that for you internally.</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_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING
|
||||
<span style="color:#666666">#define</span> MINIAUDIO_IMPLEMENTATION
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300">"../miniaudio.h"</span>
|
||||
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300"><stdio.h></span>
|
||||
|
||||
<span style="color:#009900">/*
|
||||
For simplicity, this example requires the device to use floating point samples.
|
||||
*/</span>
|
||||
<span style="color:#666666">#define</span> SAMPLE_FORMAT ma_format_f32
|
||||
<span style="color:#666666">#define</span> CHANNEL_COUNT 2
|
||||
<span style="color:#666666">#define</span> SAMPLE_RATE 48000
|
||||
|
||||
<span style="color:#0099cc">ma_uint32</span> g_decoderCount;
|
||||
<span style="color:#0099cc">ma_decoder</span>* g_pDecoders;
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_data_source</span>* next_callback_tail(<span style="color:#0099cc">ma_data_source</span>* pDataSource)
|
||||
{
|
||||
MA_ASSERT(g_decoderCount > 0); <span style="color:#009900">/* <-- We check for this in main() so should never happen. */</span>
|
||||
|
||||
<span style="color:#009900">/*
|
||||
This will be fired when the last item in the chain has reached the end. In this example we want
|
||||
to loop back to the start, so we need only return a pointer back to the head.
|
||||
*/</span>
|
||||
<span style="color:#0033ff">return</span> &g_pDecoders[0];
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> <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">/*
|
||||
We can just read from the first decoder and miniaudio will resolve the chain for us. Note that
|
||||
if you want to loop the chain, like we're doing in this example, you need to set the <span style="font-family:monospace;">loop</span>
|
||||
parameter to false, or else only the current data source will be looped.
|
||||
*/</span>
|
||||
ma_data_source_read_pcm_frames(&g_pDecoders[0], pOutput, frameCount, NULL);
|
||||
|
||||
<span style="color:#009900">/* Unused in this example. */</span>
|
||||
(<span style="color:#0033ff">void</span>)pDevice;
|
||||
(<span style="color:#0033ff">void</span>)pInput;
|
||||
}
|
||||
|
||||
<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 = MA_SUCCESS;
|
||||
<span style="color:#0099cc">ma_uint32</span> iDecoder;
|
||||
<span style="color:#0099cc">ma_decoder_config</span> decoderConfig;
|
||||
<span style="color:#0099cc">ma_device_config</span> deviceConfig;
|
||||
<span style="color:#0099cc">ma_device</span> device;
|
||||
|
||||
<span style="color:#0033ff">if</span> (argc < 2) {
|
||||
printf(<span style="color:#cc3300">"No input files.\n"</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
g_decoderCount = argc-1;
|
||||
g_pDecoders = (<span style="color:#0099cc">ma_decoder</span>*)malloc(<span style="color:#0033ff">sizeof</span>(*g_pDecoders) * g_decoderCount);
|
||||
|
||||
<span style="color:#009900">/* In this example, all decoders need to have the same output format. */</span>
|
||||
decoderConfig = ma_decoder_config_init(SAMPLE_FORMAT, CHANNEL_COUNT, SAMPLE_RATE);
|
||||
<span style="color:#0033ff">for</span> (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
|
||||
result = ma_decoder_init_file(argv[1+iDecoder], &decoderConfig, &g_pDecoders[iDecoder]);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0099cc">ma_uint32</span> iDecoder2;
|
||||
<span style="color:#0033ff">for</span> (iDecoder2 = 0; iDecoder2 < iDecoder; ++iDecoder2) {
|
||||
ma_decoder_uninit(&g_pDecoders[iDecoder2]);
|
||||
}
|
||||
free(g_pDecoders);
|
||||
|
||||
printf(<span style="color:#cc3300">"Failed to load %s.\n"</span>, argv[1+iDecoder]);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
We're going to set up our decoders to run one after the other, but then have the last one loop back
|
||||
to the first one. For demonstration purposes we're going to use the callback method for the last
|
||||
data source.
|
||||
*/</span>
|
||||
<span style="color:#0033ff">for</span> (iDecoder = 0; iDecoder < g_decoderCount-1; iDecoder += 1) {
|
||||
ma_data_source_set_next(&g_pDecoders[iDecoder], &g_pDecoders[iDecoder+1]);
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
For the last data source we'll loop back to the start, but for demonstration purposes we'll use a
|
||||
callback to determine the next data source in the chain.
|
||||
*/</span>
|
||||
ma_data_source_set_next_callback(&g_pDecoders[g_decoderCount-1], next_callback_tail);
|
||||
|
||||
|
||||
<span style="color:#009900">/*
|
||||
The data source chain has been established so now we can get the device up and running so we
|
||||
can listen to it.
|
||||
*/</span>
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.format = SAMPLE_FORMAT;
|
||||
deviceConfig.playback.channels = CHANNEL_COUNT;
|
||||
deviceConfig.sampleRate = SAMPLE_RATE;
|
||||
deviceConfig.dataCallback = data_callback;
|
||||
deviceConfig.pUserData = NULL;
|
||||
|
||||
<span style="color:#0033ff">if</span> (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to open playback device.\n"</span>);
|
||||
result = -1;
|
||||
<span style="color:#0033ff">goto</span> done_decoders;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">if</span> (ma_device_start(&device) != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to start playback device.\n"</span>);
|
||||
result = -1;
|
||||
<span style="color:#0033ff">goto</span> done;
|
||||
}
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit..."</span>);
|
||||
getchar();
|
||||
|
||||
done:
|
||||
ma_device_uninit(&device);
|
||||
|
||||
done_decoders:
|
||||
<span style="color:#0033ff">for</span> (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {
|
||||
ma_decoder_uninit(&g_pDecoders[iDecoder]);
|
||||
}
|
||||
free(g_pDecoders);
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,415 @@
|
||||
<!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://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="../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 doc-navigation-active">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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Duplex Effect</h1><p>
|
||||
Demonstrates how to apply an effect to a duplex stream using the node graph system.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This example applies a vocoder effect to the input stream before outputting it. A custom node
|
||||
called <span style="font-family:monospace;">ma_vocoder_node</span> is used to achieve the effect which can be found in the extras folder in
|
||||
the miniaudio repository. The vocoder node uses <a href="https://github.com/blastbay/voclib">https://github.com/blastbay/voclib</a> to achieve the
|
||||
effect.</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">"../miniaudio.h"</span>
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300">"../extras/nodes/ma_vocoder_node/ma_vocoder_node.c"</span>
|
||||
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300"><stdio.h></span>
|
||||
|
||||
<span style="color:#666666">#define</span> DEVICE_FORMAT ma_format_f32; <span style="color:#009900">/* Must always be f32 for this example because the node graph system only works with this. */</span>
|
||||
<span style="color:#666666">#define</span> DEVICE_CHANNELS 1 <span style="color:#009900">/* For this example, always set to 1. */</span>
|
||||
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_waveform</span> g_sourceData; <span style="color:#009900">/* The underlying data source of the excite node. */</span>
|
||||
<span style="color:#0033ff">static</span> ma_audio_buffer_ref g_exciteData; <span style="color:#009900">/* The underlying data source of the source node. */</span>
|
||||
<span style="color:#0033ff">static</span> ma_data_source_node g_sourceNode; <span style="color:#009900">/* A data source node containing the source data we'll be sending through to the vocoder. This will be routed into the first bus of the vocoder node. */</span>
|
||||
<span style="color:#0033ff">static</span> ma_data_source_node g_exciteNode; <span style="color:#009900">/* A data source node containing the excite data we'll be sending through to the vocoder. This will be routed into the second bus of the vocoder node. */</span>
|
||||
<span style="color:#0033ff">static</span> ma_vocoder_node g_vocoderNode; <span style="color:#009900">/* The vocoder node. */</span>
|
||||
<span style="color:#0033ff">static</span> ma_node_graph g_nodeGraph;
|
||||
|
||||
<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)
|
||||
{
|
||||
MA_ASSERT(pDevice->capture.format == pDevice->playback.format);
|
||||
MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels);
|
||||
|
||||
<span style="color:#009900">/*
|
||||
The node graph system is a pulling style of API. At the lowest level of the chain will be a
|
||||
node acting as a data source for the purpose of delivering the initial audio data. In our case,
|
||||
the data source is our <span style="font-family:monospace;">pInput</span> buffer. We need to update the underlying data source so that it
|
||||
read data from <span style="font-family:monospace;">pInput</span>.
|
||||
*/</span>
|
||||
ma_audio_buffer_ref_set_data(&g_exciteData, pInput, frameCount);
|
||||
|
||||
<span style="color:#009900">/* With the source buffer configured we can now read directly from the node graph. */</span>
|
||||
ma_node_graph_read_pcm_frames(&g_nodeGraph, pOutput, frameCount, NULL);
|
||||
}
|
||||
|
||||
<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:#0099cc">ma_device</span> device;
|
||||
ma_node_graph_config nodeGraphConfig;
|
||||
ma_vocoder_node_config vocoderNodeConfig;
|
||||
ma_data_source_node_config sourceNodeConfig;
|
||||
ma_data_source_node_config exciteNodeConfig;
|
||||
<span style="color:#0099cc">ma_waveform_config</span> waveformConfig;
|
||||
|
||||
deviceConfig = ma_device_config_init(ma_device_type_duplex);
|
||||
deviceConfig.capture.pDeviceID = NULL;
|
||||
deviceConfig.capture.format = DEVICE_FORMAT;
|
||||
deviceConfig.capture.channels = DEVICE_CHANNELS;
|
||||
deviceConfig.capture.shareMode = ma_share_mode_shared;
|
||||
deviceConfig.playback.pDeviceID = NULL;
|
||||
deviceConfig.playback.format = DEVICE_FORMAT;
|
||||
deviceConfig.playback.channels = DEVICE_CHANNELS;
|
||||
deviceConfig.dataCallback = data_callback;
|
||||
result = ma_device_init(NULL, &deviceConfig, &device);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0033ff">return</span> result;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Now we can setup our node graph. */</span>
|
||||
nodeGraphConfig = ma_node_graph_config_init(device.capture.channels);
|
||||
|
||||
result = ma_node_graph_init(&nodeGraphConfig, NULL, &g_nodeGraph);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize node graph."</span>);
|
||||
<span style="color:#0033ff">goto</span> done0;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Vocoder. Attached straight to the endpoint. */</span>
|
||||
vocoderNodeConfig = ma_vocoder_node_config_init(device.capture.channels, device.sampleRate);
|
||||
|
||||
result = ma_vocoder_node_init(&g_nodeGraph, &vocoderNodeConfig, NULL, &g_vocoderNode);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize vocoder node."</span>);
|
||||
<span style="color:#0033ff">goto</span> done1;
|
||||
}
|
||||
|
||||
ma_node_attach_output_bus(&g_vocoderNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
||||
|
||||
<span style="color:#009900">/* Amplify the volume of the vocoder output because in my testing it is a bit quiet. */</span>
|
||||
ma_node_set_output_bus_volume(&g_vocoderNode, 0, 4);
|
||||
|
||||
|
||||
<span style="color:#009900">/* Source/carrier. Attached to input bus 0 of the vocoder node. */</span>
|
||||
waveformConfig = ma_waveform_config_init(device.capture.format, device.capture.channels, device.sampleRate, ma_waveform_type_sawtooth, 1.0, 50);
|
||||
|
||||
result = ma_waveform_init(&waveformConfig, &g_sourceData);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize waveform for excite node."</span>);
|
||||
<span style="color:#0033ff">goto</span> done3;
|
||||
}
|
||||
|
||||
sourceNodeConfig = ma_data_source_node_config_init(&g_sourceData);
|
||||
|
||||
result = ma_data_source_node_init(&g_nodeGraph, &sourceNodeConfig, NULL, &g_sourceNode);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize excite node."</span>);
|
||||
<span style="color:#0033ff">goto</span> done3;
|
||||
}
|
||||
|
||||
ma_node_attach_output_bus(&g_sourceNode, 0, &g_vocoderNode, 0);
|
||||
|
||||
|
||||
<span style="color:#009900">/* Excite/modulator. Attached to input bus 1 of the vocoder node. */</span>
|
||||
result = ma_audio_buffer_ref_init(device.capture.format, device.capture.channels, NULL, 0, &g_exciteData);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize audio buffer for source."</span>);
|
||||
<span style="color:#0033ff">goto</span> done2;
|
||||
}
|
||||
|
||||
exciteNodeConfig = ma_data_source_node_config_init(&g_exciteData);
|
||||
|
||||
result = ma_data_source_node_init(&g_nodeGraph, &exciteNodeConfig, NULL, &g_exciteNode);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize source node."</span>);
|
||||
<span style="color:#0033ff">goto</span> done2;
|
||||
}
|
||||
|
||||
ma_node_attach_output_bus(&g_exciteNode, 0, &g_vocoderNode, 1);
|
||||
|
||||
|
||||
ma_device_start(&device);
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit...\n"</span>);
|
||||
getchar();
|
||||
|
||||
<span style="color:#009900">/* It's important that we stop the device first or else we'll uninitialize the graph from under the device. */</span>
|
||||
ma_device_stop(&device);
|
||||
|
||||
<span style="color:#009900">/*done4:*/</span> ma_data_source_node_uninit(&g_exciteNode, NULL);
|
||||
done3: ma_data_source_node_uninit(&g_sourceNode, NULL);
|
||||
done2: ma_vocoder_node_uninit(&g_vocoderNode, NULL);
|
||||
done1: ma_node_graph_uninit(&g_nodeGraph, NULL);
|
||||
done0: ma_device_uninit(&device);
|
||||
|
||||
(<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,524 @@
|
||||
<!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://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="../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 doc-navigation-active">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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Engine Advanced</h1><p>
|
||||
This example demonstrates some of the advanced features of the high level engine API.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The following features are demonstrated:
|
||||
</p>
|
||||
<ul style="overflow:hidden;">
|
||||
<li>
|
||||
Initialization of the engine from a pre-initialized device.</li>
|
||||
<li>
|
||||
Self-managed resource managers.</li>
|
||||
<li>
|
||||
Multiple engines with a shared resource manager.</li>
|
||||
<li>
|
||||
Creation and management of <span style="font-family:monospace;">ma_sound</span> objects.</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
This example will play the sound that's passed in on the command line.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
Using a shared resource manager, as we do in this example, is useful for when you want to user
|
||||
multiple engines so that you can output to multiple playback devices simultaneoulys. An example
|
||||
might be a local co-op multiplayer game where each player has their own headphones.</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">"../miniaudio.h"</span>
|
||||
|
||||
<span style="color:#666666">#define</span> MAX_DEVICES 2
|
||||
<span style="color:#666666">#define</span> MAX_SOUNDS 32
|
||||
|
||||
<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:#0033ff">void</span>)pInput;
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Since we're managing the underlying device ourselves, we need to read from the engine directly.
|
||||
To do this we need access to the <span style="font-family:monospace;">ma_engine</span> object which we passed in to the user data. One
|
||||
advantage of this is that you could do your own audio processing in addition to the engine's
|
||||
standard processing.
|
||||
*/</span>
|
||||
ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL);
|
||||
}
|
||||
|
||||
<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_context</span> context;
|
||||
ma_resource_manager_config resourceManagerConfig;
|
||||
ma_resource_manager resourceManager;
|
||||
ma_engine engines[MAX_DEVICES];
|
||||
<span style="color:#0099cc">ma_device</span> devices[MAX_DEVICES];
|
||||
<span style="color:#0099cc">ma_uint32</span> engineCount = 0;
|
||||
<span style="color:#0099cc">ma_uint32</span> iEngine;
|
||||
<span style="color:#0099cc">ma_device_info</span>* pPlaybackDeviceInfos;
|
||||
<span style="color:#0099cc">ma_uint32</span> playbackDeviceCount;
|
||||
<span style="color:#0099cc">ma_uint32</span> iAvailableDevice;
|
||||
<span style="color:#0099cc">ma_uint32</span> iChosenDevice;
|
||||
ma_sound sounds[MAX_SOUNDS];
|
||||
<span style="color:#0099cc">ma_uint32</span> soundCount;
|
||||
<span style="color:#0099cc">ma_uint32</span> iSound;
|
||||
|
||||
<span style="color:#0033ff">if</span> (argc < 2) {
|
||||
printf(<span style="color:#cc3300">"No input file."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/*
|
||||
We are going to be initializing multiple engines. In order to save on memory usage we can use a self managed
|
||||
resource manager so we can share a single resource manager across multiple engines.
|
||||
*/</span>
|
||||
resourceManagerConfig = ma_resource_manager_config_init();
|
||||
resourceManagerConfig.decodedFormat = ma_format_f32; <span style="color:#009900">/* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */</span>
|
||||
resourceManagerConfig.decodedChannels = 0; <span style="color:#009900">/* Setting the channel count to 0 will cause sounds to use their native channel count. */</span>
|
||||
resourceManagerConfig.decodedSampleRate = 48000; <span style="color:#009900">/* Using a consistent sample rate is useful for avoiding expensive resampling in the audio thread. This will result in resampling being performed by the loading thread(s). */</span>
|
||||
|
||||
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize resource manager."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* We're going to want a context so we can enumerate our playback devices. */</span>
|
||||
result = ma_context_init(NULL, 0, NULL, &context);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize context."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Now that we have a context we will want to enumerate over each device so we can display them to the user and give
|
||||
them a chance to select the output devices they want to use.
|
||||
*/</span>
|
||||
result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to enumerate playback devices."</span>);
|
||||
ma_context_uninit(&context);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* We have our devices, so now we want to get the user to select the devices they want to output to. */</span>
|
||||
engineCount = 0;
|
||||
|
||||
<span style="color:#0033ff">for</span> (iChosenDevice = 0; iChosenDevice < MAX_DEVICES; iChosenDevice += 1) {
|
||||
<span style="color:#0033ff">int</span> <span style="color:#0033ff">c</span> = 0;
|
||||
<span style="color:#0033ff">for</span> (;;) {
|
||||
printf(<span style="color:#cc3300">"Select playback device %d ([%d - %d], Q to quit):\n"</span>, iChosenDevice+1, 0, ma_min((<span style="color:#0033ff">int</span>)playbackDeviceCount, 9));
|
||||
|
||||
<span style="color:#0033ff">for</span> (iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) {
|
||||
printf(<span style="color:#cc3300">" %d: %s\n"</span>, iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name);
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">for</span> (;;) {
|
||||
<span style="color:#0033ff">c</span> = getchar();
|
||||
<span style="color:#0033ff">if</span> (<span style="color:#0033ff">c</span> != <span style="color:#cc3300">'\n'</span>) {
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">if</span> (<span style="color:#0033ff">c</span> == <span style="color:#cc3300">'q'</span> || <span style="color:#0033ff">c</span> == <span style="color:#cc3300">'Q'</span>) {
|
||||
<span style="color:#0033ff">return</span> 0; <span style="color:#009900">/* User aborted. */</span>
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">if</span> (<span style="color:#0033ff">c</span> >= <span style="color:#cc3300">'0'</span> && <span style="color:#0033ff">c</span> <= <span style="color:#cc3300">'9'</span>) {
|
||||
<span style="color:#0033ff">c</span> -= <span style="color:#cc3300">'0'</span>;
|
||||
|
||||
<span style="color:#0033ff">if</span> (<span style="color:#0033ff">c</span> < (<span style="color:#0033ff">int</span>)playbackDeviceCount) {
|
||||
<span style="color:#0099cc">ma_device_config</span> deviceConfig;
|
||||
ma_engine_config engineConfig;
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Create the device first before the engine. We'll specify the device in the engine's config. This is optional. When a device is
|
||||
not pre-initialized the engine will create one for you internally. The device does not need to be started here - the engine will
|
||||
do that for us in <span style="font-family:monospace;">ma_engine_start()</span>. The device's format is derived from the resource manager, but can be whatever you want.
|
||||
It's useful to keep the format consistent with the resource manager to avoid data conversions costs in the audio callback. In
|
||||
this example we're using the resource manager's sample format and sample rate, but leaving the channel count set to the device's
|
||||
native channels. You can use whatever format/channels/rate you like.
|
||||
*/</span>
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[<span style="color:#0033ff">c</span>].id;
|
||||
deviceConfig.playback.format = resourceManager.config.decodedFormat;
|
||||
deviceConfig.playback.channels = 0;
|
||||
deviceConfig.sampleRate = resourceManager.config.decodedSampleRate;
|
||||
deviceConfig.dataCallback = data_callback;
|
||||
deviceConfig.pUserData = &engines[engineCount];
|
||||
|
||||
result = ma_device_init(&context, &deviceConfig, &devices[engineCount]);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize device for %s.\n"</span>, pPlaybackDeviceInfos[<span style="color:#0033ff">c</span>].name);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Now that we have the device we can initialize the engine. The device is passed into the engine's config. */</span>
|
||||
engineConfig = ma_engine_config_init();
|
||||
engineConfig.pDevice = &devices[engineCount];
|
||||
engineConfig.pResourceManager = &resourceManager;
|
||||
engineConfig.noAutoStart = MA_TRUE; <span style="color:#009900">/* Don't start the engine by default - we'll do that manually below. */</span>
|
||||
|
||||
result = ma_engine_init(&engineConfig, &engines[engineCount]);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize engine for %s.\n"</span>, pPlaybackDeviceInfos[<span style="color:#0033ff">c</span>].name);
|
||||
ma_device_uninit(&devices[engineCount]);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
engineCount += 1;
|
||||
<span style="color:#0033ff">break</span>;
|
||||
} <span style="color:#0033ff">else</span> {
|
||||
printf(<span style="color:#cc3300">"Invalid device number.\n"</span>);
|
||||
}
|
||||
} <span style="color:#0033ff">else</span> {
|
||||
printf(<span style="color:#cc3300">"Invalid device number.\n"</span>);
|
||||
}
|
||||
}
|
||||
|
||||
printf(<span style="color:#cc3300">"Device %d: %s\n"</span>, iChosenDevice+1, pPlaybackDeviceInfos[<span style="color:#0033ff">c</span>].name);
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* We should now have our engine's initialized. We can now start them. */</span>
|
||||
<span style="color:#0033ff">for</span> (iEngine = 0; iEngine < engineCount; iEngine += 1) {
|
||||
result = ma_engine_start(&engines[iEngine]);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"WARNING: Failed to start engine %d.\n"</span>, iEngine);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/*
|
||||
At this point our engine's are running and outputting nothing but silence. To get them playing something we'll need
|
||||
some sounds. In this example we're just using one sound per engine, but you can create as many as you like. Since
|
||||
we're using a shared resource manager, the sound data will only be loaded once. This is how you would implement
|
||||
multiple listeners.
|
||||
*/</span>
|
||||
soundCount = 0;
|
||||
<span style="color:#0033ff">for</span> (iEngine = 0; iEngine < engineCount; iEngine += 1) {
|
||||
<span style="color:#009900">/* Just one sound per engine in this example. We're going to be loading this asynchronously. */</span>
|
||||
result = ma_sound_init_from_file(&engines[iEngine], argv[1], MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM, NULL, NULL, &sounds[iEngine]);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"WARNING: Failed to load sound \"%s\""</span>, argv[1]);
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
The sound can be started as soon as ma_sound_init_from_file() returns, even for sounds that are initialized
|
||||
with MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC. The sound will start playing while it's being loaded. Note that if the
|
||||
asynchronous loading process cannot keep up with the rate at which you try reading you'll end up glitching.
|
||||
If this is an issue, you need to not load sounds asynchronously.
|
||||
*/</span>
|
||||
result = ma_sound_start(&sounds[iEngine]);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"WARNING: Failed to start sound."</span>);
|
||||
}
|
||||
|
||||
soundCount += 1;
|
||||
}
|
||||
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit..."</span>);
|
||||
getchar();
|
||||
|
||||
<span style="color:#0033ff">for</span> (;;) {
|
||||
<span style="color:#0033ff">int</span> <span style="color:#0033ff">c</span> = getchar();
|
||||
<span style="color:#0033ff">if</span> (<span style="color:#0033ff">c</span> == <span style="color:#cc3300">'\n'</span>) {
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Teardown. */</span>
|
||||
|
||||
<span style="color:#009900">/* The application owns the <span style="font-family:monospace;">ma_sound</span> object which means you're responsible for uninitializing them. */</span>
|
||||
<span style="color:#0033ff">for</span> (iSound = 0; iSound < soundCount; iSound += 1) {
|
||||
ma_sound_uninit(&sounds[iSound]);
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* We can now uninitialize each engine. */</span>
|
||||
<span style="color:#0033ff">for</span> (iEngine = 0; iEngine < engineCount; iEngine += 1) {
|
||||
ma_engine_uninit(&engines[iEngine]);
|
||||
|
||||
<span style="color:#009900">/*
|
||||
The engine has been uninitialized so now lets uninitialize the device. Do this first to ensure we don't
|
||||
uninitialize the resource manager from under the device while the data callback is running.
|
||||
*/</span>
|
||||
ma_device_uninit(&devices[iEngine]);
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Do the resource manager last. This way we can guarantee the data callbacks of each device aren't trying to access
|
||||
and data managed by the resource manager.
|
||||
*/</span>
|
||||
ma_resource_manager_uninit(&resourceManager);
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,374 @@
|
||||
<!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://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="../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 doc-navigation-active">Engine Effects</a><a href="engine_hello_world.html" class="doc-navigation doc-navigation-l1 ">Engine Hello World</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Engine Effects</h1><p>
|
||||
Demonstrates how to apply an effect to sounds using the high level engine API.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This example will load a file from the command line and apply an echo/delay effect to it. It will
|
||||
show you how to manage <span style="font-family:monospace;">ma_sound</span> objects and how to insert an effect into the graph.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The <span style="font-family:monospace;">ma_engine</span> object is a node graph and is compatible with the <span style="font-family:monospace;">ma_node_graph</span> API. The
|
||||
<span style="font-family:monospace;">ma_sound</span> object is a node within the node and is compatible with the <span style="font-family:monospace;">ma_node</span> API. This means
|
||||
that applying an effect is as simple as inserting an effect node into the graph and plugging in the
|
||||
sound's output into the effect's input. See the Node Graph example for how to use the node graph.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This example is playing only a single sound at a time which means only a single <span style="font-family:monospace;">ma_sound</span> object
|
||||
it being used. If you want to play multiple sounds at the same time, even if they're for the same
|
||||
sound file, you need multiple <span style="font-family:monospace;">ma_sound</span> objects.</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">"../miniaudio.h"</span>
|
||||
|
||||
<span style="color:#666666">#define</span> DELAY_IN_SECONDS 0.2f
|
||||
<span style="color:#666666">#define</span> DECAY 0.25f <span style="color:#009900">/* Volume falloff for each echo. */</span>
|
||||
|
||||
<span style="color:#0033ff">static</span> ma_engine g_engine;
|
||||
<span style="color:#0033ff">static</span> ma_sound g_sound; <span style="color:#009900">/* This example will play only a single sound at once, so we only need one <span style="font-family:monospace;">ma_sound</span> object. */</span>
|
||||
<span style="color:#0033ff">static</span> ma_delay_node g_delayNode; <span style="color:#009900">/* The echo effect is achieved using a delay node. */</span>
|
||||
|
||||
<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:#0033ff">if</span> (argc < 2) {
|
||||
printf(<span style="color:#cc3300">"No input file."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* The engine needs to be initialized first. */</span>
|
||||
result = ma_engine_init(NULL, &g_engine);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize audio engine."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/*
|
||||
We'll build our graph starting from the end so initialize the delay node now. The output of
|
||||
this node will be connected straight to the output. You could also attach it to a sound group
|
||||
or any other node that accepts an input.
|
||||
|
||||
Creating a node requires a pointer to the node graph that owns it. The engine itself is a node
|
||||
graph. In the code below we can get a pointer to the node graph with <span style="font-family:monospace;">ma_engine_get_node_graph()</span>
|
||||
or we could simple cast the engine to a ma_node_graph* like so:
|
||||
|
||||
(ma_node_graph*)&g_engine
|
||||
|
||||
The endpoint of the graph can be retrieved with <span style="font-family:monospace;">ma_engine_get_endpoint()</span>.
|
||||
*/</span>
|
||||
{
|
||||
ma_delay_node_config delayNodeConfig;
|
||||
<span style="color:#0099cc">ma_uint32</span> channels;
|
||||
<span style="color:#0099cc">ma_uint32</span> sampleRate;
|
||||
|
||||
channels = ma_engine_get_channels(&g_engine);
|
||||
sampleRate = ma_engine_get_sample_rate(&g_engine);
|
||||
|
||||
delayNodeConfig = ma_delay_node_config_init(channels, sampleRate, (<span style="color:#0099cc">ma_uint32</span>)(sampleRate * DELAY_IN_SECONDS), DECAY);
|
||||
|
||||
result = ma_delay_node_init(ma_engine_get_node_graph(&g_engine), &delayNodeConfig, NULL, &g_delayNode);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize delay node."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Connect the output of the delay node to the input of the endpoint. */</span>
|
||||
ma_node_attach_output_bus(&g_delayNode, 0, ma_engine_get_endpoint(&g_engine), 0);
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Now we can load the sound and connect it to the delay node. */</span>
|
||||
{
|
||||
result = ma_sound_init_from_file(&g_engine, argv[1], 0, NULL, NULL, &g_sound);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize sound \"%s\"."</span>, argv[1]);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Connect the output of the sound to the input of the effect. */</span>
|
||||
ma_node_attach_output_bus(&g_sound, 0, &g_delayNode, 0);
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Start the sound after it's applied to the sound. Otherwise there could be a scenario where
|
||||
the very first part of it is read before the attachment to the effect is made.
|
||||
*/</span>
|
||||
ma_sound_start(&g_sound);
|
||||
}
|
||||
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit..."</span>);
|
||||
getchar();
|
||||
|
||||
ma_sound_uninit(&g_sound);
|
||||
ma_delay_node_uninit(&g_delayNode, NULL);
|
||||
ma_engine_uninit(&g_engine);
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,302 @@
|
||||
<!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://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="../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 doc-navigation-active">Engine Hello World</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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>Engine Hello World</h1><p>
|
||||
This example demonstrates how to initialize an audio engine and play a sound.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This will play the sound specified on the command line.</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">"../miniaudio.h"</span>
|
||||
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300"><stdio.h></span>
|
||||
|
||||
<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;
|
||||
ma_engine engine;
|
||||
|
||||
<span style="color:#0033ff">if</span> (argc < 2) {
|
||||
printf(<span style="color:#cc3300">"No input file."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
result = ma_engine_init(NULL, &engine);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize audio engine."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
ma_engine_play_sound(&engine, argv[1], NULL);
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit..."</span>);
|
||||
getchar();
|
||||
|
||||
ma_engine_uninit(&engine);
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 doc-navigation-active">Fixed Size Callback</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="../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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 doc-navigation-active">Fixed Size Callback</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="../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>Fixed Size Callback</h1><p>
|
||||
Shows one way to implement a data callback that is called with a fixed frame count.
|
||||
</p>
|
||||
@@ -289,7 +289,7 @@ of data movement.</p>
|
||||
*/</span>
|
||||
printf(<span style="color:#cc3300">"frameCount=%d\n"</span>, frameCount);
|
||||
|
||||
ma_waveform_read_pcm_frames(&g_sineWave, pOutput, frameCount);
|
||||
ma_waveform_read_pcm_frames(&g_sineWave, pOutput, frameCount, NULL);
|
||||
|
||||
<span style="color:#009900">/* Unused in this example. */</span>
|
||||
(<span style="color:#0033ff">void</span>)pDevice;
|
||||
@@ -324,7 +324,7 @@ of data movement.</p>
|
||||
{
|
||||
memcpy(pRunningOutput, pReadBuffer, framesToRead * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels));
|
||||
}
|
||||
ma_pcm_rb_commit_read(&g_rb, framesToRead, pReadBuffer);
|
||||
ma_pcm_rb_commit_read(&g_rb, framesToRead);
|
||||
|
||||
pRunningOutput += framesToRead * ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels);
|
||||
pcmFramesProcessed += framesToRead;
|
||||
@@ -344,7 +344,7 @@ of data movement.</p>
|
||||
MA_ASSERT(framesToWrite == PCM_FRAME_CHUNK_SIZE); <span style="color:#009900">/* <-- This should always work in this example because we just reset the ring buffer. */</span>
|
||||
data_callback_fixed(pDevice, pWriteBuffer, NULL, framesToWrite);
|
||||
}
|
||||
ma_pcm_rb_commit_write(&g_rb, framesToWrite, pWriteBuffer);
|
||||
ma_pcm_rb_commit_write(&g_rb, framesToWrite);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -245,10 +245,10 @@ a.doc-navigation-l4 {
|
||||
<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 doc-navigation-active">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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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;">
|
||||
<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 doc-navigation-active">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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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="../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;">Examples</div><div style="padding-top:0.75em; text-align:center;"><a href="../manual/index.html">Programming Manual</a> - <a href="../api/index.html">API Reference</a> - <a href="https://github.com/mackron/miniaudio">Source Code</a></div></div>
|
||||
<table style="border:none;"><tr><td style="padding-right:2em;"><a href="custom_backend.html">Custom Backend</a></td><td>This example show how a custom backend can be implemented.</td></tr><tr><td style="padding-right:2em;"><a href="custom_decoder.html">Custom Decoder</a></td><td>Demonstrates how to implement a custom decoder.</td></tr><tr><td style="padding-right:2em;"><a href="data_source_chaining.html">Data Source Chaining</a></td><td>Demonstrates one way to chain together a number of data sources so they play back seamlessly
|
||||
without gaps.</td></tr><tr><td style="padding-right:2em;"><a href="fixed_size_callback.html">Fixed Size Callback</a></td><td>Shows one way to implement a data callback that is called with a fixed frame count.</td></tr><tr><td style="padding-right:2em;"><a href="simple_capture.html">Simple Capture</a></td><td>Demonstrates how to capture data from a microphone using the low-level API.</td></tr><tr><td style="padding-right:2em;"><a href="simple_duplex.html">Simple Duplex</a></td><td>Demonstrates duplex mode which is where data is captured from a microphone and then output to a speaker device.</td></tr><tr><td style="padding-right:2em;"><a href="simple_enumeration.html">Simple Enumeration</a></td><td>Demonstrates how to enumerate over devices.</td></tr><tr><td style="padding-right:2em;"><a href="simple_loopback.html">Simple Loopback</a></td><td>Demonstrates how to implement loopback recording.</td></tr><tr><td style="padding-right:2em;"><a href="simple_looping.html">Simple Looping</a></td><td>Shows one way to handle looping of a sound.</td></tr><tr><td style="padding-right:2em;"><a href="simple_mixing.html">Simple Mixing</a></td><td>Demonstrates one way to load multiple files and play them all back at the same time.</td></tr><tr><td style="padding-right:2em;"><a href="simple_playback.html">Simple Playback</a></td><td>Demonstrates how to load a sound file and play it back using the low-level API.</td></tr><tr><td style="padding-right:2em;"><a href="simple_playback_sine.html">Simple Playback Sine</a></td><td>Demonstrates playback of a sine wave.</td></tr></table></td>
|
||||
<table style="border:none;"><tr><td style="padding-right:2em;"><a href="custom_backend.html">Custom Backend</a></td><td>This example show how a custom backend can be implemented.</td></tr><tr><td style="padding-right:2em;"><a href="custom_decoder.html">Custom Decoder</a></td><td>Demonstrates how to implement a custom decoder.</td></tr><tr><td style="padding-right:2em;"><a href="custom_decoder_engine.html">Custom Decoder Engine</a></td><td>Demonstrates how to implement a custom decoder and use it with the high level API.</td></tr><tr><td style="padding-right:2em;"><a href="data_source_chaining.html">Data Source Chaining</a></td><td>Demonstrates one way to chain together a number of data sources so they play back seamlessly
|
||||
without gaps.</td></tr><tr><td style="padding-right:2em;"><a href="duplex_effect.html">Duplex Effect</a></td><td>Demonstrates how to apply an effect to a duplex stream using the node graph system.</td></tr><tr><td style="padding-right:2em;"><a href="engine_advanced.html">Engine Advanced</a></td><td>This example demonstrates some of the advanced features of the high level engine API.</td></tr><tr><td style="padding-right:2em;"><a href="engine_effects.html">Engine Effects</a></td><td>Demonstrates how to apply an effect to sounds using the high level engine API.</td></tr><tr><td style="padding-right:2em;"><a href="engine_hello_world.html">Engine Hello World</a></td><td>This example demonstrates how to initialize an audio engine and play a sound.</td></tr><tr><td style="padding-right:2em;"><a href="fixed_size_callback.html">Fixed Size Callback</a></td><td>Shows one way to implement a data callback that is called with a fixed frame count.</td></tr><tr><td style="padding-right:2em;"><a href="node_graph.html">Node Graph</a></td><td>This example shows how to use the node graph system.</td></tr><tr><td style="padding-right:2em;"><a href="resource_manager.html">Resource Manager</a></td><td>Demonstrates how you can use the resource manager to manage loaded sounds.</td></tr><tr><td style="padding-right:2em;"><a href="resource_manager_advanced.html">Resource Manager Advanced</a></td><td>Demonstrates how you can use the resource manager to manage loaded sounds.</td></tr><tr><td style="padding-right:2em;"><a href="simple_capture.html">Simple Capture</a></td><td>Demonstrates how to capture data from a microphone using the low-level API.</td></tr><tr><td style="padding-right:2em;"><a href="simple_duplex.html">Simple Duplex</a></td><td>Demonstrates duplex mode which is where data is captured from a microphone and then output to a speaker device.</td></tr><tr><td style="padding-right:2em;"><a href="simple_enumeration.html">Simple Enumeration</a></td><td>Demonstrates how to enumerate over devices.</td></tr><tr><td style="padding-right:2em;"><a href="simple_loopback.html">Simple Loopback</a></td><td>Demonstrates how to implement loopback recording.</td></tr><tr><td style="padding-right:2em;"><a href="simple_looping.html">Simple Looping</a></td><td>Shows one way to handle looping of a sound.</td></tr><tr><td style="padding-right:2em;"><a href="simple_mixing.html">Simple Mixing</a></td><td>Demonstrates one way to load multiple files and play them all back at the same time.</td></tr><tr><td style="padding-right:2em;"><a href="simple_playback.html">Simple Playback</a></td><td>Demonstrates how to load a sound file and play it back using the low-level API.</td></tr><tr><td style="padding-right:2em;"><a href="simple_playback_sine.html">Simple Playback Sine</a></td><td>Demonstrates playback of a sine wave.</td></tr></table></td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<table style="margin:0 auto; padding:1em 0px; text-align:center;">
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
<!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://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="../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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</a><a href="node_graph.html" class="doc-navigation doc-navigation-l1 doc-navigation-active">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="../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>Node Graph</h1><p>
|
||||
This example shows how to use the node graph system.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The node graph system can be used for doing complex mixing and effect processing. The idea is that
|
||||
you have a number of nodes that are connected to each other to form a graph. At the end of the
|
||||
graph is an endpoint which all nodes eventually connect to.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
A node is used to do some kind of processing on zero or more input streams and produce one or more
|
||||
output streams. Each node can have a number of inputs and outputs. Each of these is called a bus in
|
||||
miniaudio. Some nodes, particularly data source nodes, have no inputs and instead generate their
|
||||
outputs dynamically. All nodes will have at least one output or else it'll be disconnected from the
|
||||
graph and will never get processed. Each output bus of a node will be connected to an input bus of
|
||||
another node, but they don't all need to connect to the same input node. For example, a splitter
|
||||
node has 1 input bus and 2 output buses and is used to duplicate a signal. You could then branch
|
||||
off and have one output bus connected to one input node and the other connected to a different
|
||||
input node, and then have two different effects process for each of the duplicated branches.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
Any number of output buses can be connected to an input bus in which case the output buses will be
|
||||
mixed before processing by the input node. This is how you would achieve the mixing part of the
|
||||
node graph.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This example will be using the following node graph set up:
|
||||
</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;">
|
||||
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Data flows left to right >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
+---------------+ +-----------------+
|
||||
| Data Source 1 =----+ +----------+ +----= Low Pass Filter =----+
|
||||
+---------------+ | | =----+ +-----------------+ | +----------+
|
||||
+----= Splitter | +----= ENDPOINT |
|
||||
+---------------+ | | =----+ +-----------------+ | +----------+
|
||||
| Data Source 2 =----+ +----------+ +----= Echo / Delay =----+
|
||||
+---------------+ +-----------------+
|
||||
</pre></div><p>
|
||||
|
||||
This does not represent a realistic real-world scenario, but it demonstrates how to make use of
|
||||
mixing, multiple outputs and multiple effects.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The data source nodes are connected to the input of the splitter. They'll be mixed before being
|
||||
processed by the splitter. The splitter has two output buses. In the graph above, one bus will be
|
||||
routed to a low pass filter, whereas the other bus will be routed to an echo effect. Then, the
|
||||
outputs of these two effects will be connected to the input bus of the endpoint. Because both of
|
||||
the outputs are connected to the same input bus, they'll be mixed at that point.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The two data sources at the start of the graph have no inputs. They'll instead generate their
|
||||
output by reading from a data source. The data source in this case will be one <span style="font-family:monospace;">ma_decoder</span> for
|
||||
each input file specified on the command line.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
You can also control the volume of an output bus. In this example, we set the volumes of the low
|
||||
pass and echo effects so that one of them becomes more obvious than the other.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
When you want to read from the graph, you simply call <span style="font-family:monospace;">ma_node_graph_read_pcm_frames()</span>.</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">"../miniaudio.h"</span>
|
||||
|
||||
<span style="color:#009900">/* Data Format */</span>
|
||||
<span style="color:#666666">#define</span> FORMAT ma_format_f32 <span style="color:#009900">/* Must always be f32. */</span>
|
||||
<span style="color:#666666">#define</span> CHANNELS 2
|
||||
<span style="color:#666666">#define</span> SAMPLE_RATE 48000
|
||||
|
||||
<span style="color:#009900">/* Effect Properties */</span>
|
||||
<span style="color:#666666">#define</span> LPF_BIAS 0.9f <span style="color:#009900">/* Higher values means more bias towards the low pass filter (the low pass filter will be more audible). Lower values means more bias towards the echo. Must be between 0 and 1. */</span>
|
||||
<span style="color:#666666">#define</span> LPF_CUTOFF_FACTOR 80 <span style="color:#009900">/* High values = more filter. */</span>
|
||||
<span style="color:#666666">#define</span> LPF_ORDER 8
|
||||
<span style="color:#666666">#define</span> DELAY_IN_SECONDS 0.2f
|
||||
<span style="color:#666666">#define</span> DECAY 0.5f <span style="color:#009900">/* Volume falloff for each echo. */</span>
|
||||
|
||||
<span style="color:#0033ff">typedef</span> <span style="color:#0033ff">struct</span>
|
||||
{
|
||||
ma_data_source_node node; <span style="color:#009900">/* If you make this the first member, you can pass a pointer to this struct into any <span style="font-family:monospace;">ma_node_*</span> API and it will "Just Work". */</span>
|
||||
<span style="color:#0099cc">ma_decoder</span> decoder;
|
||||
} sound_node;
|
||||
|
||||
<span style="color:#0033ff">static</span> ma_node_graph g_nodeGraph;
|
||||
<span style="color:#0033ff">static</span> ma_lpf_node g_lpfNode;
|
||||
<span style="color:#0033ff">static</span> ma_delay_node g_delayNode;
|
||||
<span style="color:#0033ff">static</span> ma_splitter_node g_splitterNode;
|
||||
<span style="color:#0033ff">static</span> sound_node* g_pSoundNodes;
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0033ff">int</span> g_soundNodeCount;
|
||||
|
||||
<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)
|
||||
{
|
||||
MA_ASSERT(pDevice->playback.channels == CHANNELS);
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Hearing the output of the node graph is as easy as reading straight into the output buffer. You just need to
|
||||
make sure you use a consistent data format or else you'll need to do your own conversion.
|
||||
*/</span>
|
||||
ma_node_graph_read_pcm_frames(&g_nodeGraph, pOutput, frameCount, NULL);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pInput; <span style="color:#009900">/* Unused. */</span>
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">int</span> main(<span style="color:#0033ff">int</span> argc, <span style="color:#0033ff">char</span>** argv)
|
||||
{
|
||||
<span style="color:#0033ff">int</span> iarg;
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
|
||||
<span style="color:#009900">/* We'll set up our nodes starting from the end and working our way back to the start. We'll need to set up the graph first. */</span>
|
||||
{
|
||||
ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(CHANNELS);
|
||||
|
||||
result = ma_node_graph_init(&nodeGraphConfig, NULL, &g_nodeGraph);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"ERROR: Failed to initialize node graph."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Low Pass Filter. */</span>
|
||||
{
|
||||
ma_lpf_node_config lpfNodeConfig = ma_lpf_node_config_init(CHANNELS, SAMPLE_RATE, SAMPLE_RATE / LPF_CUTOFF_FACTOR, LPF_ORDER);
|
||||
|
||||
result = ma_lpf_node_init(&g_nodeGraph, &lpfNodeConfig, NULL, &g_lpfNode);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"ERROR: Failed to initialize low pass filter node."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Connect the output bus of the low pass filter node to the input bus of the endpoint. */</span>
|
||||
ma_node_attach_output_bus(&g_lpfNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
||||
|
||||
<span style="color:#009900">/* Set the volume of the low pass filter to make it more of less impactful. */</span>
|
||||
ma_node_set_output_bus_volume(&g_lpfNode, 0, LPF_BIAS);
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Echo / Delay. */</span>
|
||||
{
|
||||
ma_delay_node_config delayNodeConfig = ma_delay_node_config_init(CHANNELS, SAMPLE_RATE, (<span style="color:#0099cc">ma_uint32</span>)(SAMPLE_RATE * DELAY_IN_SECONDS), DECAY);
|
||||
|
||||
result = ma_delay_node_init(&g_nodeGraph, &delayNodeConfig, NULL, &g_delayNode);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"ERROR: Failed to initialize delay node."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Connect the output bus of the delay node to the input bus of the endpoint. */</span>
|
||||
ma_node_attach_output_bus(&g_delayNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0);
|
||||
|
||||
<span style="color:#009900">/* Set the volume of the delay filter to make it more of less impactful. */</span>
|
||||
ma_node_set_output_bus_volume(&g_delayNode, 0, 1 - LPF_BIAS);
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Splitter. */</span>
|
||||
{
|
||||
ma_splitter_node_config splitterNodeConfig = ma_splitter_node_config_init(CHANNELS);
|
||||
|
||||
result = ma_splitter_node_init(&g_nodeGraph, &splitterNodeConfig, NULL, &g_splitterNode);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"ERROR: Failed to initialize splitter node."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Connect output bus 0 to the input bus of the low pass filter node, and output bus 1 to the input bus of the delay node. */</span>
|
||||
ma_node_attach_output_bus(&g_splitterNode, 0, &g_lpfNode, 0);
|
||||
ma_node_attach_output_bus(&g_splitterNode, 1, &g_delayNode, 0);
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* Data sources. Ignore any that cannot be loaded. */</span>
|
||||
g_pSoundNodes = (sound_node*)ma_malloc(<span style="color:#0033ff">sizeof</span>(*g_pSoundNodes) * argc-1, NULL);
|
||||
<span style="color:#0033ff">if</span> (g_pSoundNodes == NULL) {
|
||||
printf(<span style="color:#cc3300">"Failed to allocate memory for sounds."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
g_soundNodeCount = 0;
|
||||
<span style="color:#0033ff">for</span> (iarg = 1; iarg < argc; iarg += 1) {
|
||||
<span style="color:#0099cc">ma_decoder_config</span> decoderConfig = ma_decoder_config_init(FORMAT, CHANNELS, SAMPLE_RATE);
|
||||
|
||||
result = ma_decoder_init_file(argv[iarg], &decoderConfig, &g_pSoundNodes[g_soundNodeCount].decoder);
|
||||
<span style="color:#0033ff">if</span> (result == MA_SUCCESS) {
|
||||
ma_data_source_node_config dataSourceNodeConfig = ma_data_source_node_config_init(&g_pSoundNodes[g_soundNodeCount].decoder);
|
||||
|
||||
result = ma_data_source_node_init(&g_nodeGraph, &dataSourceNodeConfig, NULL, &g_pSoundNodes[g_soundNodeCount].node);
|
||||
<span style="color:#0033ff">if</span> (result == MA_SUCCESS) {
|
||||
<span style="color:#009900">/* The data source node has been created successfully. Attach it to the splitter. */</span>
|
||||
ma_node_attach_output_bus(&g_pSoundNodes[g_soundNodeCount].node, 0, &g_splitterNode, 0);
|
||||
g_soundNodeCount += 1;
|
||||
} <span style="color:#0033ff">else</span> {
|
||||
printf(<span style="color:#cc3300">"WARNING: Failed to init data source node for sound \"%s\". Ignoring."</span>, argv[iarg]);
|
||||
ma_decoder_uninit(&g_pSoundNodes[g_soundNodeCount].decoder);
|
||||
}
|
||||
} <span style="color:#0033ff">else</span> {
|
||||
printf(<span style="color:#cc3300">"WARNING: Failed to load sound \"%s\". Ignoring."</span>, argv[iarg]);
|
||||
}
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Everything has been initialized successfully so now we can set up a playback device so we can listen to the result. */</span>
|
||||
{
|
||||
<span style="color:#0099cc">ma_device_config</span> deviceConfig;
|
||||
<span style="color:#0099cc">ma_device</span> device;
|
||||
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.format = FORMAT;
|
||||
deviceConfig.playback.channels = CHANNELS;
|
||||
deviceConfig.sampleRate = SAMPLE_RATE;
|
||||
deviceConfig.dataCallback = data_callback;
|
||||
deviceConfig.pUserData = NULL;
|
||||
|
||||
result = ma_device_init(NULL, &deviceConfig, &device);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"ERROR: Failed to initialize device."</span>);
|
||||
<span style="color:#0033ff">goto</span> cleanup_graph;
|
||||
}
|
||||
|
||||
result = ma_device_start(&device);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_device_uninit(&device);
|
||||
<span style="color:#0033ff">goto</span> cleanup_graph;
|
||||
}
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit...\n"</span>);
|
||||
getchar();
|
||||
|
||||
<span style="color:#009900">/* We're done. Clean up the device. */</span>
|
||||
ma_device_uninit(&device);
|
||||
}
|
||||
|
||||
|
||||
cleanup_graph:
|
||||
{
|
||||
<span style="color:#009900">/* It's good practice to tear down the graph from the lowest level nodes first. */</span>
|
||||
<span style="color:#0033ff">int</span> iSound;
|
||||
|
||||
<span style="color:#009900">/* Sounds. */</span>
|
||||
<span style="color:#0033ff">for</span> (iSound = 0; iSound < g_soundNodeCount; iSound += 1) {
|
||||
ma_data_source_node_uninit(&g_pSoundNodes[iSound].node, NULL);
|
||||
ma_decoder_uninit(&g_pSoundNodes[iSound].decoder);
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Splitter. */</span>
|
||||
ma_splitter_node_uninit(&g_splitterNode, NULL);
|
||||
|
||||
<span style="color:#009900">/* Echo / Delay */</span>
|
||||
ma_delay_node_uninit(&g_delayNode, NULL);
|
||||
|
||||
<span style="color:#009900">/* Low Pass Filter */</span>
|
||||
ma_lpf_node_uninit(&g_lpfNode, NULL);
|
||||
|
||||
<span style="color:#009900">/* Node Graph */</span>
|
||||
ma_node_graph_uninit(&g_nodeGraph, NULL);
|
||||
}
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,430 @@
|
||||
<!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://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="../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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Resource Manager</h1><p>
|
||||
Demonstrates how you can use the resource manager to manage loaded sounds.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
This example loads the first sound specified on the command line via the resource manager and then plays it using the
|
||||
low level API.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
You can control whether or not you want to load the sound asynchronously and whether or not you want to store the data
|
||||
in-memory or stream it. When storing the sound in-memory you can also control whether or not it is decoded. To do this,
|
||||
specify a combination of the following options in <span style="font-family:monospace;">ma_resource_manager_data_source_init()</span>:
|
||||
</p>
|
||||
<ul style="overflow:hidden;">
|
||||
<li>
|
||||
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC - Load asynchronously.</li>
|
||||
<li>
|
||||
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE - Store the sound in-memory in uncompressed/decoded format.</li>
|
||||
<li>
|
||||
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM - Stream the sound from disk rather than storing entirely in memory. Useful for music.</li>
|
||||
</ul>
|
||||
<p>
|
||||
|
||||
The object returned by the resource manager is just a standard data source which means it can be plugged into any of
|
||||
<span style="font-family:monospace;">ma_data_source_*()</span> APIs just like any other data source and it should just work.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
Internally, there's a background thread that's used to process jobs and enable asynchronicity. By default there is only
|
||||
a single job thread, but this can be configured in the resource manager config. You can also implement your own threads
|
||||
for processing jobs. That is more advanced, and beyond the scope of this example.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
When you initialize a resource manager you can specify the sample format, channels and sample rate to use when reading
|
||||
data from the data source. This means the resource manager will ensure all sounds will have a standard format. When not
|
||||
set, each sound will have their own formats and you'll need to do the necessary data conversion yourself.</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_ENGINE <span style="color:#009900">/* We're intentionally not using the ma_engine API here. */</span>
|
||||
<span style="color:#666666">#define</span> MINIAUDIO_IMPLEMENTATION
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300">"../miniaudio.h"</span>
|
||||
|
||||
<span style="color:#666666">#ifdef</span> __EMSCRIPTEN__
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300"><emscripten.h></span>
|
||||
|
||||
<span style="color:#0033ff">void</span> main_loop__em(<span style="color:#0033ff">void</span>* pUserData)
|
||||
{
|
||||
ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData;
|
||||
MA_ASSERT(pResourceManager != NULL);
|
||||
|
||||
<span style="color:#009900">/*
|
||||
The Emscripten build does not support threading which means we need to process jobs manually. If
|
||||
there are no jobs needing to be processed this will return immediately with MA_NO_DATA_AVAILABLE.
|
||||
*/</span>
|
||||
ma_resource_manager_process_next_job(pResourceManager);
|
||||
}
|
||||
<span style="color:#666666">#endif</span>
|
||||
|
||||
<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)
|
||||
{
|
||||
ma_data_source_read_pcm_frames((<span style="color:#0099cc">ma_data_source</span>*)pDevice->pUserData, pOutput, frameCount, NULL);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pInput;
|
||||
}
|
||||
|
||||
<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:#0099cc">ma_device</span> device;
|
||||
ma_resource_manager_config resourceManagerConfig;
|
||||
ma_resource_manager resourceManager;
|
||||
ma_resource_manager_data_source dataSource;
|
||||
|
||||
<span style="color:#0033ff">if</span> (argc < 2) {
|
||||
printf(<span style="color:#cc3300">"No input file."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* We'll initialize the device first. */</span>
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.dataCallback = data_callback;
|
||||
deviceConfig.pUserData = &dataSource; <span style="color:#009900">/* <-- We'll be reading from this in the data callback. */</span>
|
||||
|
||||
result = ma_device_init(NULL, &deviceConfig, &device);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize device."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/*
|
||||
We have the device so now we want to initialize the resource manager. We'll use the resource manager to load a
|
||||
sound based on the command line.
|
||||
*/</span>
|
||||
resourceManagerConfig = ma_resource_manager_config_init();
|
||||
resourceManagerConfig.decodedFormat = device.playback.format;
|
||||
resourceManagerConfig.decodedChannels = device.playback.channels;
|
||||
resourceManagerConfig.decodedSampleRate = device.sampleRate;
|
||||
|
||||
<span style="color:#009900">/*
|
||||
We're not supporting threading with Emscripten so go ahead and disable threading. It's important
|
||||
that we set the appropriate flag and also the job thread count to 0.
|
||||
*/</span>
|
||||
<span style="color:#666666">#ifdef</span> __EMSCRIPTEN__
|
||||
resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING;
|
||||
resourceManagerConfig.jobThreadCount = 0;
|
||||
<span style="color:#666666">#endif</span>
|
||||
|
||||
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_device_uninit(&device);
|
||||
printf(<span style="color:#cc3300">"Failed to initialize the resource manager."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Now that we have a resource manager we can load a sound. */</span>
|
||||
result = ma_resource_manager_data_source_init(
|
||||
&resourceManager,
|
||||
argv[1],
|
||||
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM,
|
||||
NULL, <span style="color:#009900">/* Async notification. */</span>
|
||||
&dataSource);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to load sound \"%s\"."</span>, argv[1]);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* In this example we'll enable looping. */</span>
|
||||
ma_data_source_set_looping(&dataSource, MA_TRUE);
|
||||
|
||||
|
||||
<span style="color:#009900">/* Now that we have a sound we can start the device. */</span>
|
||||
result = ma_device_start(&device);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_device_uninit(&device);
|
||||
printf(<span style="color:#cc3300">"Failed to start device."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#666666">#ifdef</span> __EMSCRIPTEN__
|
||||
emscripten_set_main_loop_arg(main_loop__em, &resourceManager, 0, 1);
|
||||
<span style="color:#666666">#else</span>
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit...\n"</span>);
|
||||
getchar();
|
||||
<span style="color:#666666">#endif</span>
|
||||
|
||||
<span style="color:#009900">/* Teardown. */</span>
|
||||
|
||||
<span style="color:#009900">/* Uninitialize the device first to ensure the data callback is stopped and doesn't try to access any data. */</span>
|
||||
ma_device_uninit(&device);
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Before uninitializing the resource manager we need to uninitialize every data source. The data source is owned by
|
||||
the caller which means you're responsible for uninitializing it.
|
||||
*/</span>
|
||||
ma_resource_manager_data_source_uninit(&dataSource);
|
||||
|
||||
<span style="color:#009900">/* Uninitialize the resource manager after each data source. */</span>
|
||||
ma_resource_manager_uninit(&resourceManager);
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,602 @@
|
||||
<!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://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="../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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Resource Manager Advanced</h1><p>
|
||||
Demonstrates how you can use the resource manager to manage loaded sounds.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The resource manager can be used to create a data source whose resources are managed internally by miniaudio. The data
|
||||
sources can then be read just like any other data source such as decoders and audio buffers.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
In this example we use the resource manager independently of the <span style="font-family:monospace;">ma_engine</span> API so that we can demonstrate how it can
|
||||
be used by itself without getting it confused with <span style="font-family:monospace;">ma_engine</span>.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
The main feature of the resource manager is the ability to decode and stream audio data asynchronously. Asynchronicity
|
||||
is achieved with a job system. The resource manager will issue jobs which are processed by a configurable number of job
|
||||
threads. You can also implement your own custom job threads which this example also demonstrates.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
In this example we show how you can create a data source, mix them with other data sources, configure the number of job
|
||||
threads to manage internally and how to implement your own custom job thread.</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_ENGINE <span style="color:#009900">/* We're intentionally not using the ma_engine API here. */</span>
|
||||
<span style="color:#666666">#define</span> MINIAUDIO_IMPLEMENTATION
|
||||
<span style="color:#666666">#include</span> <span style="color:#cc3300">"../miniaudio.h"</span>
|
||||
|
||||
<span style="color:#0033ff">static</span> ma_resource_manager_data_source g_dataSources[16];
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_uint32</span> g_dataSourceCount;
|
||||
|
||||
|
||||
<span style="color:#009900">/*
|
||||
TODO: Consider putting these public functions in miniaudio.h. Will depend on ma_mix_pcm_frames_f32()
|
||||
being merged into miniaudio.h (it's currently in miniaudio_engine.h).
|
||||
*/</span>
|
||||
<span style="color:#0033ff">static</span> <span style="color:#0099cc">ma_result</span> ma_data_source_read_pcm_frames_f32_ex(<span style="color:#0099cc">ma_data_source</span>* pDataSource, <span style="color:#0033ff">float</span>* pFramesOut, <span style="color:#0099cc">ma_uint64</span> frameCount, <span style="color:#0099cc">ma_uint64</span>* pFramesRead, ma_format dataSourceFormat, <span style="color:#0099cc">ma_uint32</span> dataSourceChannels)
|
||||
{
|
||||
<span style="color:#009900">/*
|
||||
This function is intended to be used when the format and channel count of the data source is
|
||||
known beforehand. The idea is to avoid overhead due to redundant calls to ma_data_source_get_data_format().
|
||||
*/</span>
|
||||
MA_ASSERT(pDataSource != NULL);
|
||||
|
||||
<span style="color:#0033ff">if</span> (dataSourceFormat == ma_format_f32) {
|
||||
<span style="color:#009900">/* Fast path. No conversion necessary. */</span>
|
||||
<span style="color:#0033ff">return</span> ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, pFramesRead);
|
||||
} <span style="color:#0033ff">else</span> {
|
||||
<span style="color:#009900">/* Slow path. Conversion necessary. */</span>
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
<span style="color:#0099cc">ma_uint64</span> totalFramesRead;
|
||||
<span style="color:#0099cc">ma_uint8</span> temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
|
||||
<span style="color:#0099cc">ma_uint64</span> tempCapInFrames = <span style="color:#0033ff">sizeof</span>(temp) / ma_get_bytes_per_frame(dataSourceFormat, dataSourceChannels);
|
||||
|
||||
totalFramesRead = 0;
|
||||
<span style="color:#0033ff">while</span> (totalFramesRead < frameCount) {
|
||||
<span style="color:#0099cc">ma_uint64</span> framesJustRead;
|
||||
<span style="color:#0099cc">ma_uint64</span> framesToRead = frameCount - totalFramesRead;
|
||||
<span style="color:#0033ff">if</span> (framesToRead > tempCapInFrames) {
|
||||
framesToRead = tempCapInFrames;
|
||||
}
|
||||
|
||||
result = ma_data_source_read_pcm_frames(pDataSource, pFramesOut, framesToRead, &framesJustRead);
|
||||
|
||||
ma_convert_pcm_frames_format(ma_offset_pcm_frames_ptr_f32(pFramesOut, totalFramesRead, dataSourceChannels), ma_format_f32, temp, dataSourceFormat, framesJustRead, dataSourceChannels, ma_dither_mode_none);
|
||||
totalFramesRead += framesJustRead;
|
||||
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">return</span> MA_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
MA_API <span style="color:#0099cc">ma_result</span> ma_data_source_read_pcm_frames_f32(<span style="color:#0099cc">ma_data_source</span>* pDataSource, <span style="color:#0033ff">float</span>* pFramesOut, <span style="color:#0099cc">ma_uint64</span> frameCount, <span style="color:#0099cc">ma_uint64</span>* pFramesRead)
|
||||
{
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
ma_format format;
|
||||
<span style="color:#0099cc">ma_uint32</span> channels;
|
||||
|
||||
result = ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0033ff">return</span> result; <span style="color:#009900">/* Failed to retrieve the data format of the data source. */</span>
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">return</span> ma_data_source_read_pcm_frames_f32_ex(pDataSource, pFramesOut, frameCount, pFramesRead, format, channels);
|
||||
}
|
||||
|
||||
MA_API <span style="color:#0099cc">ma_result</span> ma_data_source_read_pcm_frames_and_mix_f32(<span style="color:#0099cc">ma_data_source</span>* pDataSource, <span style="color:#0033ff">float</span>* pFramesOut, <span style="color:#0099cc">ma_uint64</span> frameCount, <span style="color:#0099cc">ma_uint64</span>* pFramesRead, <span style="color:#0033ff">float</span> volume)
|
||||
{
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
ma_format format;
|
||||
<span style="color:#0099cc">ma_uint32</span> channels;
|
||||
<span style="color:#0099cc">ma_uint64</span> totalFramesRead;
|
||||
|
||||
<span style="color:#0033ff">if</span> (pFramesRead != NULL) {
|
||||
*pFramesRead = 0;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">if</span> (pDataSource == NULL) {
|
||||
<span style="color:#0033ff">return</span> MA_INVALID_ARGS;
|
||||
}
|
||||
|
||||
result = ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0033ff">return</span> result; <span style="color:#009900">/* Failed to retrieve the data format of the data source. */</span>
|
||||
}
|
||||
|
||||
totalFramesRead = 0;
|
||||
<span style="color:#0033ff">while</span> (totalFramesRead < frameCount) {
|
||||
<span style="color:#0033ff">float</span> temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE/<span style="color:#0033ff">sizeof</span>(<span style="color:#0033ff">float</span>)];
|
||||
<span style="color:#0099cc">ma_uint64</span> tempCapInFrames = ma_countof(temp) / channels;
|
||||
<span style="color:#0099cc">ma_uint64</span> framesJustRead;
|
||||
<span style="color:#0099cc">ma_uint64</span> framesToRead = frameCount - totalFramesRead;
|
||||
<span style="color:#0033ff">if</span> (framesToRead > tempCapInFrames) {
|
||||
framesToRead = tempCapInFrames;
|
||||
}
|
||||
|
||||
result = ma_data_source_read_pcm_frames_f32_ex(pDataSource, temp, framesToRead, &framesJustRead, format, channels);
|
||||
|
||||
ma_mix_pcm_frames_f32(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), temp, framesJustRead, channels, volume);
|
||||
totalFramesRead += framesJustRead;
|
||||
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">if</span> (pFramesRead != NULL) {
|
||||
*pFramesRead = totalFramesRead;
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">return</span> MA_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
<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 this example we're just going to play our data sources layered on top of each other. This
|
||||
assumes the device's format is f32 and that the buffer is not pre-silenced.
|
||||
*/</span>
|
||||
<span style="color:#0099cc">ma_uint32</span> iDataSource;
|
||||
|
||||
MA_ASSERT(pDevice->playback.format == ma_format_f32);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pInput; <span style="color:#009900">/* Unused. */</span>
|
||||
|
||||
<span style="color:#009900">/*
|
||||
If the device was configured with noPreSilencedOutputBuffer then you would need to silence the
|
||||
buffer here, or make sure the first data source to be mixed is copied rather than mixed.
|
||||
*/</span>
|
||||
<span style="color:#009900">/*ma_silence_pcm_frames(pOutput, frameCount, ma_format_f32, pDevice->playback.channels);*/</span>
|
||||
|
||||
<span style="color:#009900">/* For each sound, mix as much data as we can. */</span>
|
||||
<span style="color:#0033ff">for</span> (iDataSource = 0; iDataSource < g_dataSourceCount; iDataSource += 1) {
|
||||
ma_data_source_read_pcm_frames_and_mix_f32(&g_dataSources[iDataSource], (<span style="color:#0033ff">float</span>*)pOutput, frameCount, NULL, <span style="color:#009900">/* volume = */</span>1);
|
||||
}
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">static</span> ma_thread_result MA_THREADCALL custom_job_thread(<span style="color:#0033ff">void</span>* pUserData)
|
||||
{
|
||||
ma_resource_manager* pResourceManager = (ma_resource_manager*)pUserData;
|
||||
MA_ASSERT(pResourceManager != NULL);
|
||||
|
||||
<span style="color:#0033ff">for</span> (;;) {
|
||||
<span style="color:#0099cc">ma_result</span> result;
|
||||
ma_resource_manager_job job;
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Retrieve a job from the queue first. This defines what it is you're about to do. By default this will be
|
||||
blocking. You can initialize the resource manager with MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING to not block in
|
||||
which case MA_NO_DATA_AVAILABLE will be returned if no jobs are available.
|
||||
|
||||
When the quit job is returned (MA_RESOURCE_MANAGER_JOB_QUIT), the return value will always be MA_CANCELLED. If you don't want
|
||||
to check the return value (you should), you can instead check if the job code is MA_RESOURCE_MANAGER_JOB_QUIT and use that
|
||||
instead.
|
||||
*/</span>
|
||||
result = ma_resource_manager_next_job(pResourceManager, &job);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0033ff">if</span> (result == MA_CANCELLED) {
|
||||
printf(<span style="color:#cc3300">"CUSTOM JOB THREAD TERMINATING VIA MA_CANCELLED... "</span>);
|
||||
} <span style="color:#0033ff">else</span> {
|
||||
printf(<span style="color:#cc3300">"CUSTOM JOB THREAD ERROR: %s. TERMINATING... "</span>, ma_result_description(result));
|
||||
}
|
||||
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Terminate if we got a quit message. You don't need to terminate like this, but's a bit more robust. You can
|
||||
just use a global variable or something similar if it's easier for your particular situation. The quit job
|
||||
remains in the queue and will continue to be returned by future calls to ma_resource_manager_next_job(). The
|
||||
reason for this is to give every job thread visibility to the quit job so they have a chance to exit.
|
||||
|
||||
We won't actually be hitting this code because the call above will return MA_CANCELLED when the MA_RESOURCE_MANAGER_JOB_QUIT
|
||||
event is received which means the <span style="font-family:monospace;">result != MA_SUCCESS</span> logic above will catch it. If you do not check the
|
||||
return value of ma_resource_manager_next_job() you will want to check for MA_RESOURCE_MANAGER_JOB_QUIT like the code below.
|
||||
*/</span>
|
||||
<span style="color:#0033ff">if</span> (job.toc.breakup.code == MA_RESOURCE_MANAGER_JOB_QUIT) {
|
||||
printf(<span style="color:#cc3300">"CUSTOM JOB THREAD TERMINATING VIA MA_RESOURCE_MANAGER_JOB_QUIT... "</span>);
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Call ma_resource_manager_process_job() to actually do the work to process the job. */</span>
|
||||
printf(<span style="color:#cc3300">"PROCESSING IN CUSTOM JOB THREAD: %d\n"</span>, job.toc.breakup.code);
|
||||
ma_resource_manager_process_job(pResourceManager, &job);
|
||||
}
|
||||
|
||||
printf(<span style="color:#cc3300">"TERMINATED\n"</span>);
|
||||
<span style="color:#0033ff">return</span> (ma_thread_result)0;
|
||||
}
|
||||
|
||||
<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:#0099cc">ma_device</span> device;
|
||||
ma_resource_manager_config resourceManagerConfig;
|
||||
ma_resource_manager resourceManager;
|
||||
<span style="color:#0099cc">ma_thread</span> jobThread;
|
||||
<span style="color:#0033ff">int</span> iFile;
|
||||
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.format = ma_format_f32;
|
||||
deviceConfig.dataCallback = data_callback;
|
||||
deviceConfig.pUserData = NULL;
|
||||
|
||||
result = ma_device_init(NULL, &deviceConfig, &device);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize device."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/* We can start the device before loading any sounds. We'll just end up outputting silence. */</span>
|
||||
result = ma_device_start(&device);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_device_uninit(&device);
|
||||
printf(<span style="color:#cc3300">"Failed to start device."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
|
||||
<span style="color:#009900">/*
|
||||
We have the device so now we want to initialize the resource manager. We'll use the resource manager to load some
|
||||
sounds based on the command line.
|
||||
*/</span>
|
||||
resourceManagerConfig = ma_resource_manager_config_init();
|
||||
|
||||
<span style="color:#009900">/*
|
||||
We'll set a standard decoding format to save us to processing time at mixing time. If you're wanting to use
|
||||
spatialization with your decoded sounds, you may want to consider leaving this as 0 to ensure the file's native
|
||||
channel count is used so you can do proper spatialization.
|
||||
*/</span>
|
||||
resourceManagerConfig.decodedFormat = device.playback.format;
|
||||
resourceManagerConfig.decodedChannels = device.playback.channels;
|
||||
resourceManagerConfig.decodedSampleRate = device.sampleRate;
|
||||
|
||||
<span style="color:#009900">/* The number of job threads to be managed internally. Set this to 0 if you want to self-manage your job threads */</span>
|
||||
resourceManagerConfig.jobThreadCount = 4;
|
||||
|
||||
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
ma_device_uninit(&device);
|
||||
printf(<span style="color:#cc3300">"Failed to initialize the resource manager."</span>);
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Now that we have a resource manager we can set up our custom job thread. This is optional. Normally when doing
|
||||
self-managed job threads you would set the internal job thread count to zero. We're doing both internal and
|
||||
self-managed job threads in this example just for demonstration purposes.
|
||||
*/</span>
|
||||
ma_thread_create(&jobThread, ma_thread_priority_default, 0, custom_job_thread, &resourceManager, NULL);
|
||||
|
||||
<span style="color:#009900">/* Create each data source from the resource manager. Note that the caller is the owner. */</span>
|
||||
<span style="color:#0033ff">for</span> (iFile = 0; iFile < ma_countof(g_dataSources) && iFile < argc-1; iFile += 1) {
|
||||
result = ma_resource_manager_data_source_init(
|
||||
&resourceManager,
|
||||
argv[iFile+1],
|
||||
MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC <span style="color:#009900">/*| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM*/</span>,
|
||||
NULL, <span style="color:#009900">/* Async notification. */</span>
|
||||
&g_dataSources[iFile]);
|
||||
|
||||
<span style="color:#0033ff">if</span> (result != MA_SUCCESS) {
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/* Use looping in this example. */</span>
|
||||
ma_data_source_set_looping(&g_dataSources[iFile], MA_TRUE);
|
||||
|
||||
g_dataSourceCount += 1;
|
||||
}
|
||||
|
||||
printf(<span style="color:#cc3300">"Press Enter to quit..."</span>);
|
||||
getchar();
|
||||
|
||||
|
||||
<span style="color:#009900">/* Teardown. */</span>
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Uninitialize the device first to ensure the data callback is stopped and doesn't try to access
|
||||
any data.
|
||||
*/</span>
|
||||
ma_device_uninit(&device);
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Our data sources need to be explicitly uninitialized. ma_resource_manager_uninit() will not do
|
||||
it for us. This needs to be done before posting the quit event and uninitializing the resource
|
||||
manager or else we'll get stuck in a deadlock because ma_resource_manager_data_source_uninit()
|
||||
will be waiting for the job thread(s) to finish work, which will never happen because they were
|
||||
just terminated.
|
||||
*/</span>
|
||||
<span style="color:#0033ff">for</span> (iFile = 0; (size_t)iFile < g_dataSourceCount; iFile += 1) {
|
||||
ma_resource_manager_data_source_uninit(&g_dataSources[iFile]);
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
Before uninitializing the resource manager we need to make sure a quit event has been posted to
|
||||
ensure we can get out of our custom thread. The call to ma_resource_manager_uninit() will also
|
||||
do this, but we need to call it explicitly so that our self-managed thread can exit naturally.
|
||||
You only need to post a quit job if you're using that as the exit indicator. You can instead
|
||||
use whatever variable you want to terminate your job thread, but since this example is using a
|
||||
quit job we need to post one. Note that you don't need to do this if you're not managing your
|
||||
own threads - ma_resource_manager_uninit() alone will suffice in that case.
|
||||
*/</span>
|
||||
ma_resource_manager_post_job_quit(&resourceManager);
|
||||
ma_thread_wait(&jobThread); <span style="color:#009900">/* Wait for the custom job thread to finish so it doesn't try to access any data. */</span>
|
||||
|
||||
<span style="color:#009900">/* Uninitialize the resource manager after each data source. */</span>
|
||||
ma_resource_manager_uninit(&resourceManager);
|
||||
|
||||
<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://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 © 2021 David Reid<br/>
|
||||
Developed by David Reid - <a class="footer-link" href="mailto:mackron@gmail.com">mackron@gmail.com</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</a><a href="simple_capture.html" class="doc-navigation doc-navigation-l1 doc-navigation-active">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="../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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Simple Capture</h1><p>
|
||||
Demonstrates how to capture data from a microphone using the low-level API.
|
||||
</p>
|
||||
@@ -271,7 +271,7 @@ data received by the microphone straight to a WAV file.</p>
|
||||
<span style="color:#0099cc">ma_encoder</span>* pEncoder = (<span style="color:#0099cc">ma_encoder</span>*)pDevice->pUserData;
|
||||
MA_ASSERT(pEncoder != NULL);
|
||||
|
||||
ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount);
|
||||
ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount, NULL);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pOutput;
|
||||
}
|
||||
@@ -289,7 +289,7 @@ data received by the microphone straight to a WAV file.</p>
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
encoderConfig = ma_encoder_config_init(ma_resource_format_wav, ma_format_f32, 2, 44100);
|
||||
encoderConfig = ma_encoder_config_init(ma_encoding_format_wav, ma_format_f32, 2, 44100);
|
||||
|
||||
<span style="color:#0033ff">if</span> (ma_encoder_init_file(argv[1], &encoderConfig, &encoder) != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize output file.\n"</span>);
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Simple Duplex</h1><p>
|
||||
Demonstrates duplex mode which is where data is captured from a microphone and then output to a speaker device.
|
||||
</p>
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Simple Enumeration</h1><p>
|
||||
Demonstrates how to enumerate over devices.
|
||||
</p>
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Simple Loopback</h1><p>
|
||||
Demonstrates how to implement loopback recording.
|
||||
</p>
|
||||
@@ -275,7 +275,7 @@ properties. The output buffer in the callback will be null whereas the input buf
|
||||
<span style="color:#0099cc">ma_encoder</span>* pEncoder = (<span style="color:#0099cc">ma_encoder</span>*)pDevice->pUserData;
|
||||
MA_ASSERT(pEncoder != NULL);
|
||||
|
||||
ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount);
|
||||
ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount, NULL);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pOutput;
|
||||
}
|
||||
@@ -298,7 +298,7 @@ properties. The output buffer in the callback will be null whereas the input buf
|
||||
<span style="color:#0033ff">return</span> -1;
|
||||
}
|
||||
|
||||
encoderConfig = ma_encoder_config_init(ma_resource_format_wav, ma_format_f32, 2, 44100);
|
||||
encoderConfig = ma_encoder_config_init(ma_encoding_format_wav, ma_format_f32, 2, 44100);
|
||||
|
||||
<span style="color:#0033ff">if</span> (ma_encoder_init_file(argv[1], &encoderConfig, &encoder) != MA_SUCCESS) {
|
||||
printf(<span style="color:#cc3300">"Failed to initialize output file.\n"</span>);
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Simple Looping</h1><p>
|
||||
Shows one way to handle looping of a sound.
|
||||
</p>
|
||||
@@ -262,18 +262,13 @@ decoder straight into <span style="font-family:monospace;">ma_data_source_read_p
|
||||
|
||||
<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:#0099cc">ma_bool32</span> isLooping = MA_TRUE;
|
||||
|
||||
<span style="color:#0099cc">ma_decoder</span>* pDecoder = (<span style="color:#0099cc">ma_decoder</span>*)pDevice->pUserData;
|
||||
<span style="color:#0033ff">if</span> (pDecoder == NULL) {
|
||||
<span style="color:#0033ff">return</span>;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
A decoder is a data source which means you can seemlessly plug it into the ma_data_source API. We can therefore take advantage
|
||||
of the "loop" parameter of ma_data_source_read_pcm_frames() to handle looping for us.
|
||||
*/</span>
|
||||
ma_data_source_read_pcm_frames(pDecoder, pOutput, frameCount, NULL, isLooping);
|
||||
<span style="color:#009900">/* Reading PCM frames will loop based on what we specified when called ma_data_source_set_looping(). */</span>
|
||||
ma_data_source_read_pcm_frames(pDecoder, pOutput, frameCount, NULL);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pInput;
|
||||
}
|
||||
@@ -295,6 +290,12 @@ decoder straight into <span style="font-family:monospace;">ma_data_source_read_p
|
||||
<span style="color:#0033ff">return</span> -2;
|
||||
}
|
||||
|
||||
<span style="color:#009900">/*
|
||||
A decoder is a data source which means we just use ma_data_source_set_looping() to set the
|
||||
looping state. We will read data using ma_data_source_read_pcm_frames() in the data callback.
|
||||
*/</span>
|
||||
ma_data_source_set_looping(&decoder, MA_TRUE);
|
||||
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.format = decoder.outputFormat;
|
||||
deviceConfig.playback.channels = decoder.outputChannels;
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">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="../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>Simple Mixing</h1><p>
|
||||
Demonstrates one way to load multiple files and play them all back at the same time.
|
||||
</p>
|
||||
@@ -313,7 +313,7 @@ For simplicity, this example requires the device to use floating point samples.
|
||||
framesToReadThisIteration = totalFramesRemaining;
|
||||
}
|
||||
|
||||
framesReadThisIteration = (<span style="color:#0099cc">ma_uint32</span>)ma_decoder_read_pcm_frames(pDecoder, temp, framesToReadThisIteration);
|
||||
framesReadThisIteration = (<span style="color:#0099cc">ma_uint32</span>)ma_decoder_read_pcm_frames(pDecoder, temp, framesToReadThisIteration, NULL);
|
||||
<span style="color:#0033ff">if</span> (framesReadThisIteration == 0) {
|
||||
<span style="color:#0033ff">break</span>;
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">Simple Playback</a><a href="simple_playback_sine.html" class="doc-navigation doc-navigation-l1 ">Simple Playback Sine</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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">Simple Playback</a><a href="simple_playback_sine.html" class="doc-navigation doc-navigation-l1 ">Simple Playback Sine</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>Simple Playback</h1><p>
|
||||
Demonstrates how to load a sound file and play it back using the low-level API.
|
||||
</p>
|
||||
@@ -274,7 +274,7 @@ the simple_mixing example for how best to do this.</p>
|
||||
<span style="color:#0033ff">return</span>;
|
||||
}
|
||||
|
||||
ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount);
|
||||
ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, NULL);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pInput;
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ a.doc-navigation-l4 {
|
||||
<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="data_source_chaining.html" class="doc-navigation doc-navigation-l1 ">Data Source Chaining</a><a href="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">Simple Playback Sine</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;">
|
||||
<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="fixed_size_callback.html" class="doc-navigation doc-navigation-l1 ">Fixed Size Callback</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 doc-navigation-active">Simple Playback Sine</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>Simple Playback Sine</h1><p>
|
||||
Demonstrates playback of a sine wave.
|
||||
</p>
|
||||
@@ -296,7 +296,7 @@ This example works with Emscripten.</p>
|
||||
pSineWave = (<span style="color:#0099cc">ma_waveform</span>*)pDevice->pUserData;
|
||||
MA_ASSERT(pSineWave != NULL);
|
||||
|
||||
ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount);
|
||||
ma_waveform_read_pcm_frames(pSineWave, pOutput, frameCount, NULL);
|
||||
|
||||
(<span style="color:#0033ff">void</span>)pInput; <span style="color:#009900">/* Unused. */</span>
|
||||
}
|
||||
|
||||
+3218
-416
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 832 B After Width: | Height: | Size: 1.2 KiB |
Reference in New Issue
Block a user