pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c
Go to the documentation of this file.
1 /*
2 Demonstrates how to implement a custom decoder.
3 
4 This example implements two custom decoders:
5 
6  * Vorbis via libvorbis
7  * Opus via libopus
8 
9 A custom decoder must implement a data source. In this example, the libvorbis data source is called
10 `ma_libvorbis` and the Opus data source is called `ma_libopus`. These two objects are compatible
11 with the `ma_data_source` APIs and can be taken straight from this example and used in real code.
12 
13 The custom decoding data sources (`ma_libvorbis` and `ma_libopus` in this example) are connected to
14 the decoder via the decoder config (`ma_decoder_config`). You need to implement a vtable for each
15 of your custom decoders. See `ma_decoding_backend_vtable` for the functions you need to implement.
16 The `onInitFile`, `onInitFileW` and `onInitMemory` functions are optional.
17 */
18 #define MA_NO_VORBIS /* Disable the built-in Vorbis decoder to ensure the libvorbis decoder is picked. */
19 #define MA_NO_OPUS /* Disable the (not yet implemented) built-in Opus decoder to ensure the libopus decoder is picked. */
20 #define MINIAUDIO_IMPLEMENTATION
21 #include "../../miniaudio.h"
22 #include "../../extras/miniaudio_libvorbis.h"
23 #include "../../extras/miniaudio_libopus.h"
24 #include "../miniaudio_engine.h"
25 
26 #include <stdio.h>
27 
28 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)
29 {
30  ma_result result;
31  ma_libvorbis* pVorbis;
32 
33  (void)pUserData;
34 
35  pVorbis = (ma_libvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks);
36  if (pVorbis == NULL) {
37  return MA_OUT_OF_MEMORY;
38  }
39 
40  result = ma_libvorbis_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pVorbis);
41  if (result != MA_SUCCESS) {
42  ma_free(pVorbis, pAllocationCallbacks);
43  return result;
44  }
45 
46  *ppBackend = pVorbis;
47 
48  return MA_SUCCESS;
49 }
50 
51 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)
52 {
53  ma_result result;
54  ma_libvorbis* pVorbis;
55 
56  (void)pUserData;
57 
58  pVorbis = (ma_libvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks);
59  if (pVorbis == NULL) {
60  return MA_OUT_OF_MEMORY;
61  }
62 
63  result = ma_libvorbis_init_file(pFilePath, pConfig, pAllocationCallbacks, pVorbis);
64  if (result != MA_SUCCESS) {
65  ma_free(pVorbis, pAllocationCallbacks);
66  return result;
67  }
68 
69  *ppBackend = pVorbis;
70 
71  return MA_SUCCESS;
72 }
73 
74 static void ma_decoding_backend_uninit__libvorbis(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
75 {
76  ma_libvorbis* pVorbis = (ma_libvorbis*)pBackend;
77 
78  (void)pUserData;
79 
80  ma_libvorbis_uninit(pVorbis, pAllocationCallbacks);
81  ma_free(pVorbis, pAllocationCallbacks);
82 }
83 
84 static ma_result ma_decoding_backend_get_channel_map__libvorbis(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap)
85 {
86  ma_libvorbis* pVorbis = (ma_libvorbis*)pBackend;
87 
88  (void)pUserData;
89 
90  return ma_libvorbis_get_data_format(pVorbis, NULL, NULL, NULL, pChannelMap, channelMapCap);
91 }
92 
94 {
97  NULL, /* onInitFileW() */
98  NULL, /* onInitMemory() */
101 };
102 
103 
104 
105 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)
106 {
107  ma_result result;
108  ma_libopus* pOpus;
109 
110  (void)pUserData;
111 
112  pOpus = (ma_libopus*)ma_malloc(sizeof(*pOpus), pAllocationCallbacks);
113  if (pOpus == NULL) {
114  return MA_OUT_OF_MEMORY;
115  }
116 
117  result = ma_libopus_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pOpus);
118  if (result != MA_SUCCESS) {
119  ma_free(pOpus, pAllocationCallbacks);
120  return result;
121  }
122 
123  *ppBackend = pOpus;
124 
125  return MA_SUCCESS;
126 }
127 
128 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)
129 {
130  ma_result result;
131  ma_libopus* pOpus;
132 
133  (void)pUserData;
134 
135  pOpus = (ma_libopus*)ma_malloc(sizeof(*pOpus), pAllocationCallbacks);
136  if (pOpus == NULL) {
137  return MA_OUT_OF_MEMORY;
138  }
139 
140  result = ma_libopus_init_file(pFilePath, pConfig, pAllocationCallbacks, pOpus);
141  if (result != MA_SUCCESS) {
142  ma_free(pOpus, pAllocationCallbacks);
143  return result;
144  }
145 
146  *ppBackend = pOpus;
147 
148  return MA_SUCCESS;
149 }
150 
151 static void ma_decoding_backend_uninit__libopus(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks)
152 {
153  ma_libopus* pOpus = (ma_libopus*)pBackend;
154 
155  (void)pUserData;
156 
157  ma_libopus_uninit(pOpus, pAllocationCallbacks);
158  ma_free(pOpus, pAllocationCallbacks);
159 }
160 
161 static ma_result ma_decoding_backend_get_channel_map__libopus(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap)
162 {
163  ma_libopus* pOpus = (ma_libopus*)pBackend;
164 
165  (void)pUserData;
166 
167  return ma_libopus_get_data_format(pOpus, NULL, NULL, NULL, pChannelMap, channelMapCap);
168 }
169 
171 {
174  NULL, /* onInitFileW() */
175  NULL, /* onInitMemory() */
178 };
179 
180 
181 
182 
183 void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
184 {
185  ma_data_source* pDataSource = (ma_data_source*)pDevice->pUserData;
186  if (pDataSource == NULL) {
187  return;
188  }
189 
190  ma_data_source_read_pcm_frames(pDataSource, pOutput, frameCount, NULL, MA_TRUE);
191 
192  (void)pInput;
193 }
194 
195 int main(int argc, char** argv)
196 {
197  ma_result result;
198  ma_resource_manager_config resourceManagerConfig;
199  ma_resource_manager resourceManager;
200  ma_engine_config engineConfig;
201  ma_engine engine;
202 
203  /*
204  Add your custom backend vtables here. The order in the array defines the order of priority. The
205  vtables will be passed in to the resource manager config.
206  */
207  ma_decoding_backend_vtable* pCustomBackendVTables[] =
208  {
211  };
212 
213 
214  if (argc < 2) {
215  printf("No input file.\n");
216  return -1;
217  }
218 
219 
220  /* Using custom decoding backends requires a resource manager. */
221  resourceManagerConfig = ma_resource_manager_config_init();
222  resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables;
223  resourceManagerConfig.customDecodingBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]);
224  resourceManagerConfig.pCustomDecodingBackendUserData = NULL; /* <-- This will be passed in to the pUserData parameter of each function in the decoding backend vtables. */
225 
226  result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
227  if (result != MA_SUCCESS) {
228  printf("Failed to initialize resource manager.");
229  return -1;
230  }
231 
232 
233  /* Once we have a resource manager we can create the engine. */
234  engineConfig = ma_engine_config_init();
235  engineConfig.pResourceManager = &resourceManager;
236 
237  result = ma_engine_init(&engineConfig, &engine);
238  if (result != MA_SUCCESS) {
239  printf("Failed to initialize engine.");
240  return -1;
241  }
242 
243 
244  /* Now we can play our sound. */
245  result = ma_engine_play_sound(&engine, argv[1], NULL);
246  if (result != MA_SUCCESS) {
247  printf("Failed to play sound.");
248  return -1;
249  }
250 
251 
252  printf("Press Enter to quit...");
253  getchar();
254 
255  return 0;
256 }
ma_libopus_init
MA_API ma_result ma_libopus_init(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_libopus *pOpus)
ma_engine_init
MA_API ma_result ma_engine_init(const ma_engine_config *pConfig, ma_engine *pEngine)
ma_tell_proc
ma_result(* ma_tell_proc)(void *pUserData, ma_int64 *pCursor)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:4682
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:92
ma_decoding_backend_vtable
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:4723
ma_libvorbis_get_data_format
MA_API ma_result ma_libvorbis_get_data_format(ma_libvorbis *pVorbis, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate, ma_channel *pChannelMap, size_t channelMapCap)
ma_engine_config_init
MA_API ma_engine_config ma_engine_config_init(void)
ma_decoding_backend_init__libvorbis
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)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:28
ma_data_source_read_pcm_frames
MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source *pDataSource, void *pFramesOut, ma_uint64 frameCount, ma_uint64 *pFramesRead, ma_bool32 loop)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37348
ma_libvorbis
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_libvorbis.h:21
ma_resource_manager_config::customDecodingBackendCount
ma_uint32 customDecodingBackendCount
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1522
g_ma_decoding_backend_vtable_libvorbis
static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_libvorbis
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:93
ma_engine
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1968
ma_data_source
void ma_data_source
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:4500
ma_decoding_backend_config
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:4715
ma_allocation_callbacks
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1823
ma_resource_manager_config::pCustomDecodingBackendUserData
void * pCustomDecodingBackendUserData
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1523
ma_libvorbis_init_file
MA_API ma_result ma_libvorbis_init_file(const char *pFilePath, const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks, ma_libvorbis *pVorbis)
ma_libvorbis_init
MA_API ma_result ma_libvorbis_init(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_libvorbis *pVorbis)
ma_result
int ma_result
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1658
ma_libopus_uninit
MA_API void ma_libopus_uninit(ma_libopus *pOpus, const ma_allocation_callbacks *pAllocationCallbacks)
ma_decoding_backend_init_file__libopus
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)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:128
ma_libopus
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_libopus.h:20
ma_resource_manager_init
MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config *pConfig, ma_resource_manager *pResourceManager)
ma_decoding_backend_init__libopus
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)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:105
ma_resource_manager_config
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1511
ma_device::pUserData
void * pUserData
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3592
main
int main(int argc, char **argv)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:195
ma_libopus_init_file
MA_API ma_result ma_libopus_init_file(const char *pFilePath, const ma_decoding_backend_config *pConfig, const ma_allocation_callbacks *pAllocationCallbacks, ma_libopus *pOpus)
ma_libopus_get_data_format
MA_API ma_result ma_libopus_get_data_format(ma_libopus *pOpus, ma_format *pFormat, ma_uint32 *pChannels, ma_uint32 *pSampleRate, ma_channel *pChannelMap, size_t channelMapCap)
ma_decoding_backend_get_channel_map__libvorbis
static ma_result ma_decoding_backend_get_channel_map__libvorbis(void *pUserData, ma_data_source *pBackend, ma_channel *pChannelMap, size_t channelMapCap)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:84
ma_resource_manager
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1528
ma_read_proc
ma_result(* ma_read_proc)(void *pUserData, void *pBufferOut, size_t bytesToRead, size_t *pBytesRead)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:4680
ma_resource_manager_config_init
MA_API ma_resource_manager_config ma_resource_manager_config_init(void)
ma_uint32
uint32_t ma_uint32
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1503
ma_engine_config::pResourceManager
ma_resource_manager * pResourceManager
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1948
ma_decoding_backend_get_channel_map__libopus
static ma_result ma_decoding_backend_get_channel_map__libopus(void *pUserData, ma_data_source *pBackend, ma_channel *pChannelMap, size_t channelMapCap)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:161
g_ma_decoding_backend_vtable_libopus
static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_libopus
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:170
ma_seek_proc
ma_result(* ma_seek_proc)(void *pUserData, ma_int64 offset, ma_seek_origin origin)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.h:4681
ma_resource_manager_config::ppCustomDecodingBackendVTables
ma_decoding_backend_vtable ** ppCustomDecodingBackendVTables
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1521
data_callback
void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:183
ma_decoding_backend_uninit__libopus
static void ma_decoding_backend_uninit__libopus(void *pUserData, ma_data_source *pBackend, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:151
ma_libvorbis_uninit
MA_API void ma_libvorbis_uninit(ma_libvorbis *pVorbis, const ma_allocation_callbacks *pAllocationCallbacks)
python.test_porcupine.argv
argv
Definition: test_porcupine.py:158
ma_device
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:3584
ma_engine_play_sound
MA_API ma_result ma_engine_play_sound(ma_engine *pEngine, const char *pFilePath, ma_sound_group *pGroup)
MA_TRUE
#define MA_TRUE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1530
MA_SUCCESS
#define MA_SUCCESS
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1659
ma_decoding_backend_init_file__libvorbis
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)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:51
ma_engine_config
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/research/miniaudio_engine.h:1946
ma_malloc
void * ma_malloc(size_t sz, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37117
ma_channel
ma_uint8 ma_channel
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1600
ma_free
void ma_free(void *p, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: porcupine/demo/c/pvrecorder/src/miniaudio/extras/miniaudio_split/miniaudio.c:37139
ma_decoding_backend_uninit__libvorbis
static void ma_decoding_backend_uninit__libvorbis(void *pUserData, ma_data_source *pBackend, const ma_allocation_callbacks *pAllocationCallbacks)
Definition: pvrecorder/src/miniaudio/research/_examples/custom_decoder_engine.c:74
MA_OUT_OF_MEMORY
#define MA_OUT_OF_MEMORY
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/miniaudio.h:1663


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:13:48