update SDL_mixer to SDL3_mixer 3.2.0

This commit is contained in:
Sven Balzer
2026-04-02 16:52:07 +02:00
parent 05b19704f8
commit 8a5caf5c0d
1202 changed files with 366156 additions and 152445 deletions
+40
View File
@@ -0,0 +1,40 @@
# CMake script for building SDL_mixer tests
set(CMAKE_POSITION_INDEPENDENT_CODE OFF)
set(RESOURCE_FILES
)
function(add_sdl_mixer_test_executable TARGET)
add_executable(${TARGET} ${ARGN})
if("c_std_99" IN_LIST CMAKE_C_COMPILE_FEATURES)
target_compile_features(${TARGET} PRIVATE c_std_99)
endif()
target_compile_definitions(${TARGET}
PRIVATE
$<TARGET_PROPERTY:${sdl3_mixer_target_name},COMPILE_DEFINITIONS>
)
sdl_add_warning_options(${TARGET} WARNING_AS_ERROR ${SDLMIXER_WERROR})
target_link_libraries(${TARGET} PRIVATE SDL3_mixer::SDL3_mixer SDL3::SDL3)
if(SDLMIXER_TESTS_INSTALL)
install(
TARGETS ${TARGET}
DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/${PROJECT_NAME}"
)
if(MSVC)
SDL_install_pdb("${TARGET}" "${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/${PROJECT_NAME}")
endif()
endif()
endfunction()
add_sdl_mixer_test_executable(testaudiodecoder testaudiodecoder.c)
add_sdl_mixer_test_executable(testmixer testmixer.c)
add_sdl_mixer_test_executable(testspatialization testspatialization.c)
if(SDLMIXER_TESTS_INSTALL)
install(
FILES ${RESOURCE_FILES}
DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/${PROJECT_NAME}"
)
endif()
+108
View File
@@ -0,0 +1,108 @@
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "SDL3_mixer/SDL_mixer.h"
static bool done = false;
static SDL_AudioSpec spec;
static void SDLCALL AudioDeviceCallback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount)
{
MIX_AudioDecoder *audiodecoder = (MIX_AudioDecoder *) userdata;
if (!additional_amount) {
return;
}
Uint8 buffer[1024];
while (additional_amount > 0) {
const int needed = SDL_min((int)sizeof(buffer), additional_amount);
const int br = MIX_DecodeAudio(audiodecoder, buffer, needed, &spec);
if (br <= 0) {
done = true;
break;
}
SDL_PutAudioStreamData(stream, buffer, br);
additional_amount -= br;
}
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_SetAppMetadata("Test SDL_mixer MIX_AudioDecoder", "1.0", "org.libsdl.testmixeraudiodecoder");
/* this doesn't have to run very much, so give up tons of CPU time between iterations. */
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
if (argc != 2) {
SDL_Log("USAGE: %s <file_to_play>", argv[0]);
return SDL_APP_FAILURE;
} else if (!SDL_Init(SDL_INIT_AUDIO)) {
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
} else if (!MIX_Init()) {
SDL_Log("Couldn't initialize SDL_mixer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
const char *audiofname = argv[1];
MIX_AudioDecoder *audiodecoder = MIX_CreateAudioDecoder(audiofname, 0);
if (!audiodecoder) {
SDL_Log("Failed to create audiodecoder for '%s': %s", audiofname, SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AudioStream *stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL, AudioDeviceCallback, audiodecoder);
if (!stream) {
SDL_Log("Failed to open audio device: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_GetAudioStreamFormat(stream, &spec, NULL);
SDL_ResumeAudioStreamDevice(stream);
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
return done ? SDL_APP_SUCCESS : SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
// SDL will clean up the audio device for us.
MIX_Quit(); // SDL_mixer will clean up the audiodecoder.
}
+353
View File
@@ -0,0 +1,353 @@
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
PLEASE NOTE THAT THE CODE IN THIS FILE IS ATROCIOUS, DON'T USE IT AS A
FOUNDATION FOR YOUR OWN PROGRAMS.
This is mostly just meant to test various things in quick-and-dirty ways.
I might delete it later.
I strongly recommend you use the programs in the "examples" directory to
get started. You can see them running in your web browser at:
https://examples.libsdl.org/SDL3_mixer/
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "SDL3_mixer/SDL_mixer.h"
#define USE_MIX_GENERATE 0
#define TEST_TAGS 0
//static SDL_Window *window = NULL;
//static SDL_Renderer *renderer = NULL;
static MIX_Mixer *mixer = NULL;
static MIX_Track *track1 = NULL;
static MIX_Track *track2 = NULL;
#if USE_MIX_GENERATE
static SDL_IOStream *io = NULL;
#endif
static SDL_IOStream *ioraw = NULL;
static SDL_IOStream *iocooked = NULL;
static SDL_IOStream *iopostmix = NULL;
static void SDLCALL WritePCMCallback(void *userdata, MIX_Track *track, const SDL_AudioSpec *spec, float *pcm, int samples)
{
SDL_WriteIO((SDL_IOStream *) userdata, pcm, samples * sizeof (float));
}
static void SDLCALL WritePostmixPCMCallback(void *userdata, MIX_Mixer *mixer, const SDL_AudioSpec *spec, float *pcm, int samples)
{
WritePCMCallback(userdata, NULL, spec, pcm, samples);
}
static void LogMetadata(SDL_PropertiesID props, const char *name)
{
switch (SDL_GetPropertyType(props, name)) {
case SDL_PROPERTY_TYPE_INVALID:
SDL_Log(" - %s [invalid type]", name);
break;
case SDL_PROPERTY_TYPE_POINTER:
SDL_Log(" - %s [pointer=%p]", name, SDL_GetPointerProperty(props, name, NULL));
break;
case SDL_PROPERTY_TYPE_STRING:
SDL_Log(" - %s [string=\"%s\"]", name, SDL_GetStringProperty(props, name, ""));
break;
case SDL_PROPERTY_TYPE_NUMBER:
SDL_Log(" - %s [number=%" SDL_PRIs64 "]", name, SDL_GetNumberProperty(props, name, 0));
break;
case SDL_PROPERTY_TYPE_FLOAT:
SDL_Log(" - %s [float=%f]", name, SDL_GetFloatProperty(props, name, 0.0f));
break;
case SDL_PROPERTY_TYPE_BOOLEAN:
SDL_Log(" - %s [boolean=%s]", name, SDL_GetBooleanProperty(props, name, false) ? "true" : "false");
break;
default:
SDL_Log(" - %s [unknown type]", name);
break;
}
}
typedef struct MetadataKeys
{
char **keys;
size_t num_keys;
} MetadataKeys;
static void SDLCALL CollectMetadata(void *userdata, SDL_PropertiesID props, const char *name)
{
MetadataKeys *mkeys = (MetadataKeys *) userdata;
char *key = SDL_strdup(name);
if (key) {
void *ptr = SDL_realloc(mkeys->keys, (mkeys->num_keys + 1) * sizeof (*mkeys->keys));
if (!ptr) {
SDL_free(key);
} else {
mkeys->keys = (char **) ptr;
mkeys->keys[mkeys->num_keys++] = key;
}
}
}
static int SDLCALL CompareMetadataKeys(const void *a, const void *b)
{
return SDL_strcmp(*(const char **) a, *(const char **) b);
}
#if TEST_TAGS
static void showtags(MIX_Track *track, const char *when)
{
int count;
char **tags = MIX_GetTrackTags(track, &count);
if (!tags) {
SDL_Log("GETTRACKTAGS FAILED! %s", SDL_GetError());
return;
}
SDL_Log("Track tags %s (%d):", when, count);
for (int i = 0; i < count; i++) {
SDL_Log(" - %s", tags[i]);
}
SDL_assert(tags[count] == NULL);
SDL_free(tags);
}
#endif
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_SetAppMetadata("Test SDL_mixer", "1.0", "org.libsdl.testmixer");
#if USE_MIX_GENERATE
const SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 48000 };
#endif
if ((argc != 2) && (argc != 3)) {
SDL_Log("USAGE: %s <file_to_play1> [file_to_play2]", argv[0]);
return SDL_APP_FAILURE;
} else if (!SDL_Init(SDL_INIT_VIDEO)) { // it's safe to SDL_INIT_AUDIO, but MIX_Init will do it for us.
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
} else if (!MIX_Init()) {
SDL_Log("Couldn't initialize SDL_mixer: %s", SDL_GetError());
return SDL_APP_FAILURE;
// } else if (!SDL_CreateWindowAndRenderer("testmixer", 640, 480, 0, &window, &renderer)) {
// SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
// return SDL_APP_FAILURE;
#if USE_MIX_GENERATE
} else if ((io = SDL_IOFromFile("dump.raw", "wb")) == NULL) {
SDL_Log("Couldn't create dump.raw: %s", SDL_GetError());
return SDL_APP_FAILURE;
} else if ((mixer = MIX_CreateMixer(&spec)) == NULL) {
#else
} else if ((mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL)) == NULL) {
#endif
SDL_Log("Couldn't create mixer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AudioSpec mixerspec;
MIX_GetMixerFormat(mixer, &mixerspec);
SDL_Log("Mixer is format %s, %d channels, %d frequency", SDL_GetAudioFormatName(mixerspec.format), mixerspec.channels, mixerspec.freq);
SDL_Log("Available decoders:");
const int num_decoders = MIX_GetNumAudioDecoders();
if (num_decoders < 0) {
SDL_Log(" - [error (%s)]", SDL_GetError());
} else if (num_decoders == 0) {
SDL_Log(" - [none]");
} else {
for (int i = 0; i < num_decoders; i++) {
SDL_Log(" - %s", MIX_GetAudioDecoder(i));
}
}
SDL_Log("%s", "");
const char *audiofname = argv[1];
#if 1
MIX_Audio *audio = MIX_LoadAudio(mixer, audiofname, false);
#else
size_t databuffersize = 0;
void *databuffer = SDL_LoadFile(audiofname, &databuffersize);
if (!databuffer) {
SDL_Log("Failed to load file '%s' from disk: %s", audiofname, SDL_GetError());
return SDL_APP_FAILURE;
}
MIX_Audio *audio = MIX_LoadAudioNoCopy(mixer, databuffer, databuffersize, true);
#endif
//MIX_Audio *audio = MIX_CreateSineWaveAudio(mixer, 300, 0.25f, 5000);
if (!audio) {
SDL_Log("Failed to load '%s': %s", audiofname, SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_AudioSpec audiospec;
MIX_GetAudioFormat(audio, &audiospec);
SDL_Log("%s: %s, %d channel%s, %d freq", audiofname, SDL_GetAudioFormatName(audiospec.format), audiospec.channels, (audiospec.channels == 1) ? "" : "s", audiospec.freq);
SDL_Log("%s metadata:", audiofname);
SDL_PropertiesID props = MIX_GetAudioProperties(audio);
bool had_metadata = false;
if (props) {
MetadataKeys mkeys;
SDL_zero(mkeys);
SDL_EnumerateProperties(props, CollectMetadata, &mkeys);
if (mkeys.num_keys > 0) {
SDL_qsort(mkeys.keys, mkeys.num_keys, sizeof (*mkeys.keys), CompareMetadataKeys);
for (size_t i = 0; i < mkeys.num_keys; i++) {
LogMetadata(props, mkeys.keys[i]);
SDL_free(mkeys.keys[i]);
had_metadata = true;
}
}
SDL_free(mkeys.keys);
}
if (!had_metadata) {
SDL_Log(" - [none]");
}
SDL_Log("%s", "");
track1 = MIX_CreateTrack(mixer);
//ioraw = SDL_IOFromFile("trackraw.raw", "wb"); if (ioraw) { MIX_SetTrackRawCallback(track1, WritePCMCallback, ioraw); }
//iocooked = SDL_IOFromFile("trackcooked.raw", "wb"); if (iocooked) { MIX_SetTrackCookedCallback(track1, WritePCMCallback, iocooked); }
//iopostmix = SDL_IOFromFile("postmix.raw", "wb"); if (iopostmix) { MIX_SetPostMixCallback(mixer, WritePostmixPCMCallback, iopostmix); }
(void) WritePostmixPCMCallback; // stop a compiler warning when not using the callbacks.
//const int chmap[] = { 1, 0 }; MIX_SetTrackOutputChannelMap(track1, chmap, SDL_arraysize(chmap));
MIX_SetTrackAudio(track1, audio);
if (argv[2]) {
track2 = MIX_CreateTrack(mixer);
MIX_SetTrackIOStream(track2, SDL_IOFromFile(argv[2], "rb"), true);
}
SDL_PropertiesID options;
#if TEST_TAGS
MIX_TagTrack(track1, "Abc");
MIX_TagTrack(track1, "xyZ");
MIX_TagTrack(track1, "1234567890");
MIX_TagTrack(track1, "TopSecret");
MIX_TagTrack(track1, "MyFavoriteTrack");
MIX_TagTrack(track1, "Can I put spaces and punctuation in here?");
MIX_TagTrack(track1, "Music");
MIX_TagTrack(track1, "NotImportant");
MIX_TagTrack(track1, "Orange");
int tagged_count = 77;
MIX_Track **tagged = MIX_GetTaggedTracks(mixer, "TopSecret", &tagged_count);
SDL_Log("MIX_GetTaggedTracks is %sworking", (tagged && (tagged_count == 1) && (tagged[0] == track1) && (tagged[1] == NULL)) ? "" : "NOT ");
SDL_free(tagged);
showtags(track1, "at startup");
MIX_UntagTrack(track1, "TopSecret");
showtags(track1, "after removing 'TopSecret'");
MIX_UntagTrack(track1, NULL);
showtags(track1, "after removing everything");
#endif
options = SDL_CreateProperties();
SDL_SetNumberProperty(options, MIX_PROP_PLAY_MAX_MILLISECONDS_NUMBER, 9440);
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, 3);
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOP_START_MILLISECOND_NUMBER, 6097);
SDL_SetNumberProperty(options, MIX_PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER, 30000);
//SDL_SetFloatProperty(options, MIX_PROP_PLAY_FADE_IN_START_GAIN_FLOAT, 0.25f);
SDL_SetNumberProperty(options, MIX_PROP_PLAY_APPEND_SILENCE_MILLISECONDS_NUMBER, 30000);
MIX_PlayTrack(track1, options);
SDL_DestroyProperties(options);
if (track2) {
options = SDL_CreateProperties();
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, -1);
MIX_PlayTrack(track2, options);
SDL_DestroyProperties(options);
}
// we cheat here with PlayAudio, since the sinewave decoder produces infinite audio.
//MIX_PlayAudio(mixer, MIX_CreateSineWaveAudio(mixer, 300, 0.25f, -1));
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS;
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
#if USE_MIX_GENERATE
float buf[1024];
const int br = MIX_Generate(mixer, buf, sizeof (buf));
if (br == -1) {
SDL_Log("MIX_Generate failed: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
//SDL_Log("MIX_Generate() came through with %d bytes vs %d requested", br, (int) sizeof (buf));
SDL_WriteIO(io, buf, br);
#endif
// SDL_RenderClear(renderer);
// SDL_RenderPresent(renderer);
#if 0
float ratio = ((float) ((((Sint64) SDL_GetTicks()) - 1000) / 1000)) * 0.10f;
ratio = SDL_clamp(ratio, 0.1f, 5.0f);
static float prev_ratio = 1.0f;
if (ratio != prev_ratio) {
SDL_Log("new frequency ratio: %f", ratio);
MIX_SetTrackFrequencyRatio(track1, ratio);
prev_ratio = ratio;
}
#endif
return MIX_TrackPlaying(track1) ? SDL_APP_CONTINUE : SDL_APP_SUCCESS;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
// SDL will clean up the window/renderer for us.
// SDL_mixer will clean up the tracks and audio.
MIX_Quit();
if (ioraw) { SDL_CloseIO(ioraw); }
if (iocooked) { SDL_CloseIO(iocooked); }
if (iopostmix) { SDL_CloseIO(iopostmix); }
#if USE_MIX_GENERATE
SDL_CloseIO(io);
#endif
}
+159
View File
@@ -0,0 +1,159 @@
/*
SDL_mixer: An audio mixer library based on the SDL library
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include "SDL3_mixer/SDL_mixer.h"
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static MIX_Mixer *mixer = NULL;
static MIX_Track *track = NULL;
static bool autopilot = true;
static bool mouse_down = false;
static float mouse_x, mouse_y;
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_SetAppMetadata("Test SDL_mixer spatialization", "1.0", "org.libsdl.testmixerspatialization");
if (argc != 2) {
SDL_Log("USAGE: %s <file_to_play>", argv[0]);
return SDL_APP_FAILURE;
} else if (!SDL_Init(SDL_INIT_VIDEO)) { // it's safe to SDL_INIT_AUDIO, but MIX_Init will do it for us.
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
} else if (!MIX_Init()) {
SDL_Log("Couldn't initialize SDL_mixer: %s", SDL_GetError());
return SDL_APP_FAILURE;
} else if (!SDL_CreateWindowAndRenderer("testmixer", 640, 480, 0, &window, &renderer)) {
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
} else if ((mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL)) == NULL) {
SDL_Log("Couldn't create mixer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
const char *audiofname = argv[1];
MIX_Audio *audio = MIX_LoadAudio(mixer, audiofname, false);
if (!audio) {
SDL_Log("Failed to load '%s': %s", audiofname, SDL_GetError());
return SDL_APP_FAILURE;
}
track = MIX_CreateTrack(mixer);
MIX_SetTrackAudio(track, audio);
SDL_PropertiesID options = SDL_CreateProperties();
SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, -1);
MIX_PlayTrack(track, options);
SDL_DestroyProperties(options);
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS;
} else if ((event->type == SDL_EVENT_KEY_DOWN) && (event->key.key == SDLK_ESCAPE)) {
return SDL_APP_SUCCESS;
} else if ((event->type == SDL_EVENT_KEY_DOWN) && (event->key.key == SDLK_A)) {
autopilot = true;
} else if ((event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) && (event->button.button == 1)) {
mouse_down = true;
} else if ((event->type == SDL_EVENT_MOUSE_BUTTON_UP) && (event->button.button == 1)) {
autopilot = false;
mouse_down = false;
} else if (event->type == SDL_EVENT_MOUSE_MOTION) {
if (mouse_down) {
autopilot = false;
mouse_x = event->motion.x;
mouse_y = event->motion.y;
}
}
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
const Uint64 period = 5000;
const float moment = ((float) (SDL_GetTicks() % period)) / ((float) period); // moment in the time period, from 0.0f to 1.0f
const float angle = moment * 2.0f * SDL_PI_F; // angle on the circle for this moment, in radians.
static const SDL_FPoint center = { 640.0f / 2.0f, 480.0f / 2.0f };
const float radius = 200.0f; // size of half the circle (radius, not diameter).
const float boxsize = 30.0f;
SDL_FPoint sourcept;
MIX_Point3D position;
position.y = 0.0f; // always horizontal.
if (autopilot) { // run in a horizontal circle around the listener (circling on X and Z coordinates).
position.x = SDL_cosf(angle);
position.z = SDL_sinf(angle);
sourcept.x = center.x + (position.x * radius);
sourcept.y = center.y + (position.z * radius);
} else {
position.x = (((mouse_x / 640.0f) * 2.0f) - 1.0f); // scale to -1.0f to 1.0f
position.z = (((mouse_y / 480.0f) * 2.0f) - 1.0f);
sourcept.x = mouse_x - (boxsize / 2.0f);
sourcept.y = mouse_y - (boxsize / 2.0f);
}
#if 0
const float scale = 3.0f;
position.x *= scale; // make distance attenuation noticable.
position.z *= scale;
MIX_SetTrack3DPosition(track, &position);
#else
const float right = (position.x + 1.0f) / 2.0f; // move to 0.0f - 1.0f.
const MIX_StereoGains gains = { 1.0f - right, right };
MIX_SetTrackStereo(track, &gains);
#endif
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
const SDL_FRect source_rect = { sourcept.x, sourcept.y, boxsize, boxsize };
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderFillRect(renderer, &source_rect);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, source_rect.x + ((boxsize - 48.0f) / 2.0f), source_rect.y + boxsize, "SOURCE");
const SDL_FRect listener_rect = { center.x, center.y, boxsize, boxsize };
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderFillRect(renderer, &listener_rect);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, listener_rect.x + ((boxsize - 64.0f) / 2.0f), listener_rect.y + boxsize, "LISTENER");
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
// SDL will clean up the window/renderer for us.
// SDL_mixer will clean up the tracks and audio.
MIX_Quit();
}