Commit 9a36ca40 authored by mercury233's avatar mercury233

test opus & vorbis

parent 5ebd8aef
......@@ -30,6 +30,7 @@
/irrklang
/ikpmp3
/lua
/miniaudio
/sqlite3
/gframe/*.ico
/gframe/ygopro.rc
......
project "cminiaudio"
kind "StaticLib"
files { "*.c", "*.h" }
filter "system:linux"
links { "dl", "pthread", "m" }
This source diff could not be displayed because it is too large. You can view the blob instead.
include "lzma/."
include "spmemvfs/."
if USE_AUDIO then
include "miniaudio/."
end
project "YGOPro"
kind "WindowedApp"
......@@ -43,7 +40,8 @@ project "YGOPro"
if USE_AUDIO then
defines { "YGOPRO_USE_AUDIO" }
links { "cminiaudio" }
includedirs { "../miniaudio" }
links { "miniaudio" }
end
filter "system:windows"
......
#include "sound_manager.h"
#ifdef YGOPRO_USE_AUDIO
#include "../miniaudio/miniaudio_libvorbis.h"
#include "../miniaudio/miniaudio_libopus.h"
#endif
#include "myfilesystem.h"
namespace ygo {
......@@ -10,7 +14,21 @@ bool SoundManager::Init() {
bgm_scene = -1;
RefreshBGMList();
rnd.reset((unsigned int)std::time(nullptr));
if(ma_engine_init(nullptr, &engineSound) || ma_engine_init(nullptr, &engineMusic)) {
ma_decoding_backend_vtable* pCustomBackendVTables[] =
{
ma_decoding_backend_libvorbis,
ma_decoding_backend_libopus
};
resourceManagerConfig = ma_resource_manager_config_init();
resourceManagerConfig.ppCustomDecodingBackendVTables = pCustomBackendVTables;
resourceManagerConfig.customDecodingBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]);
resourceManagerConfig.pCustomDecodingBackendUserData = NULL;
if(ma_resource_manager_init(&resourceManagerConfig, &resourceManager) != MA_SUCCESS) {
return false;
}
engineConfig = ma_engine_config_init();
engineConfig.pResourceManager = &resourceManager;
if(ma_engine_init(&engineConfig, &engineSound) != MA_SUCCESS || ma_engine_init(&engineConfig, &engineMusic) != MA_SUCCESS) {
return false;
} else {
return true;
......
......@@ -4,7 +4,7 @@
#include "game.h"
#include "../ocgcore/mtrandom.h"
#ifdef YGOPRO_USE_AUDIO
#include "miniaudio/miniaudio.h"
#include "../miniaudio/miniaudio.h"
#endif
namespace ygo {
......@@ -15,6 +15,9 @@ private:
int bgm_scene;
mt19937 rnd;
#ifdef YGOPRO_USE_AUDIO
ma_resource_manager_config resourceManagerConfig;
ma_resource_manager resourceManager;
ma_engine_config engineConfig;
ma_engine engineSound;
ma_engine engineMusic;
ma_sound soundBGM;
......
......@@ -52081,8 +52081,6 @@ static ma_result ma_decoder_init_mp3_from_memory__internal(const void* pData, si
#endif /* ma_dr_mp3_h */
/* Vorbis */
// This is the line added by YGOPro
#include "stb_vorbis.c"
#ifdef STB_VORBIS_INCLUDE_STB_VORBIS_H
#define MA_HAS_VORBIS
#ifndef miniaudio_libopus_c
#define miniaudio_libopus_c
#include "miniaudio_libopus.h"
#if !defined(MA_NO_LIBOPUS)
#include <opusfile.h>
#endif
#include <string.h> /* For memset(). */
#include <assert.h>
static ma_result ma_libopus_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
return ma_libopus_read_pcm_frames((ma_libopus*)pDataSource, pFramesOut, frameCount, pFramesRead);
}
static ma_result ma_libopus_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
return ma_libopus_seek_to_pcm_frame((ma_libopus*)pDataSource, frameIndex);
}
static ma_result ma_libopus_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{
return ma_libopus_get_data_format((ma_libopus*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
}
static ma_result ma_libopus_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
{
return ma_libopus_get_cursor_in_pcm_frames((ma_libopus*)pDataSource, pCursor);
}
static ma_result ma_libopus_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
{
return ma_libopus_get_length_in_pcm_frames((ma_libopus*)pDataSource, pLength);
}
static ma_data_source_vtable g_ma_libopus_ds_vtable =
{
ma_libopus_ds_read,
ma_libopus_ds_seek,
ma_libopus_ds_get_data_format,
ma_libopus_ds_get_cursor,
ma_libopus_ds_get_length,
NULL, /* onSetLooping */
0 /* flags */
};
#if !defined(MA_NO_LIBOPUS)
static int ma_libopus_of_callback__read(void* pUserData, unsigned char* pBufferOut, int bytesToRead)
{
ma_libopus* pOpus = (ma_libopus*)pUserData;
ma_result result;
size_t bytesRead;
result = pOpus->onRead(pOpus->pReadSeekTellUserData, (void*)pBufferOut, bytesToRead, &bytesRead);
if (result != MA_SUCCESS) {
return -1;
}
return (int)bytesRead;
}
static int ma_libopus_of_callback__seek(void* pUserData, ogg_int64_t offset, int whence)
{
ma_libopus* pOpus = (ma_libopus*)pUserData;
ma_result result;
ma_seek_origin origin;
if (whence == SEEK_SET) {
origin = ma_seek_origin_start;
} else if (whence == SEEK_END) {
origin = ma_seek_origin_end;
} else {
origin = ma_seek_origin_current;
}
result = pOpus->onSeek(pOpus->pReadSeekTellUserData, offset, origin);
if (result != MA_SUCCESS) {
return -1;
}
return 0;
}
static opus_int64 ma_libopus_of_callback__tell(void* pUserData)
{
ma_libopus* pOpus = (ma_libopus*)pUserData;
ma_result result;
ma_int64 cursor;
if (pOpus->onTell == NULL) {
return -1;
}
result = pOpus->onTell(pOpus->pReadSeekTellUserData, &cursor);
if (result != MA_SUCCESS) {
return -1;
}
return cursor;
}
#endif
static ma_result ma_libopus_init_internal(const ma_decoding_backend_config* pConfig, ma_libopus* pOpus)
{
ma_result result;
ma_data_source_config dataSourceConfig;
if (pOpus == NULL) {
return MA_INVALID_ARGS;
}
memset(pOpus, 0, sizeof(*pOpus));
pOpus->format = ma_format_f32; /* f32 by default. */
if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16)) {
pOpus->format = pConfig->preferredFormat;
} else {
/* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */
}
dataSourceConfig = ma_data_source_config_init();
dataSourceConfig.vtable = &g_ma_libopus_ds_vtable;
result = ma_data_source_init(&dataSourceConfig, &pOpus->ds);
if (result != MA_SUCCESS) {
return result; /* Failed to initialize the base data source. */
}
return MA_SUCCESS;
}
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_result result;
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
result = ma_libopus_init_internal(pConfig, pOpus);
if (result != MA_SUCCESS) {
return result;
}
if (onRead == NULL || onSeek == NULL) {
return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
}
pOpus->onRead = onRead;
pOpus->onSeek = onSeek;
pOpus->onTell = onTell;
pOpus->pReadSeekTellUserData = pReadSeekTellUserData;
#if !defined(MA_NO_LIBOPUS)
{
int libopusResult;
OpusFileCallbacks libopusCallbacks;
/* We can now initialize the Opus decoder. This must be done after we've set up the callbacks. */
libopusCallbacks.read = ma_libopus_of_callback__read;
libopusCallbacks.seek = ma_libopus_of_callback__seek;
libopusCallbacks.close = NULL;
libopusCallbacks.tell = ma_libopus_of_callback__tell;
pOpus->of = op_open_callbacks(pOpus, &libopusCallbacks, NULL, 0, &libopusResult);
if (pOpus->of == NULL) {
return MA_INVALID_FILE;
}
return MA_SUCCESS;
}
#else
{
/* libopus is disabled. */
return MA_NOT_IMPLEMENTED;
}
#endif
}
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_result result;
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libopus. */
result = ma_libopus_init_internal(pConfig, pOpus);
if (result != MA_SUCCESS) {
return result;
}
#if !defined(MA_NO_LIBOPUS)
{
int libopusResult;
pOpus->of = op_open_file(pFilePath, &libopusResult);
if (pOpus->of == NULL) {
return MA_INVALID_FILE;
}
return MA_SUCCESS;
}
#else
{
/* libopus is disabled. */
(void)pFilePath;
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API void ma_libopus_uninit(ma_libopus* pOpus, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pOpus == NULL) {
return;
}
(void)pAllocationCallbacks;
#if !defined(MA_NO_LIBOPUS)
{
op_free((OggOpusFile*)pOpus->of);
}
#else
{
/* libopus is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
}
#endif
ma_data_source_uninit(&pOpus->ds);
}
MA_API ma_result ma_libopus_read_pcm_frames(ma_libopus* pOpus, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
if (pFramesRead != NULL) {
*pFramesRead = 0;
}
if (frameCount == 0) {
return MA_INVALID_ARGS;
}
if (pOpus == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBOPUS)
{
/* We always use floating point format. */
ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */
ma_uint64 totalFramesRead;
ma_format format;
ma_uint32 channels;
ma_libopus_get_data_format(pOpus, &format, &channels, NULL, NULL, 0);
totalFramesRead = 0;
while (totalFramesRead < frameCount) {
long libopusResult;
ma_uint64 framesToRead;
ma_uint64 framesRemaining;
framesRemaining = (frameCount - totalFramesRead);
framesToRead = 1024;
if (framesToRead > framesRemaining) {
framesToRead = framesRemaining;
}
if (format == ma_format_f32) {
libopusResult = op_read_float((OggOpusFile*)pOpus->of, (float* )ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), (int)(framesToRead * channels), NULL);
} else {
libopusResult = op_read ((OggOpusFile*)pOpus->of, (opus_int16*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), (int)(framesToRead * channels), NULL);
}
if (libopusResult < 0) {
result = MA_ERROR; /* Error while decoding. */
break;
} else {
totalFramesRead += libopusResult;
if (libopusResult == 0) {
result = MA_AT_END;
break;
}
}
}
if (pFramesRead != NULL) {
*pFramesRead = totalFramesRead;
}
if (result == MA_SUCCESS && totalFramesRead == 0) {
result = MA_AT_END;
}
return result;
}
#else
{
/* libopus is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
(void)pFramesOut;
(void)frameCount;
(void)pFramesRead;
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API ma_result ma_libopus_seek_to_pcm_frame(ma_libopus* pOpus, ma_uint64 frameIndex)
{
if (pOpus == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBOPUS)
{
int libopusResult = op_pcm_seek((OggOpusFile*)pOpus->of, (ogg_int64_t)frameIndex);
if (libopusResult != 0) {
if (libopusResult == OP_ENOSEEK) {
return MA_INVALID_OPERATION; /* Not seekable. */
} else if (libopusResult == OP_EINVAL) {
return MA_INVALID_ARGS;
} else {
return MA_ERROR;
}
}
return MA_SUCCESS;
}
#else
{
/* libopus is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
(void)frameIndex;
return MA_NOT_IMPLEMENTED;
}
#endif
}
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)
{
/* Defaults for safety. */
if (pFormat != NULL) {
*pFormat = ma_format_unknown;
}
if (pChannels != NULL) {
*pChannels = 0;
}
if (pSampleRate != NULL) {
*pSampleRate = 0;
}
if (pChannelMap != NULL) {
memset(pChannelMap, 0, sizeof(*pChannelMap) * channelMapCap);
}
if (pOpus == NULL) {
return MA_INVALID_OPERATION;
}
if (pFormat != NULL) {
*pFormat = pOpus->format;
}
#if !defined(MA_NO_LIBOPUS)
{
ma_uint32 channels = op_channel_count((OggOpusFile*)pOpus->of, -1);
if (pChannels != NULL) {
*pChannels = channels;
}
if (pSampleRate != NULL) {
*pSampleRate = 48000;
}
if (pChannelMap != NULL) {
ma_channel_map_init_standard(ma_standard_channel_map_vorbis, pChannelMap, channelMapCap, channels);
}
return MA_SUCCESS;
}
#else
{
/* libopus is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API ma_result ma_libopus_get_cursor_in_pcm_frames(ma_libopus* pOpus, ma_uint64* pCursor)
{
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0; /* Safety. */
if (pOpus == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBOPUS)
{
ogg_int64_t offset = op_pcm_tell((OggOpusFile*)pOpus->of);
if (offset < 0) {
return MA_INVALID_FILE;
}
*pCursor = (ma_uint64)offset;
return MA_SUCCESS;
}
#else
{
/* libopus is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API ma_result ma_libopus_get_length_in_pcm_frames(ma_libopus* pOpus, ma_uint64* pLength)
{
if (pLength == NULL) {
return MA_INVALID_ARGS;
}
*pLength = 0; /* Safety. */
if (pOpus == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBOPUS)
{
ogg_int64_t length = op_pcm_total((OggOpusFile*)pOpus->of, -1);
if (length < 0) {
return MA_ERROR;
}
*pLength = (ma_uint64)length;
return MA_SUCCESS;
}
#else
{
/* libopus is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
return MA_NOT_IMPLEMENTED;
}
#endif
}
/*
The code below defines the vtable that you'll plug into your `ma_decoder_config` object.
*/
#if !defined(MA_NO_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)
{
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 ma_gDecodingBackendVTable_libopus =
{
ma_decoding_backend_init__libopus,
ma_decoding_backend_init_file__libopus,
NULL, /* onInitFileW() */
NULL, /* onInitMemory() */
ma_decoding_backend_uninit__libopus
};
ma_decoding_backend_vtable* ma_decoding_backend_libopus = &ma_gDecodingBackendVTable_libopus;
#else
ma_decoding_backend_vtable* ma_decoding_backend_libopus = NULL;
#endif
#endif /* miniaudio_libopus_c */
/*
This implements a data source that decodes Opus streams via libopus + libopusfile
This object can be plugged into any `ma_data_source_*()` API and can also be used as a custom
decoding backend. See the custom_decoder example.
*/
#ifndef miniaudio_libopus_h
#define miniaudio_libopus_h
#ifdef __cplusplus
extern "C" {
#endif
#include <miniaudio.h>
typedef struct
{
ma_data_source_base ds; /* The libopus decoder can be used independently as a data source. */
ma_read_proc onRead;
ma_seek_proc onSeek;
ma_tell_proc onTell;
void* pReadSeekTellUserData;
ma_format format; /* Will be either f32 or s16. */
/*OggOpusFile**/ void* of; /* Typed as void* so we can avoid a dependency on opusfile in the header section. */
} ma_libopus;
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_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_API void ma_libopus_uninit(ma_libopus* pOpus, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_result ma_libopus_read_pcm_frames(ma_libopus* pOpus, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
MA_API ma_result ma_libopus_seek_to_pcm_frame(ma_libopus* pOpus, ma_uint64 frameIndex);
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_API ma_result ma_libopus_get_cursor_in_pcm_frames(ma_libopus* pOpus, ma_uint64* pCursor);
MA_API ma_result ma_libopus_get_length_in_pcm_frames(ma_libopus* pOpus, ma_uint64* pLength);
/* Decoding backend vtable. This is what you'll plug into ma_decoder_config.pBackendVTables. No user data required. */
extern ma_decoding_backend_vtable* ma_decoding_backend_libopus;
#ifdef __cplusplus
}
#endif
#endif /* miniaudio_libopus_h */
#ifndef miniaudio_libvorbis_c
#define miniaudio_libvorbis_c
#include "miniaudio_libvorbis.h"
#if !defined(MA_NO_LIBVORBIS)
#ifndef OV_EXCLUDE_STATIC_CALLBACKS
#define OV_EXCLUDE_STATIC_CALLBACKS
#endif
#include <vorbis/vorbisfile.h>
#endif
#include <string.h> /* For memset(). */
#include <assert.h>
static ma_result ma_libvorbis_ds_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
return ma_libvorbis_read_pcm_frames((ma_libvorbis*)pDataSource, pFramesOut, frameCount, pFramesRead);
}
static ma_result ma_libvorbis_ds_seek(ma_data_source* pDataSource, ma_uint64 frameIndex)
{
return ma_libvorbis_seek_to_pcm_frame((ma_libvorbis*)pDataSource, frameIndex);
}
static ma_result ma_libvorbis_ds_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{
return ma_libvorbis_get_data_format((ma_libvorbis*)pDataSource, pFormat, pChannels, pSampleRate, pChannelMap, channelMapCap);
}
static ma_result ma_libvorbis_ds_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor)
{
return ma_libvorbis_get_cursor_in_pcm_frames((ma_libvorbis*)pDataSource, pCursor);
}
static ma_result ma_libvorbis_ds_get_length(ma_data_source* pDataSource, ma_uint64* pLength)
{
return ma_libvorbis_get_length_in_pcm_frames((ma_libvorbis*)pDataSource, pLength);
}
static ma_data_source_vtable g_ma_libvorbis_ds_vtable =
{
ma_libvorbis_ds_read,
ma_libvorbis_ds_seek,
ma_libvorbis_ds_get_data_format,
ma_libvorbis_ds_get_cursor,
ma_libvorbis_ds_get_length,
NULL, /* onSetLooping */
0 /* flags */
};
#if !defined(MA_NO_LIBVORBIS)
static size_t ma_libvorbis_vf_callback__read(void* pBufferOut, size_t size, size_t count, void* pUserData)
{
ma_libvorbis* pVorbis = (ma_libvorbis*)pUserData;
ma_result result;
size_t bytesToRead;
size_t bytesRead;
/* For consistency with fread(). If `size` of `count` is 0, return 0 immediately without changing anything. */
if (size == 0 || count == 0) {
return 0;
}
bytesToRead = size * count;
result = pVorbis->onRead(pVorbis->pReadSeekTellUserData, pBufferOut, bytesToRead, &bytesRead);
if (result != MA_SUCCESS) {
/* Not entirely sure what to return here. What if an error occurs, but some data was read and bytesRead is > 0? */
return 0;
}
return bytesRead / size;
}
static int ma_libvorbis_vf_callback__seek(void* pUserData, ogg_int64_t offset, int whence)
{
ma_libvorbis* pVorbis = (ma_libvorbis*)pUserData;
ma_result result;
ma_seek_origin origin;
if (whence == SEEK_SET) {
origin = ma_seek_origin_start;
} else if (whence == SEEK_END) {
origin = ma_seek_origin_end;
} else {
origin = ma_seek_origin_current;
}
result = pVorbis->onSeek(pVorbis->pReadSeekTellUserData, offset, origin);
if (result != MA_SUCCESS) {
return -1;
}
return 0;
}
static long ma_libvorbis_vf_callback__tell(void* pUserData)
{
ma_libvorbis* pVorbis = (ma_libvorbis*)pUserData;
ma_result result;
ma_int64 cursor;
result = pVorbis->onTell(pVorbis->pReadSeekTellUserData, &cursor);
if (result != MA_SUCCESS) {
return -1;
}
return (long)cursor;
}
#endif
static ma_result ma_libvorbis_init_internal(const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_libvorbis* pVorbis)
{
ma_result result;
ma_data_source_config dataSourceConfig;
if (pVorbis == NULL) {
return MA_INVALID_ARGS;
}
memset(pVorbis, 0, sizeof(*pVorbis));
pVorbis->format = ma_format_f32; /* f32 by default. */
if (pConfig != NULL && (pConfig->preferredFormat == ma_format_f32 || pConfig->preferredFormat == ma_format_s16)) {
pVorbis->format = pConfig->preferredFormat;
} else {
/* Getting here means something other than f32 and s16 was specified. Just leave this unset to use the default format. */
}
dataSourceConfig = ma_data_source_config_init();
dataSourceConfig.vtable = &g_ma_libvorbis_ds_vtable;
result = ma_data_source_init(&dataSourceConfig, &pVorbis->ds);
if (result != MA_SUCCESS) {
return result; /* Failed to initialize the base data source. */
}
#if !defined(MA_NO_LIBVORBIS)
{
pVorbis->vf = (OggVorbis_File*)ma_malloc(sizeof(OggVorbis_File), pAllocationCallbacks);
if (pVorbis->vf == NULL) {
ma_data_source_uninit(&pVorbis->ds);
return MA_OUT_OF_MEMORY;
}
return MA_SUCCESS;
}
#else
{
/* libvorbis is disabled. */
(void)pAllocationCallbacks;
return MA_NOT_IMPLEMENTED;
}
#endif
}
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 result;
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libvorbis. */
result = ma_libvorbis_init_internal(pConfig, pAllocationCallbacks, pVorbis);
if (result != MA_SUCCESS) {
return result;
}
if (onRead == NULL || onSeek == NULL) {
return MA_INVALID_ARGS; /* onRead and onSeek are mandatory. */
}
pVorbis->onRead = onRead;
pVorbis->onSeek = onSeek;
pVorbis->onTell = onTell;
pVorbis->pReadSeekTellUserData = pReadSeekTellUserData;
#if !defined(MA_NO_LIBVORBIS)
{
int libvorbisResult;
ov_callbacks libvorbisCallbacks;
/* We can now initialize the vorbis decoder. This must be done after we've set up the callbacks. */
libvorbisCallbacks.read_func = ma_libvorbis_vf_callback__read;
libvorbisCallbacks.seek_func = ma_libvorbis_vf_callback__seek;
libvorbisCallbacks.close_func = NULL;
libvorbisCallbacks.tell_func = ma_libvorbis_vf_callback__tell;
libvorbisResult = ov_open_callbacks(pVorbis, (OggVorbis_File*)pVorbis->vf, NULL, 0, libvorbisCallbacks);
if (libvorbisResult < 0) {
return MA_INVALID_FILE;
}
return MA_SUCCESS;
}
#else
{
/* libvorbis is disabled. */
return MA_NOT_IMPLEMENTED;
}
#endif
}
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_result result;
(void)pAllocationCallbacks; /* Can't seem to find a way to configure memory allocations in libvorbis. */
result = ma_libvorbis_init_internal(pConfig, pAllocationCallbacks, pVorbis);
if (result != MA_SUCCESS) {
return result;
}
#if !defined(MA_NO_LIBVORBIS)
{
int libvorbisResult;
libvorbisResult = ov_fopen(pFilePath, (OggVorbis_File*)pVorbis->vf);
if (libvorbisResult < 0) {
return MA_INVALID_FILE;
}
return MA_SUCCESS;
}
#else
{
/* libvorbis is disabled. */
(void)pFilePath;
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API void ma_libvorbis_uninit(ma_libvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks)
{
if (pVorbis == NULL) {
return;
}
(void)pAllocationCallbacks;
#if !defined(MA_NO_LIBVORBIS)
{
ov_clear((OggVorbis_File*)pVorbis->vf);
}
#else
{
/* libvorbis is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
}
#endif
ma_data_source_uninit(&pVorbis->ds);
ma_free(pVorbis->vf, pAllocationCallbacks);
}
MA_API ma_result ma_libvorbis_read_pcm_frames(ma_libvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
if (pFramesRead != NULL) {
*pFramesRead = 0;
}
if (frameCount == 0) {
return MA_INVALID_ARGS;
}
if (pVorbis == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBVORBIS)
{
/* We always use floating point format. */
ma_result result = MA_SUCCESS; /* Must be initialized to MA_SUCCESS. */
ma_uint64 totalFramesRead;
ma_format format;
ma_uint32 channels;
ma_libvorbis_get_data_format(pVorbis, &format, &channels, NULL, NULL, 0);
totalFramesRead = 0;
while (totalFramesRead < frameCount) {
long libvorbisResult;
ma_uint64 framesToRead;
ma_uint64 framesRemaining;
framesRemaining = (frameCount - totalFramesRead);
framesToRead = 1024;
if (framesToRead > framesRemaining) {
framesToRead = framesRemaining;
}
if (format == ma_format_f32) {
float** ppFramesF32;
libvorbisResult = ov_read_float((OggVorbis_File*)pVorbis->vf, &ppFramesF32, (int)framesToRead, NULL);
if (libvorbisResult < 0) {
result = MA_ERROR; /* Error while decoding. */
break;
} else {
/* Frames need to be interleaved. */
ma_interleave_pcm_frames(format, channels, libvorbisResult, (const void**)ppFramesF32, ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels));
totalFramesRead += libvorbisResult;
if (libvorbisResult == 0) {
result = MA_AT_END;
break;
}
}
} else {
libvorbisResult = ov_read((OggVorbis_File*)pVorbis->vf, (char*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, format, channels), (int)(framesToRead * ma_get_bytes_per_frame(format, channels)), 0, 2, 1, NULL);
if (libvorbisResult < 0) {
result = MA_ERROR; /* Error while decoding. */
break;
} else {
/* Conveniently, there's no need to interleaving when using ov_read(). I'm not sure why ov_read_float() is different in that regard... */
totalFramesRead += libvorbisResult / ma_get_bytes_per_frame(format, channels);
if (libvorbisResult == 0) {
result = MA_AT_END;
break;
}
}
}
}
if (pFramesRead != NULL) {
*pFramesRead = totalFramesRead;
}
if (result == MA_SUCCESS && totalFramesRead == 0) {
result = MA_AT_END;
}
return result;
}
#else
{
/* libvorbis is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
(void)pFramesOut;
(void)frameCount;
(void)pFramesRead;
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API ma_result ma_libvorbis_seek_to_pcm_frame(ma_libvorbis* pVorbis, ma_uint64 frameIndex)
{
if (pVorbis == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBVORBIS)
{
int libvorbisResult = ov_pcm_seek((OggVorbis_File*)pVorbis->vf, (ogg_int64_t)frameIndex);
if (libvorbisResult != 0) {
if (libvorbisResult == OV_ENOSEEK) {
return MA_INVALID_OPERATION; /* Not seekable. */
} else if (libvorbisResult == OV_EINVAL) {
return MA_INVALID_ARGS;
} else {
return MA_ERROR;
}
}
return MA_SUCCESS;
}
#else
{
/* libvorbis is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
(void)frameIndex;
return MA_NOT_IMPLEMENTED;
}
#endif
}
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)
{
/* Defaults for safety. */
if (pFormat != NULL) {
*pFormat = ma_format_unknown;
}
if (pChannels != NULL) {
*pChannels = 0;
}
if (pSampleRate != NULL) {
*pSampleRate = 0;
}
if (pChannelMap != NULL) {
memset(pChannelMap, 0, sizeof(*pChannelMap) * channelMapCap);
}
if (pVorbis == NULL) {
return MA_INVALID_OPERATION;
}
if (pFormat != NULL) {
*pFormat = pVorbis->format;
}
#if !defined(MA_NO_LIBVORBIS)
{
vorbis_info* pInfo = ov_info((OggVorbis_File*)pVorbis->vf, 0);
if (pInfo == NULL) {
return MA_INVALID_OPERATION;
}
if (pChannels != NULL) {
*pChannels = pInfo->channels;
}
if (pSampleRate != NULL) {
*pSampleRate = pInfo->rate;
}
if (pChannelMap != NULL) {
ma_channel_map_init_standard(ma_standard_channel_map_vorbis, pChannelMap, channelMapCap, pInfo->channels);
}
return MA_SUCCESS;
}
#else
{
/* libvorbis is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API ma_result ma_libvorbis_get_cursor_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pCursor)
{
if (pCursor == NULL) {
return MA_INVALID_ARGS;
}
*pCursor = 0; /* Safety. */
if (pVorbis == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBVORBIS)
{
ogg_int64_t offset = ov_pcm_tell((OggVorbis_File*)pVorbis->vf);
if (offset < 0) {
return MA_INVALID_FILE;
}
*pCursor = (ma_uint64)offset;
return MA_SUCCESS;
}
#else
{
/* libvorbis is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
return MA_NOT_IMPLEMENTED;
}
#endif
}
MA_API ma_result ma_libvorbis_get_length_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pLength)
{
if (pLength == NULL) {
return MA_INVALID_ARGS;
}
*pLength = 0; /* Safety. */
if (pVorbis == NULL) {
return MA_INVALID_ARGS;
}
#if !defined(MA_NO_LIBVORBIS)
{
/* I don't know how to reliably retrieve the length in frames using libvorbis, so returning 0 for now. */
*pLength = 0;
return MA_SUCCESS;
}
#else
{
/* libvorbis is disabled. Should never hit this since initialization would have failed. */
assert(MA_FALSE);
return MA_NOT_IMPLEMENTED;
}
#endif
}
/*
The code below defines the vtable that you'll plug into your `ma_decoder_config` object.
*/
#if !defined(MA_NO_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)
{
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 ma_gDecodingBackendVTable_libvorbis =
{
ma_decoding_backend_init__libvorbis,
ma_decoding_backend_init_file__libvorbis,
NULL, /* onInitFileW() */
NULL, /* onInitMemory() */
ma_decoding_backend_uninit__libvorbis
};
ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = &ma_gDecodingBackendVTable_libvorbis;
#else
ma_decoding_backend_vtable* ma_decoding_backend_libvorbis = NULL;
#endif
#endif /* miniaudio_libvorbis_c */
/*
This implements a data source that decodes Vorbis streams via libvorbis + libvorbisfile
This object can be plugged into any `ma_data_source_*()` API and can also be used as a custom
decoding backend. See the custom_decoder example.
*/
#ifndef miniaudio_libvorbis_h
#define miniaudio_libvorbis_h
#ifdef __cplusplus
extern "C" {
#endif
#include <miniaudio.h>
typedef struct
{
ma_data_source_base ds; /* The libvorbis decoder can be used independently as a data source. */
ma_read_proc onRead;
ma_seek_proc onSeek;
ma_tell_proc onTell;
void* pReadSeekTellUserData;
ma_format format; /* Will be either f32 or s16. */
/*OggVorbis_File**/ void* vf; /* Typed as void* so we can avoid a dependency on opusfile in the header section. */
} ma_libvorbis;
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_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_API void ma_libvorbis_uninit(ma_libvorbis* pVorbis, const ma_allocation_callbacks* pAllocationCallbacks);
MA_API ma_result ma_libvorbis_read_pcm_frames(ma_libvorbis* pVorbis, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead);
MA_API ma_result ma_libvorbis_seek_to_pcm_frame(ma_libvorbis* pVorbis, ma_uint64 frameIndex);
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_API ma_result ma_libvorbis_get_cursor_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pCursor);
MA_API ma_result ma_libvorbis_get_length_in_pcm_frames(ma_libvorbis* pVorbis, ma_uint64* pLength);
/* Decoding backend vtable. This is what you'll plug into ma_decoder_config.pBackendVTables. No user data required. */
extern ma_decoding_backend_vtable* ma_decoding_backend_libvorbis;
#ifdef __cplusplus
}
#endif
#endif /* miniaudio_libvorbis_h */
Subproject commit fe48b4fbbf9c84c459eca432de494a5bcef1c276
Subproject commit d2c754121645fb021de5dc7d7f13f0a4210f5d9e
project "miniaudio"
kind "StaticLib"
files { "*.c", "*.h" }
files { "external/ogg/src/**.c", "external/ogg/src/**.h" }
files { "external/opus/src/**.c", "external/opus/src/**.h" }
files { "external/opus/celt/*.c", "external/opus/celt/*.h" }
files { "external/opus/silk/*.c", "external/opus/silk/*.h" }
files { "external/opus/silk/float/*.c", "external/opus/silk/float/*.h" }
files { "external/opusfile/src/**.c", "external/opusfile/src/**.h" }
files { "external/vorbis/lib/**.c", "external/vorbis/lib/**.h" }
removefiles { "external/opus/src/opus_demo.c", "external/opus/src/tone.c",
"external/opus/src/opus_encoder.c",
"external/vorbis/lib/psy.h", "external/vorbis/lib/psytune.c", "external/vorbis/lib/tone.c",}
defines { "USE_ALLOCA", "OPUS_BUILD" }
includedirs { ".",
"external/ogg/include",
"external/opus/include",
"external/opus/celt",
"external/opus/silk",
"external/opus/silk/float",
"external/opusfile/include",
"external/vorbis/include" }
filter "system:linux"
links { "dl", "pthread", "m" }
......@@ -199,6 +199,6 @@ workspace "YGOPro"
if BUILD_SQLITE then
include "sqlite3"
end
--if BUILD_IKPMP3 then
-- include "ikpmp3"
--end
if USE_AUDIO then
include "miniaudio"
end
Subproject commit 5d9d3779b34df5937ea9db039b68e6e440d461ec
Subproject commit f10071b5d60b728dda89d2d9dffb8d345d3efba1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment