SDL3 & OpenGL: Audio Playback with SDL3_mixer SDL3 и OpenGL: Воспроизведение аудио с помощью SDL3_mixer

A guide to setting up and using SDL3_mixer 3.2.2 within an OpenGL 3.3 and MinGW development pipeline to handle music and sound effects. Руководство по настройке и использованию SDL3_mixer 3.2.2 в связке с OpenGL 3.3 и MinGW для управления фоновой музыкой и звуковыми эффектами.

2. Obtain SDL3_mixer 3.2.2 2. Получение SDL3_mixer 3.2.2

3. Add SDL3_mixer to Environment Variables (Path) 3. Добавление SDL3_mixer в переменные среды (Path)

To ensure your applications can find the SDL3_mixer.dll file at runtime along with its decoding backends, add the following path to the Path variable in your User variables section: Чтобы приложения могли находить файл SDL3_mixer.dll и встроенные декодеры при запуске, добавьте следующий путь в переменную Path в разделе Переменные среды пользователя:

C:\libs\SDL3_mixer-3.2.2-win32-x64

4. Obtain cglm 4. Получение cglm

5. Project Structure and Assets 5. Структура проекта и ресурсы

Before creating the files, download the required asset: Перед созданием файлов скачайте необходимый ресурс:

C Project: Create an empty folder named audio-sdl3-mixer-opengl-mingw-c and set up the following hierarchy by creating new CMakeLists.txt and main.c files:

Проект на C: Создайте пустую папку с именем audio-sdl3-mixer-opengl-mingw-c и подготовьте следующую иерархию, создав файлы CMakeLists.txt и main.c:

audio-sdl3-mixer-opengl-mingw-c/
├── CMakeLists.txt
├── assets/audio/
│   └── Picked Coin Echo 2.wav
│   └── Winds Of Stories.ogg
└── src/
    └── main.c

C++ Project: Create an empty folder named audio-sdl3-mixer-opengl-mingw-cpp and set up the following hierarchy by creating new CMakeLists.txt and main.cpp files:

Проект на C++: Создайте пустую папку с именем audio-sdl3-mixer-opengl-mingw-cpp и подготовьте следующую иерархию, создав файлы CMakeLists.txt и main.cpp:

audio-sdl3-mixer-opengl-mingw-cpp/
├── CMakeLists.txt
├── assets/audio/
│   └── Picked Coin Echo 2.wav
│   └── Winds Of Stories.ogg
└── src/
    └── main.cpp

6. CMake Configuration 6. Конфигурация CMake

C Project: Copy and paste the following code into the CMakeLists.txt file:

Проект на C: Скопируйте и вставьте следующее содержимое в файл CMakeLists.txt:

set(CMAKE_BUILD_TYPE "Debug")
cmake_minimum_required(VERSION 3.21)
project(audio-sdl3-mixer-opengl-mingw-c)

set(SDL3_DIR "C:/libs/SDL3-devel-3.4.8-mingw/lib/cmake/SDL3")
set(SDL3_mixer_DIR "C:/libs/SDL3_mixer-devel-3.2.2-mingw/lib/cmake/SDL3_mixer")

find_package(SDL3 REQUIRED)
find_package(SDL3_mixer REQUIRED)

add_executable(app)

target_sources(app PRIVATE
    C:/libs/glad-0.1.36/opengl-3.3/src/glad.c
    src/main.c
)

target_include_directories(app PRIVATE C:/libs/glad-0.1.36/opengl-3.3/include)

# Copy the assets folder to the dist folder
if(EXISTS "${CMAKE_SOURCE_DIR}/assets")
    add_custom_command(TARGET app POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
                "${CMAKE_SOURCE_DIR}/assets"
                "$<TARGET_FILE_DIR:app>/assets"
        COMMENT "Copying assets directory"
    )
endif()

target_link_libraries(app PRIVATE SDL3_mixer::SDL3_mixer SDL3::SDL3)
target_link_options(app PRIVATE -mconsole)

C++ Project: Copy and paste the following code into the CMakeLists.txt file:

Проект на C++: Скопируйте и вставьте следующее содержимое в файл CMakeLists.txt:

set(CMAKE_BUILD_TYPE "Debug")
cmake_minimum_required(VERSION 3.21)
project(audio-sdl3-mixer-opengl-mingw-cpp)

set(SDL3_DIR "C:/libs/SDL3-devel-3.4.8-mingw/lib/cmake/SDL3")
set(SDL3_mixer_DIR "C:/libs/SDL3_mixer-devel-3.2.2-mingw/lib/cmake/SDL3_mixer")

find_package(SDL3 REQUIRED)
find_package(SDL3_mixer REQUIRED)

add_executable(app)

target_sources(app PRIVATE
    C:/libs/glad-0.1.36/opengl-3.3/src/glad.c
    src/main.cpp
)

target_include_directories(app PRIVATE C:/libs/glad-0.1.36/opengl-3.3/include)

# Copy the assets folder to the dist folder
if(EXISTS "${CMAKE_SOURCE_DIR}/assets")
    add_custom_command(TARGET app POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
                "${CMAKE_SOURCE_DIR}/assets"
                "$<TARGET_FILE_DIR:app>/assets"
        COMMENT "Copying assets directory"
    )
endif()

target_link_libraries(app PRIVATE SDL3_mixer::SDL3_mixer SDL3::SDL3)
target_link_options(app PRIVATE -mconsole)

7. Source Code 7. Исходный код

Copy and paste the following code into the src/main.c (or src/main.cpp) file. Рress Space to play the sound effect manually):

Скопируйте и вставьте следующее содержимое в файл src/main.c (или src/main.cpp). Нажмите Пробел для ручного воспроизведения звукового эффекта:

#define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()

