1

I'm using FMOD Studio with banks in my project, and I've encountered an issue when pausing and resuming audio. I load my audio as a bank event (i.e., an FMOD Studio Event Instance) and use the setPaused(true) method to pause the audio. However, while the audio is paused, the event's internal timeline continues advancing. This means that when I unpause the event, the playback position jumps ahead (e.g., from 100 ms to 150 ms), even though the audio was supposed to be paused.

Here's what's happening: The song's position is displayed in the top left corner. When I press pause at 2241ms and then resume, the song position jumps back to around ~200ms

Here's what's happening: The song's position is displayed in the top left corner. When I press pause at 2241ms and then resume, the song position jumps back to around 200ms

Here the code from App.cpp:

#include "pch.hpp"

#define RAYGUI_IMPLEMENTATION
#include "include/raygui.h"
#include "raymath.h"

#include "include/App.hpp"
#include "include/Audio.hpp"
#include "include/Constants.hpp"
#include "include/Conductor.hpp"

#include "fmod.hpp"

bool paused = true;
bool songLoad = false;

int columFuck = 0;

App::App(unsigned int Width, unsigned int Height, const std::string& title)
{
    InitWindow(Width, Height, title.c_str());
    SetTargetFPS(60);

    Audio::Init();

    Conductor::Init(77, 4, 4, Constants::SoundPath + "Episode Songs.bank", "e1-s1");

    columFuck = static_cast<int>(std::ceil(Conductor::SongMaxLenght / (Conductor::MSPerBeat / 4.0f)));

    m_LinePosition = 100.f;

    m_MainCamera.target = { 0.f, m_LinePosition };
    m_MainCamera.rotation = 0.f;
    m_MainCamera.zoom = 1.f;
    m_MainCamera.offset = { 0.f , 100.f };
}

void App::Update()
{
    Audio::Update();
    Conductor::Update();

    if(IsKeyPressed(KEY_SPACE))
    {
        paused = !paused;
        Conductor::SetPause(paused);
    }

    m_MainCamera.target = { 0.f, m_LinePosition };

    if (IsKeyPressed('Q'))
        Conductor::SetPosition(Conductor::SongMaxLenght - 2000);

    if (Conductor::SongPosition >= Conductor::SongMaxLenght - 1)
        Conductor::SetPosition(Conductor::SongMaxLenght);

    if (IsKeyPressed(KEY_ENTER))
        Conductor::SetPosition(0);

    float cellDuration = Conductor::MSPerBeat / 4.0f;
    float cell = Conductor::SongPosition / cellDuration;
    m_LinePosition = 100.f + (cell * Constants::GridHeight);
}

void App::Draw()
{
    BeginDrawing();

        BeginMode2D(m_MainCamera);

            ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));

            for (int j = 0; j < Constants::MaxColumns; j++)
            {
                for (size_t i = 0; i < columFuck; i++)
                {
                    Color c = (i + j) % 2 == 0 ? BLACK : GRAY;

                    DrawRectangle(100 + (Constants::GridWidth * j), 100 + (Constants::GridHeight * i), Constants::GridWidth, Constants::GridHeight, c);
                }
            }


        EndMode2D();

        std::string Pos = std::to_string(Conductor::SongPosition) + "/" + std::to_string(Conductor::SongMaxLenght);

        DrawLineEx({ 50, 100 }, { 500, 100 }, 2, RED);
        DrawText(Pos.c_str(), 0, 0, 24, ORANGE);

    EndDrawing();
}

Audio.cpp:

#include "pch.hpp"
#include "include/Audio.hpp"

#include "include/ResourceManager.hpp"
#include "include/Constants.hpp"

#include <fmod_studio.hpp>
#include <fmod_errors.h>

void ERRCHECK_fn(FMOD_RESULT result, const char* file, int line);
#define ERRCHECK(_result) ERRCHECK_fn(_result, __FILE__, __LINE__)

