This commit is contained in:
David Reid
2020-11-04 20:05:31 +10:00
8 changed files with 2033 additions and 1496 deletions
+43 -16
View File
@@ -1,6 +1,6 @@
/*
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_flac - v0.12.19 - 2020-08-30
dr_flac - v0.12.22 - 2020-11-01
David Reid - mackron@gmail.com
@@ -232,7 +232,7 @@ extern "C" {
#define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 19
#define DRFLAC_VERSION_REVISION 22
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
@@ -248,7 +248,7 @@ typedef unsigned int drflac_uint32;
typedef signed __int64 drflac_int64;
typedef unsigned __int64 drflac_uint64;
#else
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
@@ -257,7 +257,7 @@ typedef unsigned int drflac_uint32;
#endif
typedef signed long long drflac_int64;
typedef unsigned long long drflac_uint64;
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#endif
@@ -1319,7 +1319,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
#define dr_flac_c
/* Disable some annoying warnings. */
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#if __GNUC__ >= 7
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
@@ -1367,7 +1367,15 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
#define DRFLAC_ARM
#endif
/* Intrinsics Support */
/*
Intrinsics Support
There's a bug in GCC 4.2.x which results in an incorrect compilation error when using _mm_slli_epi32() where it complains with
"error: shift must be an immediate"
Unfortuantely dr_flac depends on this for a few things so we're just going to disable SSE on GCC 4.2 and below.
*/
#if !defined(DR_FLAC_NO_SIMD)
#if defined(DRFLAC_X64) || defined(DRFLAC_X86)
#if defined(_MSC_VER) && !defined(__clang__)
@@ -1378,7 +1386,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
#if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) /* 2010 */
#define DRFLAC_SUPPORT_SSE41
#endif
#else
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
/* Assume GNUC-style. */
#if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2)
#define DRFLAC_SUPPORT_SSE2
@@ -1828,14 +1836,15 @@ static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n)
#error "This compiler does not support the byte swap intrinsic."
#endif
#else
return ((n & (drflac_uint64)0xFF00000000000000) >> 56) |
((n & (drflac_uint64)0x00FF000000000000) >> 40) |
((n & (drflac_uint64)0x0000FF0000000000) >> 24) |
((n & (drflac_uint64)0x000000FF00000000) >> 8) |
((n & (drflac_uint64)0x00000000FF000000) << 8) |
((n & (drflac_uint64)0x0000000000FF0000) << 24) |
((n & (drflac_uint64)0x000000000000FF00) << 40) |
((n & (drflac_uint64)0x00000000000000FF) << 56);
/* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) |
((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) |
((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) |
((n & ((drflac_uint64)0x000000FF << 32)) >> 8) |
((n & ((drflac_uint64)0xFF000000 )) << 8) |
((n & ((drflac_uint64)0x00FF0000 )) << 24) |
((n & ((drflac_uint64)0x0000FF00 )) << 40) |
((n & ((drflac_uint64)0x000000FF )) << 56);
#endif
}
@@ -5740,6 +5749,9 @@ static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFla
*pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes;
for (;;) {
/* After rangeLo == rangeHi == targetByte fails, we need to break out. */
drflac_uint64 lastTargetByte = targetByte;
/* When seeking to a byte, failure probably means we've attempted to seek beyond the end of the stream. To counter this we just halve it each attempt. */
if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) {
/* If we couldn't even seek to the first byte in the stream we have a problem. Just abandon the whole thing. */
@@ -5780,6 +5792,11 @@ static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFla
}
#endif
}
/* We already tried this byte and there are no more to try, break out. */
if(targetByte == lastTargetByte) {
return DRFLAC_FALSE;
}
}
/* The current PCM frame needs to be updated based on the frame we just seeked to. */
@@ -11762,7 +11779,7 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
return DRFLAC_TRUE;
}
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#endif /* dr_flac_c */
@@ -11772,6 +11789,16 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
/*
REVISION HISTORY
================
v0.12.22 - 2020-11-01
- Fix an error with the previous release.
v0.12.21 - 2020-11-01
- Fix a possible deadlock when seeking.
- Improve compiler support for older versions of GCC.
v0.12.20 - 2020-09-08
- Fix a compilation error on older compilers.
v0.12.19 - 2020-08-30
- Fix a bug due to an undefined 32-bit shift.
+12 -4
View File
@@ -1,6 +1,6 @@
/*
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_mp3 - v0.6.16 - 2020-08-02
dr_mp3 - v0.6.18 - 2020-11-01
David Reid - mackron@gmail.com
@@ -95,7 +95,7 @@ extern "C" {
#define DRMP3_VERSION_MAJOR 0
#define DRMP3_VERSION_MINOR 6
#define DRMP3_VERSION_REVISION 16
#define DRMP3_VERSION_REVISION 18
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
@@ -111,7 +111,7 @@ typedef unsigned int drmp3_uint32;
typedef signed __int64 drmp3_int64;
typedef unsigned __int64 drmp3_uint64;
#else
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
@@ -120,7 +120,7 @@ typedef unsigned int drmp3_uint32;
#endif
typedef signed long long drmp3_int64;
typedef unsigned long long drmp3_uint64;
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#endif
@@ -713,6 +713,8 @@ static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_ar
__asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a));
return x;
}
#else
#define DRMP3_HAVE_ARMV6 0
#endif
@@ -4430,6 +4432,12 @@ counts rather than sample counts.
/*
REVISION HISTORY
================
v0.6.18 - 2020-11-01
- Improve compiler support for older versions of GCC.
v0.6.17 - 2020-09-28
- Bring up to date with minimp3.
v0.6.16 - 2020-08-02
- Simplify sized types.
+168 -59
View File
@@ -1,6 +1,6 @@
/*
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_wav - v0.12.10 - 2020-08-24
dr_wav - v0.12.13 - 2020-11-01
David Reid - mackron@gmail.com
@@ -18,7 +18,7 @@ Changes to Chunk Callback
dr_wav supports the ability to fire a callback when a chunk is encounted (except for WAVE and FMT chunks). The callback has been updated to include both the
container (RIFF or Wave64) and the FMT chunk which contains information about the format of the data in the wave file.
Previously, there was no direct way to determine the container, and therefore no way discriminate against the different IDs in the chunk header (RIFF and
Previously, there was no direct way to determine the container, and therefore no way to discriminate against the different IDs in the chunk header (RIFF and
Wave64 containers encode chunk ID's differently). The `container` parameter can be used to know which ID to use.
Sometimes it can be useful to know the data format at the time the chunk callback is fired. A pointer to a `drwav_fmt` object is now passed into the chunk
@@ -144,7 +144,7 @@ extern "C" {
#define DRWAV_VERSION_MAJOR 0
#define DRWAV_VERSION_MINOR 12
#define DRWAV_VERSION_REVISION 10
#define DRWAV_VERSION_REVISION 13
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
@@ -160,7 +160,7 @@ typedef unsigned int drwav_uint32;
typedef signed __int64 drwav_int64;
typedef unsigned __int64 drwav_uint64;
#else
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
@@ -169,7 +169,7 @@ typedef unsigned int drwav_uint32;
#endif
typedef signed long long drwav_int64;
typedef unsigned long long drwav_uint64;
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#endif
@@ -298,7 +298,8 @@ typedef enum
typedef enum
{
drwav_container_riff,
drwav_container_w64
drwav_container_w64,
drwav_container_rf64
} drwav_container;
typedef struct
@@ -419,8 +420,8 @@ Returns the number of bytes read + seeked.
To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must
be the total number of bytes you have read _plus_ seeked.
Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` you should use `id.fourcc`,
otherwise you should use `id.guid`.
Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should
use `id.fourcc`, otherwise you should use `id.guid`.
The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the
`DR_WAVE_FORMAT_*` identifiers.
@@ -881,8 +882,8 @@ Helper for initializing a writer which outputs data to a memory buffer.
dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be
considered valid until after drwav_uninit() has been called anyway.
The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid
until after drwav_uninit() has been called.
*/
DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
@@ -1236,14 +1237,15 @@ static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
#error "This compiler does not support the byte swap intrinsic."
#endif
#else
return ((n & (drwav_uint64)0xFF00000000000000) >> 56) |
((n & (drwav_uint64)0x00FF000000000000) >> 40) |
((n & (drwav_uint64)0x0000FF0000000000) >> 24) |
((n & (drwav_uint64)0x000000FF00000000) >> 8) |
((n & (drwav_uint64)0x00000000FF000000) << 8) |
((n & (drwav_uint64)0x0000000000FF0000) << 24) |
((n & (drwav_uint64)0x000000000000FF00) << 40) |
((n & (drwav_uint64)0x00000000000000FF) << 56);
/* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
((n & ((drwav_uint64)0x000000FF << 32)) >> 8) |
((n & ((drwav_uint64)0xFF000000 )) << 8) |
((n & ((drwav_uint64)0x00FF0000 )) << 24) |
((n & ((drwav_uint64)0x0000FF00 )) << 40) |
((n & ((drwav_uint64)0x000000FF )) << 56);
#endif
}
@@ -1537,7 +1539,7 @@ static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_for
static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
{
if (container == drwav_container_riff) {
if (container == drwav_container_riff || container == drwav_container_rf64) {
drwav_uint8 sizeInBytes[4];
if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
@@ -1629,7 +1631,7 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe
/* Skip non-fmt chunks. */
while ((container == drwav_container_riff && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
return DRWAV_FALSE;
}
@@ -1643,7 +1645,7 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe
/* Validation. */
if (container == drwav_container_riff) {
if (container == drwav_container_riff || container == drwav_container_rf64) {
if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) {
return DRWAV_FALSE;
}
@@ -1817,9 +1819,9 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
drwav_uint8 riff[4];
drwav_fmt fmt;
unsigned short translatedFormatTag;
drwav_uint64 sampleCountFromFactChunk;
drwav_bool32 foundDataChunk;
drwav_uint64 dataChunkSize;
drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */
drwav_uint64 sampleCountFromFactChunk = 0; /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */
drwav_uint64 chunkSize;
cursor = 0;
@@ -1852,12 +1854,14 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
return DRWAV_FALSE;
}
}
} else if (drwav__fourcc_equal(riff, "RF64")) {
pWav->container = drwav_container_rf64;
} else {
return DRWAV_FALSE; /* Unknown or unsupported container. */
}
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
drwav_uint8 chunkSizeBytes[4];
drwav_uint8 wave[4];
@@ -1866,9 +1870,15 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
return DRWAV_FALSE;
}
if (pWav->container == drwav_container_riff) {
if (drwav__bytes_to_u32(chunkSizeBytes) < 36) {
return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */
}
} else {
if (drwav__bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) {
return DRWAV_FALSE; /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */
}
}
if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
return DRWAV_FALSE;
@@ -1900,6 +1910,54 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
}
/* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */
if (pWav->container == drwav_container_rf64) {
drwav_uint8 sizeBytes[8];
drwav_uint64 bytesRemainingInChunk;
drwav_chunk_header header;
drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
if (result != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
if (!drwav__fourcc_equal(header.id.fourcc, "ds64")) {
return DRWAV_FALSE; /* Expecting "ds64". */
}
bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
/* We don't care about the size of the RIFF chunk - skip it. */
if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
cursor += 8;
/* Next 8 bytes is the size of the "data" chunk. */
if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
dataChunkSize = drwav__bytes_to_u64(sizeBytes);
/* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */
if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
sampleCountFromFactChunk = drwav__bytes_to_u64(sizeBytes);
/* Skip over everything else. */
if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
return DRWAV_FALSE;
}
cursor += bytesRemainingInChunk;
}
/* The next bytes should be the "fmt " chunk. */
if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */
@@ -1921,9 +1979,6 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
}
sampleCountFromFactChunk = 0;
/*
We need to enumerate over each chunk for two reasons:
1) The "data" chunk may not be the next one
@@ -1932,7 +1987,6 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
In order to correctly report each chunk back to the client we will need to keep looping until the end of the file.
*/
foundDataChunk = DRWAV_FALSE;
dataChunkSize = 0;
/* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */
for (;;)
@@ -1968,11 +2022,13 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
}
chunkSize = header.sizeInBytes;
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
if (drwav__fourcc_equal(header.id.fourcc, "data")) {
foundDataChunk = DRWAV_TRUE;
if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */
dataChunkSize = chunkSize;
}
}
} else {
if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
foundDataChunk = DRWAV_TRUE;
@@ -2011,7 +2067,7 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
sampleCountFromFactChunk = 0;
}
}
} else {
} else if (pWav->container == drwav_container_w64) {
if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
return DRWAV_FALSE;
@@ -2022,10 +2078,12 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
pWav->dataChunkDataPos = cursor;
}
}
} else if (pWav->container == drwav_container_rf64) {
/* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */
}
/* "smpl" chunk. */
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
if (drwav__fourcc_equal(header.id.fourcc, "smpl")) {
drwav_uint8 smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */
if (chunkSize >= sizeof(smplHeaderData)) {
@@ -2193,13 +2251,12 @@ DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_
static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)
{
drwav_uint32 dataSubchunkPaddingSize = drwav__chunk_padding_size_riff(dataChunkSize);
if (dataChunkSize <= (0xFFFFFFFFUL - 36 - dataSubchunkPaddingSize)) {
return 36 + (drwav_uint32)(dataChunkSize + dataSubchunkPaddingSize);
} else {
return 0xFFFFFFFF;
drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. */
if (chunkSize > 0xFFFFFFFFUL) {
chunkSize = 0xFFFFFFFFUL;
}
return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */
}
static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
@@ -2223,6 +2280,21 @@ static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
}
static drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize)
{
drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. */
if (chunkSize > 0xFFFFFFFFUL) {
chunkSize = 0xFFFFFFFFUL;
}
return chunkSize;
}
static drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
{
return dataChunkSize;
}
static size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
{
@@ -2342,23 +2414,42 @@ static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_for
/* "RIFF" chunk. */
if (pFormat->container == drwav_container_riff) {
drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize; /* +36 = "RIFF"+[RIFF Chunk Size]+"WAVE" + [sizeof "fmt " chunk] */
drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */
runningPos += drwav__write(pWav, "RIFF", 4);
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
runningPos += drwav__write(pWav, "WAVE", 4);
} else {
} else if (pFormat->container == drwav_container_w64) {
drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
} else if (pFormat->container == drwav_container_rf64) {
runningPos += drwav__write(pWav, "RF64", 4);
runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */
runningPos += drwav__write(pWav, "WAVE", 4);
}
/* "ds64" chunk (RF64 only). */
if (pFormat->container == drwav_container_rf64) {
drwav_uint32 initialds64ChunkSize = 28; /* 28 = [Size of RIFF (8 bytes)] + [Size of DATA (8 bytes)] + [Sample Count (8 bytes)] + [Table Length (4 bytes)]. Table length always set to 0. */
drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; /* +8 for the ds64 header. */
runningPos += drwav__write(pWav, "ds64", 4);
runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize); /* Size of ds64. */
runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize); /* Size of RIFF. Set to true value at the end. */
runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize); /* Size of DATA. Set to true value at the end. */
runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount); /* Sample count. */
runningPos += drwav__write_u32ne_to_le(pWav, 0); /* Table length. Always set to zero in our case since we're not doing any other chunks than "DATA". */
}
/* "fmt " chunk. */
if (pFormat->container == drwav_container_riff) {
if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
chunkSizeFMT = 16;
runningPos += drwav__write(pWav, "fmt ", 4);
runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
} else {
} else if (pFormat->container == drwav_container_w64) {
chunkSizeFMT = 40;
runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
@@ -2378,25 +2469,15 @@ static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_for
drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
runningPos += drwav__write(pWav, "data", 4);
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
} else {
} else if (pFormat->container == drwav_container_w64) {
drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
} else if (pFormat->container == drwav_container_rf64) {
runningPos += drwav__write(pWav, "data", 4);
runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always set to 0xFFFFFFFF for RF64. The true size of the data chunk is specified in the ds64 chunk. */
}
/* Simple validation. */
if (pFormat->container == drwav_container_riff) {
if (runningPos != 20 + chunkSizeFMT + 8) {
return DRWAV_FALSE;
}
} else {
if (runningPos != 40 + chunkSizeFMT + 24) {
return DRWAV_FALSE;
}
}
/* Set some properties for the client's convenience. */
pWav->container = pFormat->container;
pWav->channels = (drwav_uint16)pFormat->channels;
@@ -2440,14 +2521,17 @@ DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pF
/* Casting totalSampleCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */
drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0);
drwav_uint64 riffChunkSizeBytes;
drwav_uint64 fileSizeBytes;
drwav_uint64 fileSizeBytes = 0;
if (pFormat->container == drwav_container_riff) {
riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes);
fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
} else {
} else if (pFormat->container == drwav_container_w64) {
riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
fileSizeBytes = riffChunkSizeBytes;
} else if (pFormat->container == drwav_container_rf64) {
riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes);
fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
}
return fileSizeBytes;
@@ -3353,7 +3437,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
drwav_uint32 paddingSize = 0;
/* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
} else {
paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
@@ -3381,7 +3465,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
drwav__write_u32ne_to_le(pWav, dataChunkSize);
}
} else {
} else if (pWav->container == drwav_container_w64) {
/* The "RIFF" chunk size. */
if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
@@ -3393,6 +3477,21 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, dataChunkSize);
}
} else if (pWav->container == drwav_container_rf64) {
/* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */
int ds64BodyPos = 12 + 8;
/* The "RIFF" chunk size. */
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, riffChunkSize);
}
/* The "data" chunk size. */
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, dataChunkSize);
}
}
}
@@ -5934,6 +6033,16 @@ two different ways to initialize a drwav object.
/*
REVISION HISTORY
================
v0.12.13 - 2020-11-01
- Improve compiler support for older versions of GCC.
v0.12.12 - 2020-09-28
- Add support for RF64.
- Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section.
v0.12.11 - 2020-09-08
- Fix a compilation error on older compilers.
v0.12.10 - 2020-08-24
- Fix a bug when seeking with ADPCM formats.
+339 -136
View File
@@ -1,6 +1,6 @@
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.10.20 - 2020-10-06
miniaudio - v0.10.21 - 2020-10-30
David Reid - mackron@gmail.com
@@ -3662,6 +3662,137 @@ MA_API const char* ma_get_backend_name(ma_backend backend)
}
}
MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend)
{
/*
This looks a little bit gross, but we want all backends to be included in the switch to avoid warnings on some compilers
about some enums not being handled by the switch statement.
*/
switch (backend)
{
case ma_backend_wasapi:
#if defined(MA_HAS_WASAPI)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_dsound:
#if defined(MA_HAS_DSOUND)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_winmm:
#if defined(MA_HAS_WINMM)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_coreaudio:
#if defined(MA_HAS_COREAUDIO)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_sndio:
#if defined(MA_HAS_SNDIO)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_audio4:
#if defined(MA_HAS_AUDIO4)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_oss:
#if defined(MA_HAS_OSS)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_pulseaudio:
#if defined(MA_HAS_PULSEAUDIO)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_alsa:
#if defined(MA_HAS_ALSA)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_jack:
#if defined(MA_HAS_JACK)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_aaudio:
#if defined(MA_HAS_AAUDIO)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_opensl:
#if defined(MA_HAS_OPENSL)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_webaudio:
#if defined(MA_HAS_WEBAUDIO)
return MA_TRUE;
#else
return MA_FALSE;
#endif
case ma_backend_null:
#if defined(MA_HAS_NULL)
return MA_TRUE;
#else
return MA_FALSE;
#endif
default: return MA_FALSE;
}
}
MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount)
{
size_t backendCount;
size_t iBackend;
ma_result result = MA_SUCCESS;
if (pBackendCount == NULL) {
return MA_INVALID_ARGS;
}
backendCount = 0;
for (iBackend = 0; iBackend <= ma_backend_null; iBackend += 1) {
ma_backend backend = (ma_backend)iBackend;
if (ma_is_backend_enabled(backend)) {
/* The backend is enabled. Try adding it to the list. If there's no room, MA_NO_SPACE needs to be returned. */
if (backendCount == backendCap) {
result = MA_NO_SPACE;
break;
} else {
pBackends[backendCount] = backend;
backendCount += 1;
}
}
}
if (pBackendCount != NULL) {
*pBackendCount = backendCount;
}
return result;
}
MA_API ma_bool32 ma_is_loopback_supported(ma_backend backend)
{
switch (backend)
@@ -5107,6 +5238,10 @@ static ma_result ma_device_main_loop__null(ma_device* pDevice)
{
ma_result result = MA_SUCCESS;
ma_bool32 exitLoop = MA_FALSE;
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
MA_ASSERT(pDevice != NULL);
@@ -5128,10 +5263,6 @@ static ma_result ma_device_main_loop__null(ma_device* pDevice)
ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 capturedDeviceFramesRemaining;
ma_uint32 capturedDeviceFramesProcessed;
ma_uint32 capturedDeviceFramesToProcess;
@@ -5212,26 +5343,23 @@ static ma_result ma_device_main_loop__null(ma_device* pDevice)
case ma_device_type_capture:
{
/* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint8 intermediaryBuffer[8192];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
ma_uint32 framesReadThisPeriod = 0;
while (framesReadThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
framesToReadThisIteration = intermediaryBufferSizeInFrames;
if (framesToReadThisIteration > capturedDeviceDataCapInFrames) {
framesToReadThisIteration = capturedDeviceDataCapInFrames;
}
result = ma_device_read__null(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
result = ma_device_read__null(pDevice, capturedDeviceData, framesToReadThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
ma_device__send_frames_to_client(pDevice, framesProcessed, capturedDeviceData);
framesReadThisPeriod += framesProcessed;
}
@@ -5240,21 +5368,19 @@ static ma_result ma_device_main_loop__null(ma_device* pDevice)
case ma_device_type_playback:
{
/* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint8 intermediaryBuffer[8192];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
ma_uint32 framesWrittenThisPeriod = 0;
while (framesWrittenThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
framesToWriteThisIteration = intermediaryBufferSizeInFrames;
if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) {
framesToWriteThisIteration = playbackDeviceDataCapInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData);
result = ma_device_write__null(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
result = ma_device_write__null(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
@@ -7866,7 +7992,7 @@ static ma_result ma_device_stop__wasapi(ma_device* pDevice)
In loopback mode it's possible for WaitForSingleObject() to get stuck in a deadlock when nothing is being played. When nothing
is being played, the event is never signalled internally by WASAPI which means we will deadlock when stopping the device.
*/
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_duplex) {
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) {
SetEvent((HANDLE)pDevice->wasapi.hEventCapture);
}
@@ -11264,6 +11390,10 @@ static ma_result ma_device_main_loop__winmm(ma_device* pDevice)
{
ma_result result = MA_SUCCESS;
ma_bool32 exitLoop = MA_FALSE;
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
MA_ASSERT(pDevice != NULL);
@@ -11307,10 +11437,6 @@ static ma_result ma_device_main_loop__winmm(ma_device* pDevice)
ma_uint32 capturedDevicePeriodSizeInFrames = ma_min(pDevice->capture.internalPeriodSizeInFrames, pDevice->playback.internalPeriodSizeInFrames);
while (totalCapturedDeviceFramesProcessed < capturedDevicePeriodSizeInFrames) {
ma_uint8 capturedDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint8 playbackDeviceData[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 capturedDeviceDataCapInFrames = sizeof(capturedDeviceData) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 playbackDeviceDataCapInFrames = sizeof(playbackDeviceData) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 capturedDeviceFramesRemaining;
ma_uint32 capturedDeviceFramesProcessed;
ma_uint32 capturedDeviceFramesToProcess;
@@ -11391,25 +11517,23 @@ static ma_result ma_device_main_loop__winmm(ma_device* pDevice)
case ma_device_type_capture:
{
/* We read in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->capture.internalPeriodSizeInFrames;
ma_uint32 framesReadThisPeriod = 0;
while (framesReadThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesReadThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToReadThisIteration = framesRemainingInPeriod;
if (framesToReadThisIteration > intermediaryBufferSizeInFrames) {
framesToReadThisIteration = intermediaryBufferSizeInFrames;
if (framesToReadThisIteration > capturedDeviceDataCapInFrames) {
framesToReadThisIteration = capturedDeviceDataCapInFrames;
}
result = ma_device_read__winmm(pDevice, intermediaryBuffer, framesToReadThisIteration, &framesProcessed);
result = ma_device_read__winmm(pDevice, capturedDeviceData, framesToReadThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
}
ma_device__send_frames_to_client(pDevice, framesProcessed, intermediaryBuffer);
ma_device__send_frames_to_client(pDevice, framesProcessed, capturedDeviceData);
framesReadThisPeriod += framesProcessed;
}
@@ -11418,21 +11542,19 @@ static ma_result ma_device_main_loop__winmm(ma_device* pDevice)
case ma_device_type_playback:
{
/* We write in chunks of the period size, but use a stack allocated buffer for the intermediary. */
ma_uint8 intermediaryBuffer[MA_DATA_CONVERTER_STACK_BUFFER_SIZE];
ma_uint32 intermediaryBufferSizeInFrames = sizeof(intermediaryBuffer) / ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 periodSizeInFrames = pDevice->playback.internalPeriodSizeInFrames;
ma_uint32 framesWrittenThisPeriod = 0;
while (framesWrittenThisPeriod < periodSizeInFrames) {
ma_uint32 framesRemainingInPeriod = periodSizeInFrames - framesWrittenThisPeriod;
ma_uint32 framesProcessed;
ma_uint32 framesToWriteThisIteration = framesRemainingInPeriod;
if (framesToWriteThisIteration > intermediaryBufferSizeInFrames) {
framesToWriteThisIteration = intermediaryBufferSizeInFrames;
if (framesToWriteThisIteration > playbackDeviceDataCapInFrames) {
framesToWriteThisIteration = playbackDeviceDataCapInFrames;
}
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, intermediaryBuffer);
ma_device__read_frames_from_client(pDevice, framesToWriteThisIteration, playbackDeviceData);
result = ma_device_write__winmm(pDevice, intermediaryBuffer, framesToWriteThisIteration, &framesProcessed);
result = ma_device_write__winmm(pDevice, playbackDeviceData, framesToWriteThisIteration, &framesProcessed);
if (result != MA_SUCCESS) {
exitLoop = MA_TRUE;
break;
@@ -17136,7 +17258,14 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout*
Need to use the tag to determine the channel map. For now I'm just assuming a default channel map, but later on this should
be updated to determine the mapping based on the tag.
*/
UInt32 channelCount = ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag), channelMapCap);
UInt32 channelCount;
/* Our channel map retrieval APIs below take 32-bit integers, so we'll want to clamp the channel map capacity. */
if (channelMapCap > 0xFFFFFFFF) {
channelMapCap = 0xFFFFFFFF;
}
channelCount = ma_min(AudioChannelLayoutTag_GetNumberOfChannels(pChannelLayout->mChannelLayoutTag), (UInt32)channelMapCap);
switch (pChannelLayout->mChannelLayoutTag)
{
@@ -17742,7 +17871,7 @@ static ma_result ma_find_AudioObjectID(ma_context* pContext, ma_device_type devi
}
static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_bool32 usingDefaultFormat, ma_bool32 usingDefaultChannels, ma_bool32 usingDefaultSampleRate, AudioStreamBasicDescription* pFormat)
static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjectID deviceObjectID, ma_device_type deviceType, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_bool32 usingDefaultFormat, ma_bool32 usingDefaultChannels, ma_bool32 usingDefaultSampleRate, const AudioStreamBasicDescription* pOrigFormat, AudioStreamBasicDescription* pFormat)
{
UInt32 deviceFormatDescriptionCount;
AudioStreamRangedDescription* pDeviceFormatDescriptions;
@@ -17761,41 +17890,21 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec
desiredSampleRate = sampleRate;
if (usingDefaultSampleRate) {
/*
When using the device's default sample rate, we get the highest priority standard rate supported by the device. Otherwise
we just use the pre-set rate.
*/
ma_uint32 iStandardRate;
for (iStandardRate = 0; iStandardRate < ma_countof(g_maStandardSampleRatePriorities); ++iStandardRate) {
ma_uint32 standardRate = g_maStandardSampleRatePriorities[iStandardRate];
ma_bool32 foundRate = MA_FALSE;
UInt32 iDeviceRate;
for (iDeviceRate = 0; iDeviceRate < deviceFormatDescriptionCount; ++iDeviceRate) {
ma_uint32 deviceRate = (ma_uint32)pDeviceFormatDescriptions[iDeviceRate].mFormat.mSampleRate;
if (deviceRate == standardRate) {
desiredSampleRate = standardRate;
foundRate = MA_TRUE;
break;
}
}
if (foundRate) {
break;
}
}
desiredSampleRate = pOrigFormat->mSampleRate;
}
desiredChannelCount = channels;
if (usingDefaultChannels) {
ma_get_AudioObject_channel_count(pContext, deviceObjectID, deviceType, &desiredChannelCount); /* <-- Not critical if this fails. */
desiredChannelCount = pOrigFormat->mChannelsPerFrame;
}
desiredFormat = format;
if (usingDefaultFormat) {
result = ma_format_from_AudioStreamBasicDescription(pOrigFormat, &desiredFormat);
if (result != MA_SUCCESS || desiredFormat == ma_format_unknown) {
desiredFormat = g_maFormatPriorities[0];
}
}
/*
If we get here it means we don't have an exact match to what the client is asking for. We'll need to find the closest one. The next
@@ -18652,6 +18761,8 @@ static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContex
ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
{
/* Don't do anything if we've already initializd device tracking. */
if (g_DeviceTrackingInitCounter_CoreAudio == 0) {
AudioObjectPropertyAddress propAddress;
propAddress.mScope = kAudioObjectPropertyScopeGlobal;
propAddress.mElement = kAudioObjectPropertyElementMaster;
@@ -18663,6 +18774,9 @@ static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContex
propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
((ma_AudioObjectAddPropertyListener_proc)pContext->coreaudio.AudioObjectAddPropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
g_DeviceTrackingInitCounter_CoreAudio += 1;
}
}
ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
@@ -18675,6 +18789,9 @@ static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pCont
ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio);
{
g_DeviceTrackingInitCounter_CoreAudio -= 1;
if (g_DeviceTrackingInitCounter_CoreAudio == 0) {
AudioObjectPropertyAddress propAddress;
propAddress.mScope = kAudioObjectPropertyScopeGlobal;
propAddress.mElement = kAudioObjectPropertyElementMaster;
@@ -18685,12 +18802,14 @@ static ma_result ma_context__uninit_device_tracking__coreaudio(ma_context* pCont
propAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
((ma_AudioObjectRemovePropertyListener_proc)pContext->coreaudio.AudioObjectRemovePropertyListener)(kAudioObjectSystemObject, &propAddress, &ma_default_device_changed__coreaudio, NULL);
/* At this point there should be no tracked devices. If so there's an error somewhere. */
MA_ASSERT(g_ppTrackedDevices_CoreAudio == NULL);
MA_ASSERT(g_TrackedDeviceCount_CoreAudio == 0);
/* At this point there should be no tracked devices. If not there's an error somewhere. */
if (g_ppTrackedDevices_CoreAudio != NULL) {
ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_WARNING, "You have uninitialized all contexts while an associated device is still active.", MA_INVALID_OPERATION);
}
ma_mutex_uninit(&g_DeviceTrackingMutex_CoreAudio);
}
}
ma_spinlock_unlock(&g_DeviceTrackingInitLock_CoreAudio);
return MA_SUCCESS;
@@ -19057,26 +19176,30 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev
AudioStreamBasicDescription origFormat;
UInt32 origFormatSize;
result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, pData->usingDefaultFormat, pData->usingDefaultChannels, pData->usingDefaultSampleRate, &bestFormat);
if (result != MA_SUCCESS) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return result;
}
/* From what I can see, Apple's documentation implies that we should keep the sample rate consistent. */
origFormatSize = sizeof(origFormat);
if (deviceType == ma_device_type_playback) {
status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize);
} else {
status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize);
}
status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &origFormat, &origFormatSize);
if (status != noErr) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return result;
}
result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, pData->usingDefaultFormat, pData->usingDefaultChannels, pData->usingDefaultSampleRate, &origFormat, &bestFormat);
if (result != MA_SUCCESS) {
((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
return result;
}
/*
Update 2020-10-10:
I cannot remember where I read this in the documentation and I cannot find it again. For now I'm going to remove this
and see what the feedback from the community is like. If this results in issues we can add it back in again. The idea
is that the closest sample rate natively supported by the backend to the requested sample rate should be used if possible.
*/
#if 0
/* From what I can see, Apple's documentation implies that we should keep the sample rate consistent. */
bestFormat.mSampleRate = origFormat.mSampleRate;
#endif
status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
if (status != noErr) {
@@ -31827,7 +31950,7 @@ static ma_result ma_resampler_process_pcm_frames__seek__linear(ma_resampler* pRe
static ma_result ma_resampler_process_pcm_frames__seek__speex(ma_resampler* pResampler, const void* pFramesIn, ma_uint64* pFrameCountIn, ma_uint64* pFrameCountOut)
{
/* The generic seek method is implemented in on top of ma_resampler_process_pcm_frames__read() by just processing into a dummy buffer. */
float devnull[8192];
float devnull[4096];
ma_uint64 totalOutputFramesToProcess;
ma_uint64 totalOutputFramesProcessed;
ma_uint64 totalInputFramesProcessed;
@@ -36162,7 +36285,7 @@ MA_API ma_result ma_vfs_write(ma_vfs* pVFS, ma_vfs_file file, const void* pSrc,
{
ma_vfs_callbacks* pCallbacks = (ma_vfs_callbacks*)pVFS;
if (pBytesWritten == NULL) {
if (pBytesWritten != NULL) {
*pBytesWritten = 0;
}
@@ -36399,9 +36522,13 @@ static ma_result ma_default_vfs_read__win32(ma_vfs* pVFS, ma_vfs_file file, void
}
readResult = ReadFile((HANDLE)file, ma_offset_ptr(pDst, totalBytesRead), bytesToRead, &bytesRead, NULL);
if (readResult == 1 && bytesRead == 0) {
break; /* EOF */
}
totalBytesRead += bytesRead;
if (bytesRead < bytesToRead || (readResult == 1 && bytesRead == 0)) {
if (bytesRead < bytesToRead) {
break; /* EOF */
}
@@ -36448,7 +36575,7 @@ static ma_result ma_default_vfs_write__win32(ma_vfs* pVFS, ma_vfs_file file, con
}
}
if (pBytesWritten == NULL) {
if (pBytesWritten != NULL) {
*pBytesWritten = totalBytesWritten;
}
@@ -36910,7 +37037,7 @@ extern "C" {
#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
#define DRWAV_VERSION_MAJOR 0
#define DRWAV_VERSION_MINOR 12
#define DRWAV_VERSION_REVISION 10
#define DRWAV_VERSION_REVISION 12
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
#include <stddef.h>
typedef signed char drwav_int8;
@@ -37049,7 +37176,8 @@ typedef enum
typedef enum
{
drwav_container_riff,
drwav_container_w64
drwav_container_w64,
drwav_container_rf64
} drwav_container;
typedef struct
{
@@ -37282,7 +37410,7 @@ extern "C" {
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
#define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 19
#define DRFLAC_VERSION_REVISION 20
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h>
typedef signed char drflac_int8;
@@ -37643,7 +37771,7 @@ extern "C" {
#define DRMP3_XSTRINGIFY(x) DRMP3_STRINGIFY(x)
#define DRMP3_VERSION_MAJOR 0
#define DRMP3_VERSION_MINOR 6
#define DRMP3_VERSION_REVISION 16
#define DRMP3_VERSION_REVISION 17
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
#include <stddef.h>
typedef signed char drmp3_int8;
@@ -41684,14 +41812,14 @@ static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
#error "This compiler does not support the byte swap intrinsic."
#endif
#else
return ((n & (drwav_uint64)0xFF00000000000000) >> 56) |
((n & (drwav_uint64)0x00FF000000000000) >> 40) |
((n & (drwav_uint64)0x0000FF0000000000) >> 24) |
((n & (drwav_uint64)0x000000FF00000000) >> 8) |
((n & (drwav_uint64)0x00000000FF000000) << 8) |
((n & (drwav_uint64)0x0000000000FF0000) << 24) |
((n & (drwav_uint64)0x000000000000FF00) << 40) |
((n & (drwav_uint64)0x00000000000000FF) << 56);
return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
((n & ((drwav_uint64)0x000000FF << 32)) >> 8) |
((n & ((drwav_uint64)0xFF000000 )) << 8) |
((n & ((drwav_uint64)0x00FF0000 )) << 24) |
((n & ((drwav_uint64)0x0000FF00 )) << 40) |
((n & ((drwav_uint64)0x000000FF )) << 56);
#endif
}
static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
@@ -41927,7 +42055,7 @@ static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 sam
static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
{
if (container == drwav_container_riff) {
if (container == drwav_container_riff || container == drwav_container_rf64) {
drwav_uint8 sizeInBytes[4];
if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
return DRWAV_AT_END;
@@ -41996,7 +42124,7 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe
if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
while ((container == drwav_container_riff && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
return DRWAV_FALSE;
}
@@ -42005,7 +42133,7 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe
return DRWAV_FALSE;
}
}
if (container == drwav_container_riff) {
if (container == drwav_container_riff || container == drwav_container_rf64) {
if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) {
return DRWAV_FALSE;
}
@@ -42138,9 +42266,9 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
drwav_uint8 riff[4];
drwav_fmt fmt;
unsigned short translatedFormatTag;
drwav_uint64 sampleCountFromFactChunk;
drwav_bool32 foundDataChunk;
drwav_uint64 dataChunkSize;
drwav_uint64 dataChunkSize = 0;
drwav_uint64 sampleCountFromFactChunk = 0;
drwav_uint64 chunkSize;
cursor = 0;
sequential = (flags & DRWAV_SEQUENTIAL) != 0;
@@ -42161,18 +42289,26 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
return DRWAV_FALSE;
}
}
} else if (drwav__fourcc_equal(riff, "RF64")) {
pWav->container = drwav_container_rf64;
} else {
return DRWAV_FALSE;
}
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
drwav_uint8 chunkSizeBytes[4];
drwav_uint8 wave[4];
if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
return DRWAV_FALSE;
}
if (pWav->container == drwav_container_riff) {
if (drwav__bytes_to_u32(chunkSizeBytes) < 36) {
return DRWAV_FALSE;
}
} else {
if (drwav__bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) {
return DRWAV_FALSE;
}
}
if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
return DRWAV_FALSE;
}
@@ -42195,6 +42331,38 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
return DRWAV_FALSE;
}
}
if (pWav->container == drwav_container_rf64) {
drwav_uint8 sizeBytes[8];
drwav_uint64 bytesRemainingInChunk;
drwav_chunk_header header;
drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
if (result != DRWAV_SUCCESS) {
return DRWAV_FALSE;
}
if (!drwav__fourcc_equal(header.id.fourcc, "ds64")) {
return DRWAV_FALSE;
}
bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
cursor += 8;
if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
dataChunkSize = drwav__bytes_to_u64(sizeBytes);
if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
return DRWAV_FALSE;
}
bytesRemainingInChunk -= 8;
sampleCountFromFactChunk = drwav__bytes_to_u64(sizeBytes);
if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
return DRWAV_FALSE;
}
cursor += bytesRemainingInChunk;
}
if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) {
return DRWAV_FALSE;
}
@@ -42208,9 +42376,7 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0);
}
sampleCountFromFactChunk = 0;
foundDataChunk = DRWAV_FALSE;
dataChunkSize = 0;
for (;;)
{
drwav_chunk_header header;
@@ -42234,11 +42400,13 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
pWav->dataChunkDataPos = cursor;
}
chunkSize = header.sizeInBytes;
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
if (drwav__fourcc_equal(header.id.fourcc, "data")) {
foundDataChunk = DRWAV_TRUE;
if (pWav->container != drwav_container_rf64) {
dataChunkSize = chunkSize;
}
}
} else {
if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
foundDataChunk = DRWAV_TRUE;
@@ -42264,7 +42432,7 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
sampleCountFromFactChunk = 0;
}
}
} else {
} else if (pWav->container == drwav_container_w64) {
if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
return DRWAV_FALSE;
@@ -42274,8 +42442,9 @@ static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk,
pWav->dataChunkDataPos = cursor;
}
}
} else if (pWav->container == drwav_container_rf64) {
}
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
if (drwav__fourcc_equal(header.id.fourcc, "smpl")) {
drwav_uint8 smplHeaderData[36];
if (chunkSize >= sizeof(smplHeaderData)) {
@@ -42394,12 +42563,11 @@ DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_
}
static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize)
{
drwav_uint32 dataSubchunkPaddingSize = drwav__chunk_padding_size_riff(dataChunkSize);
if (dataChunkSize <= (0xFFFFFFFFUL - 36 - dataSubchunkPaddingSize)) {
return 36 + (drwav_uint32)(dataChunkSize + dataSubchunkPaddingSize);
} else {
return 0xFFFFFFFF;
drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
if (chunkSize > 0xFFFFFFFFUL) {
chunkSize = 0xFFFFFFFFUL;
}
return (drwav_uint32)chunkSize;
}
static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
{
@@ -42418,6 +42586,18 @@ static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
{
return 24 + dataChunkSize;
}
static drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize)
{
drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize);
if (chunkSize > 0xFFFFFFFFUL) {
chunkSize = 0xFFFFFFFFUL;
}
return chunkSize;
}
static drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
{
return dataChunkSize;
}
static size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
{
DRWAV_ASSERT(pWav != NULL);
@@ -42498,21 +42678,35 @@ static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_for
}
pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
if (pFormat->container == drwav_container_riff) {
drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize;
drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize;
runningPos += drwav__write(pWav, "RIFF", 4);
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
runningPos += drwav__write(pWav, "WAVE", 4);
} else {
} else if (pFormat->container == drwav_container_w64) {
drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize;
runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
} else if (pFormat->container == drwav_container_rf64) {
runningPos += drwav__write(pWav, "RF64", 4);
runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
runningPos += drwav__write(pWav, "WAVE", 4);
}
if (pFormat->container == drwav_container_riff) {
if (pFormat->container == drwav_container_rf64) {
drwav_uint32 initialds64ChunkSize = 28;
drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize;
runningPos += drwav__write(pWav, "ds64", 4);
runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize);
runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize);
runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize);
runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount);
runningPos += drwav__write_u32ne_to_le(pWav, 0);
}
if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
chunkSizeFMT = 16;
runningPos += drwav__write(pWav, "fmt ", 4);
runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
} else {
} else if (pFormat->container == drwav_container_w64) {
chunkSizeFMT = 40;
runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
@@ -42528,19 +42722,13 @@ static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_for
drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
runningPos += drwav__write(pWav, "data", 4);
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
} else {
} else if (pFormat->container == drwav_container_w64) {
drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize;
runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
}
if (pFormat->container == drwav_container_riff) {
if (runningPos != 20 + chunkSizeFMT + 8) {
return DRWAV_FALSE;
}
} else {
if (runningPos != 40 + chunkSizeFMT + 24) {
return DRWAV_FALSE;
}
} else if (pFormat->container == drwav_container_rf64) {
runningPos += drwav__write(pWav, "data", 4);
runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF);
}
pWav->container = pFormat->container;
pWav->channels = (drwav_uint16)pFormat->channels;
@@ -42574,13 +42762,16 @@ DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pF
{
drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0);
drwav_uint64 riffChunkSizeBytes;
drwav_uint64 fileSizeBytes;
drwav_uint64 fileSizeBytes = 0;
if (pFormat->container == drwav_container_riff) {
riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes);
fileSizeBytes = (8 + riffChunkSizeBytes);
} else {
} else if (pFormat->container == drwav_container_w64) {
riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
fileSizeBytes = riffChunkSizeBytes;
} else if (pFormat->container == drwav_container_rf64) {
riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes);
fileSizeBytes = (8 + riffChunkSizeBytes);
}
return fileSizeBytes;
}
@@ -43352,7 +43543,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
}
if (pWav->onWrite != NULL) {
drwav_uint32 paddingSize = 0;
if (pWav->container == drwav_container_riff) {
if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
} else {
paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
@@ -43371,7 +43562,7 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
drwav__write_u32ne_to_le(pWav, dataChunkSize);
}
} else {
} else if (pWav->container == drwav_container_w64) {
if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, riffChunkSize);
@@ -43380,6 +43571,16 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, dataChunkSize);
}
} else if (pWav->container == drwav_container_rf64) {
int ds64BodyPos = 12 + 8;
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, riffChunkSize);
}
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
drwav__write_u64ne_to_le(pWav, dataChunkSize);
}
}
}
if (pWav->isSequentialWrite) {
@@ -45592,14 +45793,14 @@ static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n)
#error "This compiler does not support the byte swap intrinsic."
#endif
#else
return ((n & (drflac_uint64)0xFF00000000000000) >> 56) |
((n & (drflac_uint64)0x00FF000000000000) >> 40) |
((n & (drflac_uint64)0x0000FF0000000000) >> 24) |
((n & (drflac_uint64)0x000000FF00000000) >> 8) |
((n & (drflac_uint64)0x00000000FF000000) << 8) |
((n & (drflac_uint64)0x0000000000FF0000) << 24) |
((n & (drflac_uint64)0x000000000000FF00) << 40) |
((n & (drflac_uint64)0x00000000000000FF) << 56);
return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) |
((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) |
((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) |
((n & ((drflac_uint64)0x000000FF << 32)) >> 8) |
((n & ((drflac_uint64)0xFF000000 )) << 8) |
((n & ((drflac_uint64)0x00FF0000 )) << 24) |
((n & ((drflac_uint64)0x0000FF00 )) << 40) |
((n & ((drflac_uint64)0x000000FF )) << 56);
#endif
}
static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n)
@@ -53483,6 +53684,8 @@ static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_ar
__asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a));
return x;
}
#else
#define DRMP3_HAVE_ARMV6 0
#endif
typedef struct
{
+83 -3
View File
@@ -1,6 +1,6 @@
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.10.20 - 2020-10-06
miniaudio - v0.10.21 - 2020-10-30
David Reid - mackron@gmail.com
@@ -20,7 +20,7 @@ extern "C" {
#define MA_VERSION_MAJOR 0
#define MA_VERSION_MINOR 10
#define MA_VERSION_REVISION 20
#define MA_VERSION_REVISION 21
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
#if defined(_MSC_VER) && !defined(__clang__)
@@ -1525,6 +1525,8 @@ typedef enum
ma_backend_null /* <-- Must always be the last item. Lowest priority, and used as the terminator for backend enumeration. */
} ma_backend;
#define MA_BACKEND_COUNT (ma_backend_null+1)
/*
The callback for processing audio data from the device.
@@ -2474,7 +2476,7 @@ struct ma_device
ma_uint32 currentPeriodFramesRemainingPlayback;
ma_uint32 currentPeriodFramesRemainingCapture;
ma_uint64 lastProcessedFramePlayback;
ma_uint32 lastProcessedFrameCapture;
ma_uint64 lastProcessedFrameCapture;
ma_bool32 isStarted;
} null_device;
#endif
@@ -3674,6 +3676,84 @@ Retrieves a friendly name for a backend.
*/
MA_API const char* ma_get_backend_name(ma_backend backend);
/*
Determines whether or not the given backend is available by the compilation environment.
*/
MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend);
/*
Retrieves compile-time enabled backends.
Parameters
----------
pBackends(out, optional)
A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting
the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends.
backendCap(in)
The capacity of the `pBackends` buffer.
pBackendCount(out)
A pointer to the variable that will receive the enabled backend count.
Return Value
------------
MA_SUCCESS if successful.
MA_INVALID_ARGS if `pBackendCount` is NULL.
MA_NO_SPACE if the capacity of `pBackends` is not large enough.
If `MA_NO_SPACE` is returned, the `pBackends` buffer will be filled with `*pBackendCount` values.
Thread Safety
-------------
Safe.
Callback Safety
---------------
Safe.
Remarks
-------
If you want to retrieve the number of backends so you can determine the capacity of `pBackends` buffer, you can call
this function with `pBackends` set to NULL.
This will also enumerate the null backend. If you don't want to include this you need to check for `ma_backend_null`
when you enumerate over the returned backends and handle it appropriately. Alternatively, you can disable it at
compile time with `MA_NO_NULL`.
The returned backends are determined based on compile time settings, not the platform it's currently running on. For
example, PulseAudio will be returned if it was enabled at compile time, even when the user doesn't actually have
PulseAudio installed.
Example 1
---------
The example below retrieves the enabled backend count using a fixed sized buffer allocated on the stack. The buffer is
given a capacity of `MA_BACKEND_COUNT` which will guarantee it'll be large enough to store all available backends.
Since `MA_BACKEND_COUNT` is always a relatively small value, this should be suitable for most scenarios.
```
ma_backend enabledBackends[MA_BACKEND_COUNT];
size_t enabledBackendCount;
result = ma_get_enabled_backends(enabledBackends, MA_BACKEND_COUNT, &enabledBackendCount);
if (result != MA_SUCCESS) {
// Failed to retrieve enabled backends. Should never happen in this example since all inputs are valid.
}
```
See Also
--------
ma_is_backend_enabled()
*/
MA_API ma_result ma_get_enabled_backends(ma_backend* pBackends, size_t backendCap, size_t* pBackendCount);
/*
Determines whether or not loopback mode is support by a backend.
*/
+10 -11
View File
@@ -6,21 +6,20 @@
#define RANDOM_PREFIX ma_speex
#include "thirdparty/speex_resampler.h"
#ifdef _MSC_VER
#if defined(__clang__)
#if defined(_MSC_VER)
typedef unsigned __int64 spx_uint64_t;
#else
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlanguage-extension-token"
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc++11-long-long"
#endif
typedef unsigned __int64 spx_uint64_t;
#if defined(__clang__)
#endif
typedef unsigned long long spx_uint64_t;
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#else
#define MA_HAS_STDINT
#include <stdint.h>
typedef uint64_t spx_uint64_t;
#endif
int ma_speex_resampler_get_required_input_frame_count(SpeexResamplerState* st, spx_uint64_t out_len, spx_uint64_t* in_len);
@@ -50,14 +49,14 @@ int ma_speex_resampler_get_expected_output_frame_count(SpeexResamplerState* st,
#pragma warning(disable:4244) /* conversion from 'x' to 'y', possible loss of data */
#pragma warning(disable:4018) /* signed/unsigned mismatch */
#pragma warning(disable:4706) /* assignment within conditional expression */
#else
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare" /* comparison between signed and unsigned integer expressions */
#endif
#include "thirdparty/resample.c"
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#else
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
+1243 -1141
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -240,10 +240,14 @@ ma_result print_device_info(ma_context* pContext, ma_device_type deviceType, con
MA_ASSERT(pDeviceInfo != NULL);
#if 1
result = ma_context_get_device_info(pContext, deviceType, &pDeviceInfo->id, ma_share_mode_shared, &detailedDeviceInfo);
if (result != MA_SUCCESS) {
return result;
}
#else
detailedDeviceInfo = *pDeviceInfo;
#endif
printf("%s\n", pDeviceInfo->name);
printf(" Default: %s\n", (detailedDeviceInfo._private.isDefault) ? "Yes" : "No");
@@ -579,5 +583,10 @@ done:
ma_encoder_uninit(&g_State.encoder);
}
printf("Press Enter to quit...");
getchar();
getchar();
return 0;
}