#include <glad/glad.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <SDL3_mixer/SDL_mixer.h>

static SDL_Window *window = NULL;
static SDL_GLContext glContext;

static MIX_Mixer *mixer = NULL;
static MIX_Audio *backgroundMusic = NULL;
static MIX_Audio *soundEffect = NULL;
static MIX_Track *musicTrack = NULL;
static MIX_Track *sfxTrack = NULL;

static const size_t canvasWidth = 430;
static const size_t canvasHeight = 430;

// This function runs once at startup
SDL_AppResult SDL_AppInit(void **appState, int argc, char *argv[])
{
    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO))
    {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    // Initialize Mixer 3 subsystem
    if (!MIX_Init())
    {
        SDL_Log("Couldn't initialize SDL_mixer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    // Create the central Mixer Device
    mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
    if (!mixer)
    {
        SDL_Log("Mixer creation failed: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

    const char *title = "SDL3_mixer OpenGL";
    window = SDL_CreateWindow(title, canvasWidth, canvasHeight, SDL_WINDOW_OPENGL);
    if (!window)
    {
        SDL_Log("Couldn't create the window: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    glContext = SDL_GL_CreateContext(window);
    if (!glContext)
    {
        SDL_Log("Couldn't create the glContext: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    SDL_GL_SetSwapInterval(1); // Turn on vertical sync

    if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
    {
        SDL_Log("Failed to initialize OpenGL function pointers");
        return SDL_APP_FAILURE;
    }

    glClearColor(0.15f, 0.15f, 0.18f, 1.0f);

    // Load Audio Objects (using 'true' to cache data in memory)
    backgroundMusic = MIX_LoadAudio(mixer, "assets/audio/Winds Of Stories.ogg", true);
    if (!backgroundMusic)
    {
        SDL_Log("Failed to load music: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    soundEffect = MIX_LoadAudio(mixer, "assets/audio/Picked Coin Echo 2.wav", true);
    if (!soundEffect)
    {
        SDL_Log("Failed to load sound effect: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    // Allocate dedicated playback tracks
    musicTrack = MIX_CreateTrack(mixer);
    sfxTrack = MIX_CreateTrack(mixer);
    if (!musicTrack || !sfxTrack)
    {
        SDL_Log("Failed to create playback tracks");
        return SDL_APP_FAILURE;
    }

    // Setup and stream background music infinitely
    MIX_SetTrackAudio(musicTrack, backgroundMusic);
    MIX_SetTrackLoops(musicTrack, -1); // -1 loops infinitely, 0 disables looping
    MIX_PlayTrack(musicTrack, -1); 

    return SDL_APP_CONTINUE;
}

// This function runs when a new event occurs
SDL_AppResult SDL_AppEvent(void *appState, SDL_Event *event)
{
    switch (event->type)
    {
        case SDL_EVENT_QUIT:
            return SDL_APP_SUCCESS;
        case SDL_EVENT_KEY_DOWN:
            if (event->key.key == SDLK_SPACE)
            {
                // Instantly bind and fire the one-shot sound effect (0 additional loops)
                MIX_SetTrackAudio(sfxTrack, soundEffect);
                MIX_PlayTrack(sfxTrack, 0);
            }
            break;
        default:
            break;
    }
    return SDL_APP_CONTINUE;
}

// This function runs once per frame
SDL_AppResult SDL_AppIterate(void *appState)
{
    glClear(GL_COLOR_BUFFER_BIT);

    // Context rendering logic goes here (OpenGL 3.3 pipeline)

    SDL_GL_SwapWindow(window);
    return SDL_APP_CONTINUE;
}

// This function runs once at shutdown
void SDL_AppQuit(void *appState, SDL_AppResult result)
{
    /* 
       In SDL_mixer 3, MIX_Quit() handles garbage collection, freeing
       all mixer devices, loaded audio chunks, and track configurations automatically.
    */
    MIX_Quit();

    SDL_GL_DestroyContext(glContext);
    SDL_DestroyWindow(window);
    SDL_Quit();
}

8. Opening the Project in IDEs 8. Открытие проекта в IDE

Open the CMakeLists.txt file in CLion or Qt Creator. CMake will handle the configuration automatically. Откройте файл CMakeLists.txt в CLion или Qt Creator. CMake позаботится об остальном конфигурационном процессе автоматически.

9. Automation Scripts (.bat) 9. Скрипты автоматизации (.bat)

You can open the project folder in Sublime Text 4. Create the following .bat scripts in the project root directory to automate building and running:

Вы можете открыть папку проекта в Sublime Text 4. Создайте следующие .bat скрипты в корневой директории проекта для автоматизации сборки и запуска:

1. config-exe.bat
cmake -G "MinGW Makefiles" -S . -B dist/exe
2. build-exe.bat
cd dist\exe
cmake --build .
cd ..\..
3. run-exe.bat
dist\exe\app

To build and launch the application, run these scripts in the terminal in the following order:

Чтобы собрать и запустить приложение, выполните эти скрипты в терминале в следующем порядке:

config-exe
build-exe
run-exe

10. Source Code & Downloads 10. Исходный код и загрузки

You can download the complete configured project as a ZIP archive or explore the source code directly on GitHub: Вы можете скачать готовую настроенную сборку проекта в виде ZIP-архива или изучить исходный код прямо на GitHub:


Support My Work Поддержать проект

If these tutorials helped you, consider buying me a coffee! Если эти туториалы вам помогли, вы можете поддержать автора.

Sberbank

Sberbank SBP QR Code

Direct transfer via phone number Перевод по номеру телефона

+7 (917) 212-29-59

Bybit (USDT TRC20)

Bybit USDT TRC20 QR Code

Support via Cryptocurrency Поддержка криптовалютой

TMtY1YifNf6FKvgeFmqKGQR4NStKr3csGp