c++sdlsdl-mixer

SDL2 pause sound using SDL_Mixer so it can be resumed


I am writing this after I found the solution but I thought it could be useful for documentation / future projects.

I am working on implementing a class for managing sounds in SDL2 and decided to use SDL_Mixer. The class seems to work fine (provided below) and I can play and stop sounds but the desired behavior is for the stopSound() to pause the sound at its current location so when I play the same sound it will resume where I stopped it. Most of the documentation I have looked at seems to use: Mix_HaltChannel(-1); but if I understand the documentation correctly it STOPS the sound which means you would need to replay the sound from the beginning.

#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <unordered_map>
#include <string>

class SoundManager {
    // For storing sounds
    std::unordered_map<std::string, Mix_Chunk*> m_soundMap;

    SoundManager() {
        // Initialize SDL audio subsystem
        if (SDL_Init(SDL_INIT_AUDIO) < 0) {
            printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
        }
    
        // Initialize SDL_mixer
        if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
            printf("SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError());
        }
    }

    ~SoundManager() {
        for (auto& pair : m_soundMap) {
            Mix_FreeChunk(pair.second);
        }
        m_soundMap.clear();
    
        Mix_Quit();
        SDL_Quit();
    }

    void loadSound(const char* filePath, const char* soundKey) {
        Mix_Chunk* chunk = loadChunk(filePath);
        if (chunk == nullptr) {
            return false;
        }
    
        m_soundMap[soundKey] = chunk;
        return true;
    }

    void playSound(const char* soundKey, int loops) {
        auto it = m_soundMap.find(soundKey);
        if (it != m_soundMap.end()) {
            Mix_PlayChannel(-1, it->second, loops);
        }
    }
    
    void stopSound(const char* soundKey) {
        auto it = m_soundMap.find(soundKey);
        if (it != m_soundMap.end()) {
            Mix_HaltChannel(-1);
        }
    }

};

How can you properly pause a sound? I didn't find any relevant functions in the documentation here: https://wiki.libsdl.org/SDL2_mixer/Mix_PlayChannel.

NOTE: I realize the sound class is incomplete and pauses all channels using -1 but this is about the general concept of pausing / resuming.

Related SO posts(?):
SDL_mixer stop playing music on certain event
Mix_Halt specific tracks?


Solution

  • I realize the problem was my understanding of how to properly play / resume sounds using SDL_Mixer. By diving deeper into the documentation I found that you can use the following documentation links:

    https://wiki.libsdl.org/SDL2_mixer/Mix_Resume
    https://wiki.libsdl.org/SDL2_mixer/Mix_Pause

    for pausing and resuming the sound. In my implementation in the question this would look something like:

    // SoundManager
    void playSound() {
        Mix_Resume(-1);  // The -1 means resume all channels
    }
    
    void stopSound() {
        Mix_Pause(-1);
    }