FMOD::Studio::System*   Audio::fmodSys = nullptr;
FMOD::System*           Audio::fmodSysLow = nullptr;

FMOD::Studio::Bank*     Audio::masterBank = nullptr;

bool                    Audio::m_masterBankLoaded = false;

void Audio::Init()
{
    ERRCHECK(FMOD::Studio::System::create(&fmodSys));
    ERRCHECK(fmodSys->initialize(512, FMOD_STUDIO_INIT_NORMAL, FMOD_INIT_NORMAL, 0));
    ERRCHECK(fmodSys->getCoreSystem(&fmodSysLow));
}

void Audio::StartSong(const std::string& path, const std::string& eventName)
{
    const std::string fileName = path.substr(path.find_last_of('/') + 1);
    const std::string fileNameNoExtension = fileName.substr(0 ,fileName.find('.'));
    const std::string fileExtension = fileName.substr(fileName.find('.') + 1);

    if (fileExtension != "bank" && ResourceManager::CheckIfChannelExsists(fileNameNoExtension) == false)
    {
        LoadSongLowLevel(path, fileNameNoExtension);
        FMOD::Channel* newChannel;
        ERRCHECK(fmodSysLow->playSound(ResourceManager::GetSound(fileNameNoExtension), nullptr, true, &newChannel));
        ResourceManager::LoadChannel(fileNameNoExtension, newChannel);
        ResourceManager::GetChannel(fileNameNoExtension)->setPaused(false);
    }
    
    if (fileExtension == "bank" && ResourceManager::CheckIfInstanceExsists(eventName) == false)
    {
        if (eventName == "")
        {
            std::cerr << "Event Name is empty put there something" << std::endl;
            return;
        }

        LoadSongHighLevel(path, eventName);
    }
}

void Audio::Pause(const std::string& songName, bool pause)
{
    if (auto* channel = ResourceManager::GetChannel(songName))
        ERRCHECK(channel->setPaused(pause));
    else if (auto* instance = ResourceManager::GetEventInstance(songName))
        ERRCHECK(instance->setPaused(pause));
    else
        std::cout << "Audio.cpp. Pause Function: There is no " << songName << " for pause" << std::endl;
}

unsigned int Audio::GetSongPosition(const std::string& songName)
{
    unsigned int pos;

    if (auto* channel = ResourceManager::GetChannel(songName))
        ERRCHECK(channel->getPosition(&pos, FMOD_TIMEUNIT_MS));
    else if (auto* instance = ResourceManager::GetEventInstance(songName))
    {
        int tmpPos;
        ERRCHECK(instance->getTimelinePosition(&tmpPos));
        pos = static_cast<unsigned int>(tmpPos);
    }
    else
    {
        std::cout << "There is no: " << songName << std::endl;
        return 0;
    }

    return pos;
}

unsigned int Audio::GetSongLength(const std::string& songName)
{
    unsigned int pos;

    if (auto* sound = ResourceManager::GetSound(songName))
        ERRCHECK(sound->getLength(&pos, FMOD_TIMEUNIT_MS));
    else if (auto* instance = ResourceManager::GetEventInstance(songName))
    {
        FMOD::Studio::EventDescription* envDesc;
        ERRCHECK(instance->getDescription(&envDesc));
        int tmpPos;
        ERRCHECK(envDesc->getLength(&tmpPos));
        pos = static_cast<unsigned int>(tmpPos);
    }
    else
    {
        std::cout << "There is no: " << songName << std::endl;
        return 0;
    }
        //channel->getPosition(&pos, FMOD_TIMEUNIT_MS
    return pos;
}

void Audio::SetPosition(const std::string& songName, unsigned int Position)
{
    if (auto* sound = ResourceManager::GetChannel(songName))
        ERRCHECK(sound->setPosition(Position, FMOD_TIMEUNIT_MS));
    else if (auto* instance = ResourceManager::GetEventInstance(songName))
        ERRCHECK(instance->setTimelinePosition(static_cast<int>(Position)));
    else
        std::cout << "There is no: " << songName << std::endl;
}

