Merge branch 'dev' into dev-0.12

This commit is contained in:
David Reid
2025-02-08 07:21:38 +10:00
8 changed files with 1698 additions and 31 deletions
+34 -2
View File
@@ -1,14 +1,46 @@
\#issues/
\#docs/
_private/
debugging/
evaluations/
examples/build/bin/
examples/build/codelite/
examples/build/vc6/
examples/build/vc15/
examples/build/bin/
examples/build/vc17/
examples/simple_playback_sine.cpp
extras/osaudio/tests/build/bin/
extras/osaudio/tests/build/vc17/
extras/osaudio/tests/build/watcom-dos/
extras/backends/pipewire/a.out
extras/decoders/litewav/
research/_build/
tests/_build/bin/
tests/_build/res/output/
tests/_build/tcc/
tests/_build/vc6/
tests/_build/vc15/
tests/_build/vc17/
tests/_build/watcom/
tests/_build/capture.wav
tests/_build/a.out
tests/_build/a.exe
tests/test_stress/
tests/*.c
tests/*.cpp
tools/_build/
website/docs/
*.vcxproj.user
.vs/
.idea/
# Below are individual files that I may start version controlling later or delete outright.
examples/build/COSMO.txt
research/ma_fft.c
research/ma_hrtf.c
research/ma_atomic.c
research/miniaudio_engine.c
tools/codegen/miniaudio_amalgamator.c
tools/codegen/miniaudio_codegen_utils.c
tools/codegen/miniaudio_docgen.c
tools/codegen/miniaudio_hrtfgen.c
tools/codegen/miniaudio_splitter.c
+1 -1
View File
@@ -29,7 +29,7 @@ For more information, please refer to <http://unlicense.org/>
===============================================================================
ALTERNATIVE 2 - MIT No Attribution
===============================================================================
Copyright 2023 David Reid
Copyright 2025 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
+76
View File
@@ -0,0 +1,76 @@
/*
Demonstrates how to do basic spatialization via the high level API.
You can position and orientate sounds to create a simple spatialization effect. This example shows
how to do this.
In addition to positioning sounds, there is the concept of a listener. This can also be positioned
and orientated to help with spatialization.
This example only covers the basics to get your started. See the documentation for more detailed
information on the available features.
To use this example, pass in the path of a sound as the first argument. The sound will be
positioned in front of the listener, while the listener rotates on the the spot to create an
orbiting effect. Terminate the program with Ctrl+C.
*/
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"
#include <stdio.h>
#include <math.h> /* For sinf() and cosf() */
int main(int argc, char** argv)
{
ma_result result;
ma_engine engine;
ma_sound sound;
float listenerAngle = 0;
if (argc < 2) {
printf("No input file.\n");
return -1;
}
result = ma_engine_init(NULL, &engine);
if (result != MA_SUCCESS) {
printf("Failed to initialize engine.\n");
return -1;
}
result = ma_sound_init_from_file(&engine, argv[1], 0, NULL, NULL, &sound);
if (result != MA_SUCCESS) {
printf("Failed to load sound: %s\n", argv[1]);
ma_engine_uninit(&engine);
return -1;
}
/* This sets the position of the sound. miniaudio follows the same coordinate system as OpenGL, where -Z is forward. */
ma_sound_set_position(&sound, 0, 0, -1);
/*
This sets the position of the listener. The second parameter is the listener index. If you have only a single listener, which is
most likely, just use 0. The position defaults to (0,0,0).
*/
ma_engine_listener_set_position(&engine, 0, 0, 0, 0);
/* Sounds are stopped by default. We'll start it once initial parameters have been setup. */
ma_sound_start(&sound);
/* Rotate the listener on the spot to create an orbiting effect. */
for (;;) {
listenerAngle += 0.01f;
ma_engine_listener_set_direction(&engine, 0, sinf(listenerAngle), 0, cosf(listenerAngle));
ma_sleep(1);
}
/* Won't actually get here, but do this to tear down. */
ma_sound_uninit(&sound);
ma_engine_uninit(&engine);
return 0;
}
File diff suppressed because it is too large Load Diff
+283
View File
@@ -0,0 +1,283 @@
#include "../osaudio.h"
#include "../../decoders/litewav/litewav.c"
#include <stdio.h>
#include <stdlib.h> /* free() */
#if defined(__MSDOS__) || defined(__DOS__)
#include <dos.h>
#define OSAUDIO_DOS
#endif
const char* format_to_string(osaudio_format_t format)
{
switch (format)
{
case OSAUDIO_FORMAT_F32: return "F32";
case OSAUDIO_FORMAT_U8: return "U8";
case OSAUDIO_FORMAT_S16: return "S16";
case OSAUDIO_FORMAT_S24: return "S24";
case OSAUDIO_FORMAT_S32: return "S32";
default: return "Unknown Format";
}
}
void enumerate_devices()
{
osaudio_result_t result;
osaudio_info_t* pDeviceInfos;
unsigned int deviceCount;
unsigned int iDevice;
result = osaudio_enumerate(&deviceCount, &pDeviceInfos);
if (result != OSAUDIO_SUCCESS) {
printf("Failed to enumerate devices.");
return;
}
for (iDevice = 0; iDevice < deviceCount; iDevice += 1) {
osaudio_info_t* pDeviceInfo = &pDeviceInfos[iDevice];
printf("Device %u: [%s] %s\n", iDevice, (pDeviceInfo->direction == OSAUDIO_OUTPUT) ? "Playback" : "Capture", pDeviceInfo->name);
#if 0
{
unsigned int iFormat;
printf(" Native Formats\n");
for (iFormat = 0; iFormat < pDeviceInfo->config_count; iFormat += 1) {
osaudio_config_t* pConfig = &pDeviceInfo->configs[iFormat];
printf(" %s %uHz %u channels\n", format_to_string(pConfig->format), pConfig->rate, pConfig->channels);
}
}
#endif
}
free(pDeviceInfos);
}
extern int g_TESTING;
#include <string.h>
/* Sine wave generation. */
#include <math.h>
#if defined(OSAUDIO_DOS)
/* For farmalloc(). */
static void OSAUDIO_FAR* far_malloc(unsigned int sz)
{
unsigned int segment;
unsigned int err;
err = _dos_allocmem(sz >> 4, &segment);
if (err == 0) {
return MK_FP(segment, 0);
} else {
return NULL;
}
}
#else
#define far_malloc malloc
#endif
static char OSAUDIO_FAR* gen_sine_u8(unsigned long frameCount, unsigned int channels, unsigned int sampleRate)
{
float phase = 0;
float phaseIncrement = 2 * 3.14159265f * 220.0f / 44100.0f;
unsigned long iFrame;
char OSAUDIO_FAR* pData;
char OSAUDIO_FAR* pRunningData;
pData = (char OSAUDIO_FAR*)far_malloc(frameCount * channels);
if (pData == NULL) {
return NULL;
}
pRunningData = pData;
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
unsigned int iChannel;
float sample = (float)sin(phase) * 0.2f;
sample = (sample + 1.0f) * 127.5f;
for (iChannel = 0; iChannel < channels; iChannel += 1) {
pRunningData[iChannel] = (unsigned char)sample;
}
pRunningData += channels;
phase += phaseIncrement;
}
return pData;
}
static short OSAUDIO_FAR* gen_sine_s16(unsigned long frameCount, unsigned int channels, unsigned int sampleRate)
{
float phase = 0;
float phaseIncrement = 2 * 3.14159265f * 220.0f / 44100.0f;
unsigned long iFrame;
short OSAUDIO_FAR* pData;
short OSAUDIO_FAR* pRunningData;
pData = (short OSAUDIO_FAR*)far_malloc(frameCount * channels * sizeof(short));
if (pData == NULL) {
return NULL;
}
pRunningData = pData;
for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
unsigned int iChannel;
float sample = (float)sin(phase) * 0.2f;
sample = sample * 32767.5f;
for (iChannel = 0; iChannel < channels; iChannel += 1) {
pRunningData[iChannel] = (short)sample;
}
pRunningData += channels;
phase += phaseIncrement;
}
return pData;
}
//
//
//float sinePhase = 0;
//float sinePhaseIncrement = 0;
//float sineVolume = 0.2f;
//
//static void sine_init()
//{
// sinePhase = 0;
// sinePhaseIncrement = 2 * 3.14159265f * 440.0f / 44100.0f;
//}
//
//static void sine_u8(unsigned char* dst, unsigned int frameCount, unsigned int channels)
//{
// unsigned int iFrame;
//
// for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
// unsigned int iChannel;
// float sample = (float)sin(sinePhase) * sineVolume;
// sample = (sample + 1.0f) * 127.5f;
//
// for (iChannel = 0; iChannel < channels; iChannel += 1) {
// dst[iChannel] = (unsigned char)sample;
// }
//
// dst += channels;
// sinePhase += sinePhaseIncrement;
// }
//}
//
//
//unsigned char data[4096];
int main(int argc, char** argv)
{
osaudio_result_t result;
osaudio_t audio;
osaudio_config_t config;
void OSAUDIO_FAR* pSineWave;
unsigned long sineWaveFrameCount;
unsigned long sineWaveCursor = 0;
enumerate_devices();
osaudio_config_init(&config, OSAUDIO_OUTPUT);
config.format = OSAUDIO_FORMAT_S16;
config.channels = 2;
config.rate = 44100;
result = osaudio_open(&audio, &config);
if (result != OSAUDIO_SUCCESS) {
printf("Failed to initialize audio.\n");
return -1;
}
printf("Device: %s (%s %uHz %u channels)\n", osaudio_get_info(audio)->name, format_to_string(config.format), config.rate, config.channels);
//printf("sizeof(void*) = %u\n", (unsigned int)sizeof(void far *));
/* 5 seconds. */
sineWaveFrameCount = config.rate * 1;
if (config.format == OSAUDIO_FORMAT_U8) {
pSineWave = gen_sine_u8(sineWaveFrameCount, config.channels, config.rate);
} else {
pSineWave = gen_sine_s16(sineWaveFrameCount, config.channels, config.rate);
}
if (pSineWave == NULL) {
printf("Failed to generate sine wave.\n");
return -1;
}
if (config.format == OSAUDIO_FORMAT_U8) {
/*unsigned int framesToSilence = config.rate;
while (framesToSilence > 0) {
unsigned int framesToWrite;
char silence[256];
memset(silence, 128, sizeof(silence));
framesToWrite = framesToSilence;
if (framesToWrite > sizeof(silence) / config.channels) {
framesToWrite = sizeof(silence) / config.channels;
}
osaudio_write(audio, silence, framesToWrite);
framesToSilence -= framesToWrite;
}*/
while (sineWaveCursor < sineWaveFrameCount) {
unsigned long framesToWrite = sineWaveFrameCount - sineWaveCursor;
if (framesToWrite > 0xFFFF) {
framesToWrite = 0xFFFF;
}
//printf("Writing sine wave: %u\n", (unsigned int)framesToWrite);
osaudio_write(audio, (char OSAUDIO_FAR*)pSineWave + (sineWaveCursor * config.channels), (unsigned int)framesToWrite);
sineWaveCursor += framesToWrite;
//printf("TRACE 0\n");
//sine_u8(data, frameCount, config.channels);
//printf("TRACE: %d\n", frameCount);
//osaudio_write(audio, data, frameCount);
//printf("DONE LOOP\n");
}
} else if (config.format == OSAUDIO_FORMAT_S16) {
while (sineWaveCursor < sineWaveFrameCount) {
unsigned long framesToWrite = sineWaveFrameCount - sineWaveCursor;
if (framesToWrite > 0xFFFF) {
framesToWrite = 0xFFFF;
}
osaudio_write(audio, (short OSAUDIO_FAR*)pSineWave + (sineWaveCursor * config.channels), (unsigned int)framesToWrite);
sineWaveCursor += framesToWrite;
}
}
#if defined(OSAUDIO_DOS)
printf("Processing...\n");
for (;;) {
/* Temporary. Just spinning here to ensure the program stays active. */
//delay(1);
if (g_TESTING > 0) {
//printf("TESTING: %d\n", g_TESTING);
}
}
#endif
printf("Shutting down... ");
osaudio_close(audio);
printf("Done.\n");
(void)argc;
(void)argv;
return 0;
}
+161 -28
View File
@@ -3161,7 +3161,7 @@ Biquad filtering is achieved with the `ma_biquad` API. Example:
```c
ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2);
ma_result result = ma_biquad_init(&config, &biquad);
ma_result result = ma_biquad_init(&config, NULL, &biquad);
if (result != MA_SUCCESS) {
// Error.
}
@@ -5913,6 +5913,8 @@ MA_API void ma_data_source_uninit(ma_data_source* pDataSource);
MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */
MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */
MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex);
MA_API ma_result ma_data_source_seek_seconds(ma_data_source* pDataSource, float secondCount, float* pSecondsSeeked); /* Can only seek forward. Abstraction to ma_data_source_seek_pcm_frames() */
MA_API ma_result ma_data_source_seek_to_second(ma_data_source* pDataSource, float seekPointInSeconds); /* Abstraction to ma_data_source_seek_to_pcm_frame() */
MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor);
MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */
@@ -6376,7 +6378,7 @@ Job Queue
/*
Slot Allocator
--------------
The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocator an index that can be used
The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocate an index that can be used
as the insertion point for an object.
Slots are reference counted to help mitigate the ABA problem in the lock-free queue we use for tracking jobs.
@@ -8077,6 +8079,7 @@ struct ma_device
{
/*AAudioStream**/ ma_ptr pStreamPlayback;
/*AAudioStream**/ ma_ptr pStreamCapture;
ma_mutex closeLock;
ma_aaudio_usage usage;
ma_aaudio_content_type contentType;
ma_aaudio_input_preset inputPreset;
@@ -11522,6 +11525,7 @@ MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping);
MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound);
MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound);
MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */
MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds); /* Abstraction to ma_sound_seek_to_pcm_frame() */
MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap);
MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor);
MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength);
@@ -38346,21 +38350,33 @@ static ma_result ma_context_get_device_info__aaudio(ma_context* pContext, ma_dev
return MA_SUCCESS;
}
static ma_result ma_close_streams__aaudio(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
ma_mutex_lock(&pDevice->aaudio.closeLock);
{
/* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
pDevice->aaudio.pStreamCapture = NULL;
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
pDevice->aaudio.pStreamPlayback = NULL;
}
}
ma_mutex_unlock(&pDevice->aaudio.closeLock);
return MA_SUCCESS;
}
static ma_result ma_device_uninit__aaudio(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
/* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */
if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) {
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
pDevice->aaudio.pStreamCapture = NULL;
}
if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) {
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
pDevice->aaudio.pStreamPlayback = NULL;
}
ma_close_streams__aaudio(pDevice);
ma_mutex_uninit(&pDevice->aaudio.closeLock);
return MA_SUCCESS;
}
@@ -38442,6 +38458,11 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf
}
}
result = ma_mutex_init(&pDevice->aaudio.closeLock);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
@@ -38583,15 +38604,7 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev
error_disconnected:
/* The first thing to do is close the streams. */
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) {
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture);
pDevice->aaudio.pStreamCapture = NULL;
}
if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) {
ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback);
pDevice->aaudio.pStreamPlayback = NULL;
}
ma_close_streams__aaudio(pDevice);
/* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */
{
@@ -38652,7 +38665,7 @@ error_disconnected:
result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture);
if (result != MA_SUCCESS) {
ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change.");
ma_device_uninit__aaudio(pDevice);
ma_close_streams__aaudio(pDevice);
return result;
}
@@ -57698,6 +57711,58 @@ static ma_result ma_data_source_resolve_current(ma_data_source* pDataSource, ma_
return MA_SUCCESS;
}
static ma_result ma_data_source_read_pcm_frames_from_backend(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
MA_ASSERT(pDataSourceBase != NULL);
MA_ASSERT(pDataSourceBase->vtable != NULL);
MA_ASSERT(pDataSourceBase->vtable->onRead != NULL);
MA_ASSERT(pFramesRead != NULL);
if (pFramesOut != NULL) {
return pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, pFramesRead);
} else {
/*
No output buffer. Probably seeking forward. Read and discard. Can probably optimize this in terms of
onSeek and onGetCursor, but need to keep in mind that the data source may not implement these functions.
*/
ma_result result;
ma_uint64 framesRead;
ma_format format;
ma_uint32 channels;
ma_uint64 discardBufferCapInFrames;
ma_uint8 pDiscardBuffer[4096];
result = ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0);
if (result != MA_SUCCESS) {
return result;
}
discardBufferCapInFrames = sizeof(pDiscardBuffer) / ma_get_bytes_per_frame(format, channels);
framesRead = 0;
while (framesRead < frameCount) {
ma_uint64 framesReadThisIteration = 0;
ma_uint64 framesToRead = frameCount - framesRead;
if (framesToRead > discardBufferCapInFrames) {
framesToRead = discardBufferCapInFrames;
}
result = pDataSourceBase->vtable->onRead(pDataSourceBase, pDiscardBuffer, framesToRead, &framesReadThisIteration);
if (result != MA_SUCCESS) {
return result;
}
framesRead += framesReadThisIteration;
}
*pFramesRead = framesRead;
return MA_SUCCESS;
}
}
static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead)
{
ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
@@ -57717,7 +57782,7 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa
if ((pDataSourceBase->vtable->flags & MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT) != 0 || (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE))) {
/* Either the data source is self-managing the range, or no range is set - just read like normal. The data source itself will tell us when the end is reached. */
result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead);
result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead);
} else {
/* Need to clamp to within the range. */
ma_uint64 relativeCursor;
@@ -57726,7 +57791,7 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa
result = ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase, &relativeCursor);
if (result != MA_SUCCESS) {
/* Failed to retrieve the cursor. Cannot read within a range or loop points. Just read like normal - this may happen for things like noise data sources where it doesn't really matter. */
result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead);
result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead);
} else {
ma_uint64 rangeBeg;
ma_uint64 rangeEnd;
@@ -57754,7 +57819,7 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa
MA_AT_END so the higher level function can know about it.
*/
if (frameCount > 0) {
result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead);
result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead);
} else {
result = MA_AT_END; /* The cursor is sitting on the end of the range which means we're at the end. */
}
@@ -57927,7 +57992,7 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m
ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
if (pDataSourceBase == NULL) {
return MA_SUCCESS;
return MA_INVALID_ARGS;
}
if (pDataSourceBase->vtable->onSeek == NULL) {
@@ -57935,7 +58000,7 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m
}
if (frameIndex > pDataSourceBase->rangeEndInFrames) {
return MA_INVALID_OPERATION; /* Trying to seek to far forward. */
return MA_INVALID_OPERATION; /* Trying to seek too far forward. */
}
MA_ASSERT(pDataSourceBase->vtable != NULL);
@@ -57943,6 +58008,53 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m
return pDataSourceBase->vtable->onSeek(pDataSource, pDataSourceBase->rangeBegInFrames + frameIndex);
}
MA_API ma_result ma_data_source_seek_seconds(ma_data_source* pDataSource, float secondCount, float* pSecondsSeeked)
{
ma_uint64 frameCount;
ma_uint64 framesSeeked = 0;
ma_uint32 sampleRate;
ma_result result;
if (pDataSource == NULL) {
return MA_INVALID_ARGS;
}
result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0);
if (result != MA_SUCCESS) {
return result;
}
/* We need PCM frames instead of seconds */
frameCount = (ma_uint64)(secondCount * sampleRate);
result = ma_data_source_seek_pcm_frames(pDataSource, frameCount, &framesSeeked);
/* VC6 doesn't support division between unsigned 64-bit integer and floating point number. Signed integer needed. This shouldn't affect anything in practice */
*pSecondsSeeked = (ma_int64)framesSeeked / (float)sampleRate;
return result;
}
MA_API ma_result ma_data_source_seek_to_second(ma_data_source* pDataSource, float seekPointInSeconds)
{
ma_uint64 frameIndex;
ma_uint32 sampleRate;
ma_result result;
if (pDataSource == NULL) {
return MA_INVALID_ARGS;
}
result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0);
if (result != MA_SUCCESS) {
return result;
}
/* We need PCM frames instead of seconds */
frameIndex = (ma_uint64)(seekPointInSeconds * sampleRate);
return ma_data_source_seek_to_pcm_frame(pDataSource, frameIndex);
}
MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{
ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource;
@@ -77035,6 +77147,27 @@ MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameInd
return MA_SUCCESS;
}
MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds)
{
ma_uint64 frameIndex;
ma_uint32 sampleRate;
ma_result result;
if (pSound == NULL) {
return MA_INVALID_ARGS;
}
result = ma_sound_get_data_format(pSound, NULL, NULL, &sampleRate, NULL, 0);
if (result != MA_SUCCESS) {
return result;
}
/* We need PCM frames. We need to convert first */
frameIndex = (ma_uint64)(seekPointInSeconds * sampleRate);
return ma_sound_seek_to_pcm_frame(pSound, frameIndex);
}
MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap)
{
if (pSound == NULL) {
@@ -92840,7 +92973,7 @@ For more information, please refer to <http://unlicense.org/>
===============================================================================
ALTERNATIVE 2 - MIT No Attribution
===============================================================================
Copyright 2023 David Reid
Copyright 2025 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
+1
View File
@@ -0,0 +1 @@
<svg width="74" height="79" viewBox="0 0 74 79" fill="white" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5"><path d="M73.7014 17.9592C72.5616 9.62034 65.1774 3.04876 56.424 1.77536C54.9472 1.56019 49.3517 0.7771 36.3901 0.7771H36.2933C23.3281 0.7771 20.5465 1.56019 19.0697 1.77536C10.56 3.01348 2.78877 8.91838 0.903306 17.356C-0.00357857 21.5113 -0.100361 26.1181 0.068112 30.3439C0.308275 36.404 0.354874 42.4535 0.91406 48.489C1.30064 52.498 1.97502 56.4751 2.93215 60.3905C4.72441 67.6217 11.9795 73.6395 19.0876 76.0945C26.6979 78.6548 34.8821 79.0799 42.724 77.3221C43.5866 77.1245 44.4398 76.8953 45.2833 76.6342C47.1867 76.0381 49.4199 75.3714 51.0616 74.2003C51.0841 74.1839 51.1026 74.1627 51.1156 74.1382C51.1286 74.1138 51.1359 74.0868 51.1368 74.0592V68.2108C51.1364 68.185 51.1302 68.1596 51.1185 68.1365C51.1069 68.1134 51.0902 68.0932 51.0695 68.0773C51.0489 68.0614 51.0249 68.0503 50.9994 68.0447C50.9738 68.0391 50.9473 68.0392 50.9218 68.045C45.8976 69.226 40.7491 69.818 35.5836 69.8087C26.694 69.8087 24.3031 65.6569 23.6184 63.9285C23.0681 62.4347 22.7186 60.8764 22.5789 59.2934C22.5775 59.2669 22.5825 59.2403 22.5934 59.216C22.6043 59.1916 22.621 59.1702 22.6419 59.1533C22.6629 59.1365 22.6876 59.1248 22.714 59.1191C22.7404 59.1134 22.7678 59.1139 22.794 59.1206C27.7345 60.2936 32.799 60.8856 37.8813 60.8843C39.1036 60.8843 40.3223 60.8843 41.5447 60.8526C46.6562 60.7115 52.0437 60.454 57.0728 59.4874C57.1983 59.4628 57.3237 59.4416 57.4313 59.4098C65.3638 57.9107 72.9128 53.2051 73.6799 41.2895C73.7086 40.8204 73.7803 36.3758 73.7803 35.889C73.7839 34.2347 74.3216 24.1533 73.7014 17.9592ZM61.4925 47.6918H53.1514V27.5855C53.1514 23.3526 51.3591 21.1938 47.7136 21.1938C43.7061 21.1938 41.6988 23.7476 41.6988 28.7919V39.7974H33.4078V28.7919C33.4078 23.7476 31.3969 21.1938 27.3894 21.1938C23.7654 21.1938 21.9552 23.3526 21.9516 27.5855V47.6918H13.6176V26.9752C13.6176 22.7423 14.7157 19.3795 16.9118 16.8868C19.1772 14.4 22.1488 13.1231 25.8373 13.1231C30.1064 13.1231 33.3325 14.7386 35.4832 17.9662L37.5587 21.3949L39.6377 17.9662C41.7884 14.7386 45.0145 13.1231 49.2765 13.1231C52.9614 13.1231 55.9329 14.4 58.2055 16.8868C60.4017 19.3772 61.4997 22.74 61.4997 26.9752L61.4925 47.6918Z" fill="inherit"></path></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><g><circle fill="none" cx="10" cy="10" r="10"/><path fill="#FFF" d="M16.67,10A1.46,1.46,0,0,0,14.2,9a7.12,7.12,0,0,0-3.85-1.23L11,4.65,13.14,5.1a1,1,0,1,0,.13-0.61L10.82,4a0.31,0.31,0,0,0-.37.24L9.71,7.71a7.14,7.14,0,0,0-3.9,1.23A1.46,1.46,0,1,0,4.2,11.33a2.87,2.87,0,0,0,0,.44c0,2.24,2.61,4.06,5.83,4.06s5.83-1.82,5.83-4.06a2.87,2.87,0,0,0,0-.44A1.46,1.46,0,0,0,16.67,10Zm-10,1a1,1,0,1,1,1,1A1,1,0,0,1,6.67,11Zm5.81,2.75a3.84,3.84,0,0,1-2.47.77,3.84,3.84,0,0,1-2.47-.77,0.27,0.27,0,0,1,.38-0.38A3.27,3.27,0,0,0,10,14a3.28,3.28,0,0,0,2.09-.61A0.27,0.27,0,1,1,12.48,13.79Zm-0.18-1.71a1,1,0,1,1,1-1A1,1,0,0,1,12.29,12.08Z"/></g></svg>

After

Width:  |  Height:  |  Size: 692 B