Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
miniaudio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
miniaudio
Commits
a70515a9
Commit
a70515a9
authored
Jun 30, 2021
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add example for using custom decoders with the resource manager.
parent
9ed296b3
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
252 additions
and
0 deletions
+252
-0
research/_examples/custom_decoder_engine.c
research/_examples/custom_decoder_engine.c
+252
-0
No files found.
research/_examples/custom_decoder_engine.c
0 → 100644
View file @
a70515a9
/*
Demonstrates how to implement a custom decoder.
This example implements two custom decoders:
* Vorbis via libvorbis
* Opus via libopus
A custom decoder must implement a data source. In this example, the libvorbis data source is called
`ma_libvorbis` and the Opus data source is called `ma_libopus`. These two objects are compatible
with the `ma_data_source` APIs and can be taken straight from this example and used in real code.
The custom decoding data sources (`ma_libvorbis` and `ma_libopus` in this example) are connected to
the decoder via the decoder config (`ma_decoder_config`). You need to implement a vtable for each
of your custom decoders. See `ma_decoding_backend_vtable` for the functions you need to implement.
The `onInitFile`, `onInitFileW` and `onInitMemory` functions are optional.
*/
#define MA_NO_VORBIS
/* Disable the built-in Vorbis decoder to ensure the libvorbis decoder is picked. */
#define MA_NO_OPUS
/* Disable the (not yet implemented) built-in Opus decoder to ensure the libopus decoder is picked. */
#define MINIAUDIO_IMPLEMENTATION
#include "../../miniaudio.h"
#include "../../extras/miniaudio_libvorbis.h"
#include "../../extras/miniaudio_libopus.h"
#include "../miniaudio_engine.h"
#include <stdio.h>
static
ma_result
ma_decoding_backend_init__libvorbis
(
void
*
pUserData
,
ma_read_proc
onRead
,
ma_seek_proc
onSeek
,
ma_tell_proc
onTell
,
void
*
pReadSeekTellUserData
,
const
ma_decoding_backend_config
*
pConfig
,
const
ma_allocation_callbacks
*
pAllocationCallbacks
,
ma_data_source
**
ppBackend
)
{
ma_result
result
;
ma_libvorbis
*
pVorbis
;
(
void
)
pUserData
;
pVorbis
=
(
ma_libvorbis
*
)
ma_malloc
(
sizeof
(
*
pVorbis
),
pAllocationCallbacks
);
if
(
pVorbis
==
NULL
)
{
return
MA_OUT_OF_MEMORY
;
}
result
=
ma_libvorbis_init
(
onRead
,
onSeek
,
onTell
,
pReadSeekTellUserData
,
pConfig
,
pAllocationCallbacks
,
pVorbis
);
if
(
result
!=
MA_SUCCESS
)
{
return
result
;
}
*
ppBackend
=
pVorbis
;
return
MA_SUCCESS
;
}
static
ma_result
ma_decoding_backend_init_file__libvorbis
(
void
*
pUserData
,
const
char
*
pFilePath
,
const
ma_decoding_backend_config
*
pConfig
,
const
ma_allocation_callbacks
*
pAllocationCallbacks
,
ma_data_source
**
ppBackend
)
{
ma_result
result
;
ma_libvorbis
*
pVorbis
;
(
void
)
pUserData
;
pVorbis
=
(
ma_libvorbis
*
)
ma_malloc
(
sizeof
(
*
pVorbis
),
pAllocationCallbacks
);
if
(
pVorbis
==
NULL
)
{
return
MA_OUT_OF_MEMORY
;
}
result
=
ma_libvorbis_init_file
(
pFilePath
,
pConfig
,
pAllocationCallbacks
,
pVorbis
);
if
(
result
!=
MA_SUCCESS
)
{
return
result
;
}
*
ppBackend
=
pVorbis
;
return
MA_SUCCESS
;
}
static
void
ma_decoding_backend_uninit__libvorbis
(
void
*
pUserData
,
ma_data_source
*
pBackend
,
const
ma_allocation_callbacks
*
pAllocationCallbacks
)
{
ma_libvorbis
*
pVorbis
=
(
ma_libvorbis
*
)
pBackend
;
(
void
)
pUserData
;
ma_libvorbis_uninit
(
pVorbis
,
pAllocationCallbacks
);
ma_free
(
pVorbis
,
pAllocationCallbacks
);
}
static
ma_result
ma_decoding_backend_get_channel_map__libvorbis
(
void
*
pUserData
,
ma_data_source
*
pBackend
,
ma_channel
*
pChannelMap
,
size_t
channelMapCap
)
{
ma_libvorbis
*
pVorbis
=
(
ma_libvorbis
*
)
pBackend
;
(
void
)
pUserData
;
return
ma_libvorbis_get_data_format
(
pVorbis
,
NULL
,
NULL
,
NULL
,
pChannelMap
,
channelMapCap
);
}
static
ma_decoding_backend_vtable
g_ma_decoding_backend_vtable_libvorbis
=
{
ma_decoding_backend_init__libvorbis
,
ma_decoding_backend_init_file__libvorbis
,
NULL
,
/* onInitFileW() */
NULL
,
/* onInitMemory() */
ma_decoding_backend_uninit__libvorbis
,
ma_decoding_backend_get_channel_map__libvorbis
};
static
ma_result
ma_decoding_backend_init__libopus
(
void
*
pUserData
,
ma_read_proc
onRead
,
ma_seek_proc
onSeek
,
ma_tell_proc
onTell
,
void
*
pReadSeekTellUserData
,
const
ma_decoding_backend_config
*
pConfig
,
const
ma_allocation_callbacks
*
pAllocationCallbacks
,
ma_data_source
**
ppBackend
)
{
ma_result
result
;
ma_libopus
*
pOpus
;
(
void
)
pUserData
;
pOpus
=
(
ma_libopus
*
)
ma_malloc
(
sizeof
(
*
pOpus
),
pAllocationCallbacks
);
if
(
pOpus
==
NULL
)
{
return
MA_OUT_OF_MEMORY
;
}
result
=
ma_libopus_init
(
onRead
,
onSeek
,
onTell
,
pReadSeekTellUserData
,
pConfig
,
pAllocationCallbacks
,
pOpus
);
if
(
result
!=
MA_SUCCESS
)
{
return
result
;
}
*
ppBackend
=
pOpus
;
return
MA_SUCCESS
;
}
static
ma_result
ma_decoding_backend_init_file__libopus
(
void
*
pUserData
,
const
char
*
pFilePath
,
const
ma_decoding_backend_config
*
pConfig
,
const
ma_allocation_callbacks
*
pAllocationCallbacks
,
ma_data_source
**
ppBackend
)
{
ma_result
result
;
ma_libopus
*
pOpus
;
(
void
)
pUserData
;
pOpus
=
(
ma_libopus
*
)
ma_malloc
(
sizeof
(
*
pOpus
),
pAllocationCallbacks
);
if
(
pOpus
==
NULL
)
{
return
MA_OUT_OF_MEMORY
;
}
result
=
ma_libopus_init_file
(
pFilePath
,
pConfig
,
pAllocationCallbacks
,
pOpus
);
if
(
result
!=
MA_SUCCESS
)
{
return
result
;
}
*
ppBackend
=
pOpus
;
return
MA_SUCCESS
;
}
static
void
ma_decoding_backend_uninit__libopus
(
void
*
pUserData
,
ma_data_source
*
pBackend
,
const
ma_allocation_callbacks
*
pAllocationCallbacks
)
{
ma_libopus
*
pOpus
=
(
ma_libopus
*
)
pBackend
;
(
void
)
pUserData
;
ma_libopus_uninit
(
pOpus
,
pAllocationCallbacks
);
ma_free
(
pOpus
,
pAllocationCallbacks
);
}
static
ma_result
ma_decoding_backend_get_channel_map__libopus
(
void
*
pUserData
,
ma_data_source
*
pBackend
,
ma_channel
*
pChannelMap
,
size_t
channelMapCap
)
{
ma_libopus
*
pOpus
=
(
ma_libopus
*
)
pBackend
;
(
void
)
pUserData
;
return
ma_libopus_get_data_format
(
pOpus
,
NULL
,
NULL
,
NULL
,
pChannelMap
,
channelMapCap
);
}
static
ma_decoding_backend_vtable
g_ma_decoding_backend_vtable_libopus
=
{
ma_decoding_backend_init__libopus
,
ma_decoding_backend_init_file__libopus
,
NULL
,
/* onInitFileW() */
NULL
,
/* onInitMemory() */
ma_decoding_backend_uninit__libopus
,
ma_decoding_backend_get_channel_map__libopus
};
void
data_callback
(
ma_device
*
pDevice
,
void
*
pOutput
,
const
void
*
pInput
,
ma_uint32
frameCount
)
{
ma_data_source
*
pDataSource
=
(
ma_data_source
*
)
pDevice
->
pUserData
;
if
(
pDataSource
==
NULL
)
{
return
;
}
ma_data_source_read_pcm_frames
(
pDataSource
,
pOutput
,
frameCount
,
NULL
,
MA_TRUE
);
(
void
)
pInput
;
}
int
main
(
int
argc
,
char
**
argv
)
{
ma_result
result
;
ma_resource_manager_config
resourceManagerConfig
;
ma_resource_manager
resourceManager
;
ma_engine_config
engineConfig
;
ma_engine
engine
;
/*
Add your custom backend vtables here. The order in the array defines the order of priority. The
vtables will be passed in via the decoder config.
*/
ma_decoding_backend_vtable
*
pCustomBackendVTables
[]
=
{
&
g_ma_decoding_backend_vtable_libvorbis
,
&
g_ma_decoding_backend_vtable_libopus
};
if
(
argc
<
2
)
{
printf
(
"No input file.
\n
"
);
return
-
1
;
}
/* Using custom decoding backends requires a resource manager. */
resourceManagerConfig
=
ma_resource_manager_config_init
();
resourceManagerConfig
.
ppCustomDecodingBackendVTables
=
pCustomBackendVTables
;
resourceManagerConfig
.
customDecodingBackendVTableCount
=
sizeof
(
pCustomBackendVTables
)
/
sizeof
(
pCustomBackendVTables
[
0
]);
resourceManagerConfig
.
pCustomDecodingBackendUserData
=
NULL
;
/* <-- This will be passed in to the pUserData parameter of each function in the decoding backend vtables. */
result
=
ma_resource_manager_init
(
&
resourceManagerConfig
,
&
resourceManager
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize resource manager."
);
return
-
1
;
}
/* Once we have a resource manager we can create the engine. */
engineConfig
=
ma_engine_config_init
();
engineConfig
.
pResourceManager
=
&
resourceManager
;
result
=
ma_engine_init
(
&
engineConfig
,
&
engine
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to initialize engine."
);
return
-
1
;
}
/* Now we can start our sound. */
result
=
ma_engine_play_sound
(
&
engine
,
argv
[
1
],
NULL
);
if
(
result
!=
MA_SUCCESS
)
{
printf
(
"Failed to play sound."
);
return
-
1
;
}
printf
(
"Press Enter to quit..."
);
getchar
();
return
0
;
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment