1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
|
package miniaudio
import "core:c"
foreign import lib { LIB }
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
DATA CONVERSION
===============
This section contains the APIs for data conversion. You will find everything here for channel mapping, sample format conversion, resampling, etc.
*************************************************************************************************************************************************************
************************************************************************************************************************************************************/
/**************************************************************************************************************************************************************
Resampling
**************************************************************************************************************************************************************/
linear_resampler_config :: struct {
format: format,
channels: u32,
sampleRateIn: u32,
sampleRateOut: u32,
lpfOrder: u32, /* The low-pass filter order. Setting this to 0 will disable low-pass filtering. */
lpfNyquistFactor: f64, /* 0..1. Defaults to 1. 1 = Half the sampling frequency (Nyquist Frequency), 0.5 = Quarter the sampling frequency (half Nyquest Frequency), etc. */
}
linear_resampler :: struct {
config: linear_resampler_config,
inAdvanceInt: u32,
inAdvanceFrac: u32,
inTimeInt: u32,
inTimeFrac: u32,
x0: struct #raw_union {
f32: [^]f32,
s16: [^]i16,
}, /* The previous input frame. */
x1: struct #raw_union {
f32: [^]f32,
s16: [^]i16,
}, /* The next input frame. */
lpf: lpf,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
resampling_backend :: struct {}
resampling_backend_vtable :: struct {
onGetHeapSize: proc "c" (pUserData: rawptr, pConfig: ^resampler_config, pHeapSizeInBytes: ^c.size_t) -> result,
onInit: proc "c" (pUserData: rawptr, pConfig: ^resampler_config, pHeap: rawptr, ppBackend: ^^resampling_backend) -> result,
onUninit: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, pAllocationCallbacks: ^allocation_callbacks),
onProcess: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result,
onSetRate: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, sampleRateIn: u32, sampleRateOut: u32) -> result, /* Optional. Rate changes will be disabled. */
onGetInputLatency: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> u64, /* Optional. Latency will be reported as 0. */
onGetOutputLatency: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> u64, /* Optional. Latency will be reported as 0. */
onGetRequiredInputFrameCount: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, outputFrameCount: u64, pInputFrameCount: ^u64) -> result, /* Optional. Latency mitigation will be disabled. */
onGetExpectedOutputFrameCount: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result, /* Optional. Latency mitigation will be disabled. */
onReset: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> result,
}
resample_algorithm :: enum c.int {
linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */
custom,
}
resampler_config :: struct {
format: format, /* Must be either ma_format_f32 or ma_format_s16. */
channels: u32,
sampleRateIn: u32,
sampleRateOut: u32,
algorithm: resample_algorithm, /* When set to ma_resample_algorithm_custom, pBackendVTable will be used. */
pBackendVTable: ^resampling_backend_vtable,
pBackendUserData: rawptr,
linear: struct {
lpfOrder: u32,
},
}
resampler :: struct {
pBackend: ^resampling_backend,
pBackendVTable: ^resampling_backend_vtable,
pBackendUserData: rawptr,
format: format,
channels: u32,
sampleRateIn: u32,
sampleRateOut: u32,
state: struct #raw_union {
linear: linear_resampler,
}, /* State for stock resamplers so we can avoid a malloc. For stock resamplers, pBackend will point here. */
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
linear_resampler_config_init :: proc(format: format, channels: u32, sampleRateIn, sampleRateOut: u32) -> linear_resampler_config ---
linear_resampler_get_heap_size :: proc(pConfig: ^linear_resampler_config, pHeapSizeInBytes: ^c.size_t) -> result ---
linear_resampler_init_preallocated :: proc(pConfig: ^linear_resampler_config, pHeap: rawptr, pResampler: ^linear_resampler) -> result ---
linear_resampler_init :: proc(pConfig: ^linear_resampler_config, pAllocationCallbacks: ^allocation_callbacks, pResampler: ^linear_resampler) -> result ---
linear_resampler_uninit :: proc(pResampler: ^linear_resampler, pAllocationCallbacks: ^allocation_callbacks) ---
linear_resampler_process_pcm_frames :: proc(pResampler: ^linear_resampler, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result ---
linear_resampler_set_rate :: proc(pResampler: ^linear_resampler, sampleRateIn, sampleRateOut: u32) -> result ---
linear_resampler_set_rate_ratio :: proc(pResampler: ^linear_resampler, ratioInOut: f32) -> result ---
linear_resampler_get_input_latency :: proc(pResampler: ^linear_resampler) -> u64 ---
linear_resampler_get_output_latency :: proc(pResampler: ^linear_resampler) -> u64 ---
linear_resampler_get_required_input_frame_count :: proc(pResampler: ^linear_resampler, outputFrameCount: u64, pInputFrameCount: ^u64) -> result ---
linear_resampler_get_expected_output_frame_count :: proc(pResampler: ^linear_resampler, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result ---
linear_resampler_reset :: proc(pResampler: ^linear_resampler) -> result ---
resampler_config_init :: proc(format: format, channels: u32, sampleRateIn, sampleRateOut: u32, algorithm: resample_algorithm) -> resampler_config ---
resampler_get_heap_size :: proc(pConfig: ^resampler_config, pHeapSizeInBytes: ^c.size_t) -> result ---
resampler_init_preallocated :: proc(pConfig: ^resampler_config, pHeap: rawptr, pResampler: ^resampler) -> result ---
/*
Initializes a new resampler object from a config.
*/
resampler_init :: proc(pConfig: ^resampler_config, pAllocationCallbacks: ^allocation_callbacks, pResampler: ^resampler) -> result ---
/*
Uninitializes a resampler.
*/
resampler_uninit :: proc(pResampler: ^resampler, pAllocationCallbacks: ^allocation_callbacks) ---
/*
Converts the given input data.
Both the input and output frames must be in the format specified in the config when the resampler was initialized.
On input, [pFrameCountOut] contains the number of output frames to process. On output it contains the number of output frames that
were actually processed, which may be less than the requested amount which will happen if there's not enough input data. You can use
ma_resampler_get_expected_output_frame_count() to know how many output frames will be processed for a given number of input frames.
On input, [pFrameCountIn] contains the number of input frames contained in [pFramesIn]. On output it contains the number of whole
input frames that were actually processed. You can use ma_resampler_get_required_input_frame_count() to know how many input frames
you should provide for a given number of output frames. [pFramesIn] can be NULL, in which case zeroes will be used instead.
If [pFramesOut] is NULL, a seek is performed. In this case, if [pFrameCountOut] is not NULL it will seek by the specified number of
output frames. Otherwise, if [pFramesCountOut] is NULL and [pFrameCountIn] is not NULL, it will seek by the specified number of input
frames. When seeking, [pFramesIn] is allowed to NULL, in which case the internal timing state will be updated, but no input will be
processed. In this case, any internal filter state will be updated as if zeroes were passed in.
It is an error for [pFramesOut] to be non-NULL and [pFrameCountOut] to be NULL.
It is an error for both [pFrameCountOut] and [pFrameCountIn] to be NULL.
*/
resampler_process_pcm_frames :: proc(pResampler: ^resampler, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result ---
/*
Sets the input and output sample rate.
*/
resampler_set_rate :: proc(pResampler: ^resampler, sampleRateIn, sampleRateOut: u32) -> result ---
/*
Sets the input and output sample rate as a ratio.
The ration is in/out.
*/
resampler_set_rate_ratio :: proc(pResampler: ^resampler, ratio: f32) -> result ---
/*
Retrieves the latency introduced by the resampler in input frames.
*/
resampler_get_input_latency :: proc(pResampler: ^resampler) -> u64 ---
/*
Retrieves the latency introduced by the resampler in output frames.
*/
resampler_get_output_latency :: proc(pResampler: ^resampler) -> u64 ---
/*
Calculates the number of whole input frames that would need to be read from the client in order to output the specified
number of output frames.
The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
read from the input buffer in order to output the specified number of output frames.
*/
resampler_get_required_input_frame_count :: proc(pResampler: ^resampler, outputFrameCount: u64, pInputFrameCount: ^u64) -> result ---
/*
Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
input frames.
*/
resampler_get_expected_output_frame_count :: proc(pResampler: ^resampler, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result ---
/*
Resets the resampler's timer and clears its internal cache.
*/
resampler_reset :: proc(pResampler: ^resampler) -> result ---
}
/**************************************************************************************************************************************************************
Channel Conversion
**************************************************************************************************************************************************************/
channel_conversion_path :: enum c.int {
unknown,
passthrough,
mono_out, /* Converting to mono. */
mono_in, /* Converting from mono. */
shuffle, /* Simple shuffle. Will use this when all channels are present in both input and output channel maps, but just in a different order. */
weights, /* Blended based on weights. */
}
mono_expansion_mode :: enum c.int {
duplicate = 0, /* The default. */
average, /* Average the mono channel across all channels. */
stereo_only, /* Duplicate to the left and right channels only and ignore the others. */
default = duplicate,
}
channel_converter_config :: struct {
format: format,
channelsIn: u32,
channelsOut: u32,
pChannelMapIn: [^]channel,
pChannelMapOut: [^]channel,
mixingMode: channel_mix_mode,
calculateLFEFromSpatialChannels: b32, /* When an output LFE channel is present, but no input LFE, set to true to set the output LFE to the average of all spatial channels (LR, FR, etc.). Ignored when an input LFE is present. */
ppWeights: ^[^]f32, /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
}
channel_converter :: struct {
format: format,
channelsIn: u32,
channelsOut: u32,
mixingMode: channel_mix_mode,
conversionPath: channel_conversion_path,
pChannelMapIn: [^]channel,
pChannelMapOut: [^]channel,
pShuffleTable: [^]u8,
weights: struct #raw_union { /* [in][out] */
f32: ^[^]f32,
s16: ^[^]i32,
},
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
channel_converter_config_init :: proc(format: format, channelsIn: u32, pChannelMapIn: [^]channel, channelsOut: u32, pChannelMapOut: [^]channel, mixingMode: channel_mix_mode) -> channel_converter_config ---
channel_converter_get_heap_size :: proc(pConfig: ^channel_converter_config, pHeapSizeInBytes: ^c.size_t) -> result ---
channel_converter_init_preallocated :: proc(pConfig: ^channel_converter_config, pHeap: rawptr, pConverter: ^channel_converter) -> result ---
channel_converter_init :: proc(pConfig: ^channel_converter_config, pAllocationCallbacks: ^allocation_callbacks, pConverter: ^channel_converter) -> result ---
channel_converter_uninit :: proc(pConverter: ^channel_converter, pAllocationCallbacks: ^allocation_callbacks) ---
channel_converter_process_pcm_frames :: proc(pConverter: ^channel_converter, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result ---
channel_converter_get_input_channel_map :: proc(pConverter: ^channel_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
channel_converter_get_output_channel_map :: proc(pConverter: ^channel_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
}
/**************************************************************************************************************************************************************
Data Conversion
**************************************************************************************************************************************************************/
data_converter_config :: struct {
formatIn: format,
formatOut: format,
channelsIn: u32,
channelsOut: u32,
sampleRateIn: u32,
sampleRateOut: u32,
pChannelMapIn: [^]channel,
pChannelMapOut: [^]channel,
ditherMode: dither_mode,
channelMixMode: channel_mix_mode,
calculateLFEFromSpatialChannels: b32, /* When an output LFE channel is present, but no input LFE, set to true to set the output LFE to the average of all spatial channels (LR, FR, etc.). Ignored when an input LFE is present. */
ppChannelWeights: ^[^]f32, /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */
allowDynamicSampleRate: b32,
resampling: resampler_config,
}
data_converter_execution_path :: enum c.int {
passthrough, /* No conversion. */
format_only, /* Only format conversion. */
channels_only, /* Only channel conversion. */
resample_only, /* Only resampling. */
resample_first, /* All conversions, but resample as the first step. */
channels_first, /* All conversions, but channels as the first step. */
}
data_converter :: struct {
formatIn: format,
formatOut: format,
channelsIn: u32,
channelsOut: u32,
sampleRateIn: u32,
sampleRateOut: u32,
ditherMode: dither_mode,
executionPath: data_converter_execution_path, /* The execution path the data converter will follow when processing. */
channelConverter: channel_converter,
resampler: resampler,
hasPreFormatConversion: b8,
hasPostFormatConversion: b8,
hasChannelConverter: b8,
hasResampler: b8,
isPassthrough: b8,
/* Memory management. */
_ownsHeap: b8,
_pHeap: rawptr,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
data_converter_config_init_default :: proc() -> data_converter_config ---
data_converter_config_init :: proc(formatIn, formatOut: format, channelsIn, channelsOut: u32, sampleRateIn, sampleRateOut: u32) -> data_converter_config ---
data_converter_get_heap_size :: proc(pConfig: ^data_converter_config, pHeapSizeInBytes: ^c.size_t) -> result ---
data_converter_init_preallocated :: proc(pConfig: ^data_converter_config, pHeap: rawptr, pConverter: ^data_converter) -> result ---
data_converter_init :: proc(pConfig: ^data_converter_config, pAllocationCallbacks: ^allocation_callbacks, pConverter: ^data_converter) -> result ---
data_converter_uninit :: proc(pConverter: ^data_converter, pAllocationCallbacks: ^allocation_callbacks) ---
data_converter_process_pcm_frames :: proc(pConverter: ^data_converter, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result ---
data_converter_set_rate :: proc(pConverter: ^data_converter, sampleRateIn, sampleRateOut: u32) -> result ---
data_converter_set_rate_ratio :: proc(pConverter: ^data_converter, ratioInOut: f32) -> result ---
data_converter_get_input_latency :: proc(pConverter: ^data_converter) -> u64 ---
data_converter_get_output_latency :: proc(pConverter: ^data_converter) -> u64 ---
data_converter_get_required_input_frame_count :: proc(pConverter: ^data_converter, outputFrameCount: u64, pInputFrameCount: ^u64) -> result ---
data_converter_get_expected_output_frame_count :: proc(pConverter: ^data_converter, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result ---
data_converter_get_input_channel_map :: proc(pConverter: ^data_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
data_converter_get_output_channel_map :: proc(pConverter: ^data_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
data_converter_reset :: proc(pConverter: ^data_converter) -> result ---
}
/************************************************************************************************************************************************************
Format Conversion
************************************************************************************************************************************************************/
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
pcm_u8_to_s16 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_u8_to_s24 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_u8_to_s32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_u8_to_f32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s16_to_u8 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s16_to_s24 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s16_to_s32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s16_to_f32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s24_to_u8 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s24_to_s16 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s24_to_s32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s24_to_f32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s32_to_u8 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s32_to_s16 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s32_to_s24 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_s32_to_f32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_f32_to_u8 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_f32_to_s16 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_f32_to_s24 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_f32_to_s32 :: proc(pOut: rawptr, pIn: rawptr, count: u64, ditherMode: dither_mode) ---
pcm_convert :: proc(pOut: rawptr, formatOut: format, pIn: rawptr, formatIn: format, sampleCount: u64, ditherMode: dither_mode) ---
convert_pcm_frames_format :: proc(pOut: rawptr, formatOut: format, pIn: rawptr, formatIn: format, frameCount: u64, channels: u32, ditherMode: dither_mode) ---
/*
Deinterleaves an interleaved buffer.
*/
deinterleave_pcm_frames :: proc(format: format, channels: u32, frameCount: u64, pInterleavedPCMFrames: rawptr, ppDeinterleavedPCMFrames: ^rawptr) ---
/*
Interleaves a group of deinterleaved buffers.
*/
interleave_pcm_frames :: proc(format: format, channels: u32, frameCount: u64, ppDeinterleavedPCMFrames: ^rawptr, pInterleavedPCMFrames: rawptr) ---
}
/************************************************************************************************************************************************************
Channel Maps
************************************************************************************************************************************************************/
/*
This is used in the shuffle table to indicate that the channel index is undefined and should be ignored.
*/
CHANNEL_INDEX_NULL :: 255
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
/*
Retrieves the channel position of the specified channel in the given channel map.
The pChannelMap parameter can be null, in which case miniaudio's default channel map will be assumed.
*/
channel_map_get_channel :: proc(pChannelMap: [^]channel, channelCount: u32, channelIndex: u32) -> channel ---
/*
Initializes a blank channel map.
When a blank channel map is specified anywhere it indicates that the native channel map should be used.
*/
channel_map_init_blank :: proc(pChannelMap: [^]channel, channels: u32) ---
/*
Helper for retrieving a standard channel map.
The output channel map buffer must have a capacity of at least `channelMapCap`.
*/
channel_map_init_standard :: proc(standardChannelMap: standard_channel_map, pChannelMap: [^]channel, channelMapCap: c.size_t, channels: u32) ---
/*
Copies a channel map.
Both input and output channel map buffers must have a capacity of at least `channels`.
*/
channel_map_copy :: proc(pOut: [^]channel, pIn: [^]channel, channels: u32) ---
/*
Copies a channel map if one is specified, otherwise copies the default channel map.
The output buffer must have a capacity of at least `channels`. If not NULL, the input channel map must also have a capacity of at least `channels`.
*/
channel_map_copy_or_default :: proc(pOut: [^]channel, channelMapCapOut: c.size_t, pIn: [^]channel, channels: u32) ---
/*
Determines whether or not a channel map is valid.
A blank channel map is valid (all channels set to MA_CHANNEL_NONE). The way a blank channel map is handled is context specific, but
is usually treated as a passthrough.
Invalid channel maps:
- A channel map with no channels
- A channel map with more than one channel and a mono channel
The channel map buffer must have a capacity of at least `channels`.
*/
channel_map_is_valid :: proc(pChannelMap: [^]channel, channels: u32) -> b32 ---
/*
Helper for comparing two channel maps for equality.
This assumes the channel count is the same between the two.
Both channels map buffers must have a capacity of at least `channels`.
*/
channel_map_is_equal :: proc(pChannelMapA, pChannelMapB: [^]channel, channels: u32) -> b32 ---
/*
Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE).
The channel map buffer must have a capacity of at least `channels`.
*/
channel_map_is_blank :: proc(pChannelMap: [^]channel, channels: u32) -> b32 ---
/*
Helper for determining whether or not a channel is present in the given channel map.
The channel map buffer must have a capacity of at least `channels`.
*/
channel_map_contains_channel_position :: proc(channels: u32, pChannelMap: [^]channel, channelPosition: channel) -> b32 ---
/*
Find a channel position in the given channel map. Returns MA_TRUE if the channel is found; MA_FALSE otherwise. The
index of the channel is output to `pChannelIndex`.
The channel map buffer must have a capacity of at least `channels`.
*/
channel_map_find_channel_position :: proc(channels: u32, pChannelMap: [^]channel, channelPosition: channel, pChannelIndex: ^u32) -> b32 ---
/*
Generates a string representing the given channel map.
This is for printing and debugging purposes, not serialization/deserialization.
Returns the length of the string, not including the null terminator.
*/
channel_map_to_string :: proc(pChannelMap: [^]channel, channels: u32, pBufferOut: [^]u8, bufferCap: uint) -> uint ---
/*
Retrieves a human readable version of a channel position.
*/
channel_position_to_string :: proc(channel: channel) -> cstring ---
}
/************************************************************************************************************************************************************
Conversion Helpers
************************************************************************************************************************************************************/
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
/*
High-level helper for doing a full format conversion in one go. Returns the number of output frames. Call this with pOut set to NULL to
determine the required size of the output buffer. frameCountOut should be set to the capacity of pOut. If pOut is NULL, frameCountOut is
ignored.
A return value of 0 indicates an error.
This function is useful for one-off bulk conversions, but if you're streaming data you should use the ma_data_converter APIs instead.
*/
convert_frames :: proc(pOut: rawptr, frameCountOut: u64, formatOut: format, channelsOut: u32, sampleRateOut: u32, pIn: rawptr, frameCountIn: u64, formatIn: format, channelsIn: u32, sampleRateIn: u32) -> u64 ---
convert_frames_ex :: proc(pOut: rawptr, frameCountOut: u64, pIn: rawptr, frameCountIn: u64, pConfig: ^data_converter_config) -> u64 ---
}
/************************************************************************************************************************************************************
Ring Buffer
************************************************************************************************************************************************************/
rb :: struct {
pBuffer: rawptr,
subbufferSizeInBytes: u32,
subbufferCount: u32,
subbufferStrideInBytes: u32,
encodedReadOffset: u32, /*atomic*/ /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */
encodedWriteOffset: u32, /*atomic*/ /* Most significant bit is the loop flag. Lower 31 bits contains the actual offset in bytes. Must be used atomically. */
ownsBuffer: b8, /* Used to know whether or not miniaudio is responsible for free()-ing the buffer. */
clearOnWriteAcquire: b8, /* When set, clears the acquired write buffer before returning from ma_rb_acquire_write(). */
allocationCallbacks: allocation_callbacks,
}
pcm_rb :: struct {
ds: data_source_base,
rb: rb,
format: format,
channels: u32,
sampleRate: u32, /* Not required for the ring buffer itself, but useful for associating the data with some sample rate, particularly for data sources. */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
rb_init_ex :: proc(subbufferSizeInBytes, subbufferCount, subbufferStrideInBytes: c.size_t, pOptionalPreallocatedBuffer: rawptr, pAllocationCallbacks: ^allocation_callbacks, pRB: ^rb) -> result ---
rb_init :: proc(bufferSizeInBytes: c.size_t, pOptionalPreallocatedBuffer: rawptr, pAllocationCallbacks: ^allocation_callbacks, pRB: ^rb) -> result ---
rb_uninit :: proc(pRB: ^rb) ---
rb_reset :: proc(pRB: ^rb) ---
rb_acquire_read :: proc(pRB: ^rb, pSizeInBytes: ^c.size_t, ppBufferOut: ^rawptr) -> result ---
rb_commit_read :: proc(pRB: ^rb, sizeInBytes: c.size_t) -> result ---
rb_acquire_write :: proc(pRB: ^rb, pSizeInBytes: ^c.size_t, ppBufferOut: ^rawptr) -> result ---
rb_commit_write :: proc(pRB: ^rb, sizeInBytes: c.size_t) -> result ---
rb_seek_read :: proc(pRB: ^rb, offsetInBytes: c.size_t) -> result ---
rb_seek_write :: proc(pRB: ^rb, offsetInBytes: c.size_t) -> result ---
rb_pointer_distance :: proc(pRB: ^rb) -> i32 --- /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. Will return the number of bytes that can be read before the read pointer hits the write pointer. */
rb_available_read :: proc(pRB: ^rb) -> u32 ---
rb_available_write :: proc(pRB: ^rb) -> u32 ---
rb_get_subbuffer_size :: proc(pRB: ^rb) -> c.size_t ---
rb_get_subbuffer_stride :: proc(pRB: ^rb) -> c.size_t ---
rb_get_subbuffer_offset :: proc(pRB: ^rb, subbufferIndex: c.size_t) -> c.size_t ---
rb_get_subbuffer_ptr :: proc(pRB: ^rb, subbufferIndex: c.size_t, pBuffer: rawptr) -> rawptr ---
pcm_rb_init_ex :: proc(format: format, channels: u32, subbufferSizeInFrames, subbufferCount, subbufferStrideInFrames: u32, pOptionalPreallocatedBuffer: rawptr, pAllocationCallbacks: ^allocation_callbacks, pRB: ^pcm_rb) -> result ---
pcm_rb_init :: proc(format: format, channels: u32, bufferSizeInFrames: u32, pOptionalPreallocatedBuffer: rawptr, pAllocationCallbacks: ^allocation_callbacks, pRB: ^pcm_rb) -> result ---
pcm_rb_uninit :: proc(pRB: ^pcm_rb) ---
pcm_rb_reset :: proc(pRB: ^pcm_rb) ---
pcm_rb_acquire_read :: proc(pRB: ^pcm_rb, pSizeInFrames: ^u32, ppBufferOut: ^rawptr) -> result ---
pcm_rb_commit_read :: proc(pRB: ^pcm_rb, sizeInFrames: u32) -> result ---
pcm_rb_acquire_write :: proc(pRB: ^pcm_rb, pSizeInFrames: ^u32, ppBufferOut: ^rawptr) -> result ---
pcm_rb_commit_write :: proc(pRB: ^pcm_rb, sizeInFrames: u32) -> result ---
pcm_rb_seek_read :: proc(pRB: ^pcm_rb, offsetInFrames: u32) -> result ---
pcm_rb_seek_write :: proc(pRB: ^pcm_rb, offsetInFrames: u32) -> result ---
pcm_rb_pointer_distance :: proc(pRB: ^pcm_rb) -> i32 --- /* Return value is in frames. */
pcm_rb_available_read :: proc(pRB: ^pcm_rb) -> u32 ---
pcm_rb_available_write :: proc(pRB: ^pcm_rb) -> u32 ---
pcm_rb_get_subbuffer_size :: proc(pRB: ^pcm_rb) -> u32 ---
pcm_rb_get_subbuffer_stride :: proc(pRB: ^pcm_rb) -> u32 ---
pcm_rb_get_subbuffer_offset :: proc(pRB: ^pcm_rb, subbufferIndex: u32) -> u32 ---
pcm_rb_get_subbuffer_ptr :: proc(pRB: ^pcm_rb, subbufferIndex: u32, pBuffer: rawptr) -> rawptr ---
pcm_rb_get_format :: proc(pRB: ^pcm_rb) -> format ---
pcm_rb_get_channels :: proc(pRB: ^pcm_rb) -> u32 ---
pcm_rb_get_sample_rate :: proc(pRB: ^pcm_rb) -> u32 ---
pcm_rb_set_sample_rate :: proc(pRB: ^pcm_rb, sampleRate: u32) ---
}
/*
The idea of the duplex ring buffer is to act as the intermediary buffer when running two asynchronous devices in a duplex set up. The
capture device writes to it, and then a playback device reads from it.
At the moment this is just a simple naive implementation, but in the future I want to implement some dynamic resampling to seamlessly
handle desyncs. Note that the API is work in progress and may change at any time in any version.
The size of the buffer is based on the capture side since that's what'll be written to the buffer. It is based on the capture period size
in frames. The internal sample rate of the capture device is also needed in order to calculate the size.
*/
duplex_rb :: struct {
rb: pcm_rb,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
duplex_rb_init :: proc(captureFormat: format, captureChannels: u32, sampleRate: u32, captureInternalSampleRate, captureInternalPeriodSizeInFrames: u32, pAllocationCallbacks: ^allocation_callbacks, pRB: ^duplex_rb) -> result ---
duplex_rb_uninit :: proc(pRB: ^duplex_rb) -> result ---
}
|