最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - When i resume FMOD Studio instance from pause, song position shift a little bit - Stack Overflow

programmeradmin2浏览0评论

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 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)

  1. 暂无评论