void Audio::Update()
{
    fmodSys->update();
}

void Audio::Destroy()
{
    masterBank->unload();
    fmodSys->release();
}

void ERRCHECK_fn(FMOD_RESULT result, const char* file, int line) {
    if (result != FMOD_OK)
        std::cout << "FMOD ERROR: Audio.cpp [Line " << line << "] " << result << "  - " << FMOD_ErrorString(result) << '\n';
}

void Audio::LoadSongLowLevel(const std::string& path, const std::string& SoundName)
{
    FMOD::Sound* sound;
    ERRCHECK(fmodSysLow->createSound(path.c_str(), FMOD_DEFAULT, nullptr, &sound));
    ResourceManager::LoadSound(SoundName, sound);
}

void Audio::LoadSongHighLevel(const std::string& path, const std::string& eventName)
{
    if (m_masterBankLoaded == false)
    {
        ERRCHECK(fmodSys->loadBankFile((Constants::SoundPath + "Master.bank").c_str(), FMOD_STUDIO_LOAD_BANK_NORMAL, &masterBank));
        ERRCHECK(fmodSys->loadBankFile((Constants::SoundPath + "Master.strings.bank").c_str(), FMOD_STUDIO_LOAD_BANK_NORMAL, &masterBank));
        m_masterBankLoaded = true;
    }

    ERRCHECK(fmodSys->loadBankFile(path.c_str(), FMOD_STUDIO_LOAD_BANK_NORMAL, &masterBank));

    FMOD::Studio::EventDescription* envDesc = nullptr;
    std::string event = "event:/" + eventName;

    ERRCHECK(fmodSys->getEvent(event.c_str(), &envDesc));

    FMOD::Studio::EventInstance* env = nullptr;
    ERRCHECK(envDesc->createInstance(&env));
    ERRCHECK(env->start());
    ResourceManager::LoadEventInstance(eventName, env);
}

Conductor.cpp:

#include "pch.hpp"
#include "include/Conductor.hpp"
#include "include/Audio.hpp"

int Conductor::m_TopNumber = 0;
int Conductor::m_BottomNumber = 0;
int Conductor::BPM = 0;
int Conductor::SongMaxLenght = 0;
int Conductor::SongPosition = 0;
int Conductor::SongPosInBeat = 0;

float Conductor::MSPerBeat = 0.f;

float Conductor::SongSpeed = 1.f;

std::string Conductor::m_songName = "";

bool Conductor::m_inPause = false;

void Conductor::Init(int bpm, int TopNum, int BottomNum, const std::string& SongPath, const std::string& evetName)
{
    BPM = bpm;
    m_TopNumber = TopNum;
    m_BottomNumber = BottomNum;

    if (evetName == "")
    {
        size_t startName = SongPath.find_last_of('/');
        std::string name = SongPath.substr(startName, SongPath.find_last_of('.') - startName);
        std::cout << name << std::endl;
        m_songName = name;
    }
    else
        m_songName = evetName;

    MSPerBeat = 60000.f / BPM;

    m_inPause = true;
    Audio::StartSong(SongPath, m_songName);
    Audio::Pause(m_songName, m_inPause);

    SongMaxLenght = Audio::GetSongLength(m_songName);
}

void Conductor::Update()
{
    if (m_inPause == false)
    {
        SongPosition = Audio::GetSongPosition(m_songName);
    }
}

void Conductor::SetPause(bool pause)
{
    m_inPause = pause;
    Audio::Pause(m_songName, m_inPause);
}

bool Conductor::GetPause()
{
    return m_inPause;
}

void Conductor::SetPosition(unsigned int Position)
{
    m_inPause = true;
    Audio::SetPosition(m_songName, Position);
    SongPosition = Position;
}

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.