Merge branch 'dev' into dev-0.12

This commit is contained in:
David Reid
2025-02-18 18:03:01 +10:00
32 changed files with 11546 additions and 250 deletions
+142 -5
View File
@@ -24,13 +24,150 @@ the decoder via the decoder config (`ma_decoder_config`). You need to implement
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 MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"
#include "../extras/miniaudio_libvorbis.h"
#include "../extras/miniaudio_libopus.h"
/*
For now these need to be declared before miniaudio.c due to some compatibility issues with the old
MINIAUDIO_IMPLEMENTATION system. This will change from version 0.12.
*/
#include "../extras/decoders/libvorbis/miniaudio_libvorbis.h"
#include "../extras/decoders/libopus/miniaudio_libopus.h"
#include "../miniaudio.c"
#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) {
ma_free(pVorbis, pAllocationCallbacks);
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) {
ma_free(pVorbis, pAllocationCallbacks);
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_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
};
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) {
ma_free(pOpus, pAllocationCallbacks);
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) {
ma_free(pOpus, pAllocationCallbacks);
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_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
};
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
@@ -130,4 +267,4 @@ int main(int argc, char** argv)
ma_decoder_uninit(&decoder);
return 0;
}
}
+214
View File
@@ -0,0 +1,214 @@
/*
Demonstrates how to implement a custom decoder and use it with the high level API.
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).
*/
/*
For now these need to be declared before miniaudio.c due to some compatibility issues with the old
MINIAUDIO_IMPLEMENTATION system. This will change from version 0.12.
*/
#include "../extras/decoders/libvorbis/miniaudio_libvorbis.h"
#include "../extras/decoders/libopus/miniaudio_libopus.h"
#include "../miniaudio.c"
#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) {
ma_free(pVorbis, pAllocationCallbacks);
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) {
ma_free(pVorbis, pAllocationCallbacks);
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_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
};
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) {
ma_free(pOpus, pAllocationCallbacks);
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) {
ma_free(pOpus, pAllocationCallbacks);
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_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
};
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 to the resource manager 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.customDecodingBackendCount = 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 play 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;
}
+3 -1
View File
@@ -49,6 +49,8 @@ ma_decoder* g_pDecoders;
static ma_data_source* next_callback_tail(ma_data_source* pDataSource)
{
(void)pDataSource; /* Unused. */
if (g_decoderCount > 0) { /* <-- We check for this in main() so should never happen. */
return NULL;
}
@@ -158,4 +160,4 @@ done_decoders:
free(g_pDecoders);
return 0;
}
}
+1 -1
View File
@@ -101,4 +101,4 @@ int main(int argc, char** argv)
ma_engine_uninit(&g_engine);
return 0;
}
}
+3 -1
View File
@@ -13,7 +13,7 @@ head.
#include "../miniaudio.h"
#define SDL_MAIN_HANDLED
#include <SDL.h> /* Change this to your include location. Might be <SDL2/SDL.h>. */
#include <SDL2/SDL.h> /* Change this to your include location. Might be <SDL.h>. */
#define CHANNELS 2 /* Must be stereo for this example. */
#define SAMPLE_RATE 48000
@@ -23,6 +23,8 @@ static ma_sound g_sound; /* This example will play only a single soun
void data_callback(void* pUserData, ma_uint8* pBuffer, int bufferSizeInBytes)
{
(void)pUserData;
/* Reading is just a matter of reading straight from the engine. */
ma_uint32 bufferSizeInFrames = (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(ma_format_f32, ma_engine_get_channels(&g_engine));
ma_engine_read_pcm_frames(&g_engine, pBuffer, bufferSizeInFrames, NULL);
+3 -3
View File
@@ -118,7 +118,7 @@ static void ma_steamaudio_binaural_node_process_pcm_frames(ma_node* pNode, const
pBinauralNode->ppBuffersIn[0] = (float*)ma_offset_pcm_frames_const_ptr_f32(ppFramesIn[0], totalFramesProcessed, 1);
} else {
/* Slow path. Need to deinterleave the input data. */
ma_deinterleave_pcm_frames(ma_format_f32, inputBufferDesc.numChannels, framesToProcessThisIteration, ma_offset_pcm_frames_const_ptr_f32(ppFramesIn[0], totalFramesProcessed, inputBufferDesc.numChannels), pBinauralNode->ppBuffersIn);
ma_deinterleave_pcm_frames(ma_format_f32, inputBufferDesc.numChannels, framesToProcessThisIteration, ma_offset_pcm_frames_const_ptr_f32(ppFramesIn[0], totalFramesProcessed, inputBufferDesc.numChannels), (void**)&pBinauralNode->ppBuffersIn[0]);
}
inputBufferDesc.data = pBinauralNode->ppBuffersIn;
@@ -128,7 +128,7 @@ static void ma_steamaudio_binaural_node_process_pcm_frames(ma_node* pNode, const
iplBinauralEffectApply(pBinauralNode->iplEffect, &binauralParams, &inputBufferDesc, &outputBufferDesc);
/* Interleave straight into the output buffer. */
ma_interleave_pcm_frames(ma_format_f32, 2, framesToProcessThisIteration, pBinauralNode->ppBuffersOut, ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesProcessed, 2));
ma_interleave_pcm_frames(ma_format_f32, 2, framesToProcessThisIteration, (const void**)&pBinauralNode->ppBuffersOut[0], ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesProcessed, 2));
/* Advance. */
totalFramesProcessed += framesToProcessThisIteration;
@@ -436,4 +436,4 @@ int main(int argc, char** argv)
ma_engine_uninit(&g_engine);
return 0;
}
}
+2
View File
@@ -28,6 +28,8 @@ void capture_data_callback(ma_device* pDevice, void* pFramesOut, const void* pFr
ma_result result;
ma_uint32 framesWritten;
(void)pFramesOut;
/* We need to write to the ring buffer. Need to do this in a loop. */
framesWritten = 0;
while (framesWritten < frameCount) {
+1 -1
View File
@@ -266,7 +266,7 @@ int main(int argc, char** argv)
ma_thread_create(&jobThread, ma_thread_priority_default, 0, custom_job_thread, &resourceManager, NULL);
/* Create each data source from the resource manager. Note that the caller is the owner. */
for (iFile = 0; iFile < ma_countof(g_dataSources) && iFile < argc-1; iFile += 1) {
for (iFile = 0; iFile < (int)ma_countof(g_dataSources) && iFile < argc-1; iFile += 1) {
result = ma_resource_manager_data_source_init(
&resourceManager,
argv[iFile+1],
+1 -1
View File
@@ -29,7 +29,7 @@ ma_bool32* g_pDecodersAtEnd;
ma_event g_stopEvent; /* <-- Signaled by the audio thread, waited on by the main thread. */
ma_bool32 are_all_decoders_at_end()
ma_bool32 are_all_decoders_at_end(void)
{
ma_uint32 iDecoder;
for (iDecoder = 0; iDecoder < g_decoderCount; ++iDecoder) {