Как отобразить текущую музыкальную позицию с помощью FMOD и C ++? - PullRequest
1 голос
/ 22 апреля 2019

Я хочу отображать время, прошедшее при воспроизведении музыки в режиме реального времени.Базовый API FMOD обеспечивает функцию Channel::getPosition() для получения текущей позиции в миллисекундах.Я хочу обновлять позицию каждую секунду.

Я новичок и не знаю многопоточного программирования.

Я вызываю Channel::getPosition() в цикле и использую std::this_thread::sleep_for(), чтобы задержать циклза одну секунду до следующей итерации.

Вот код:

unsigned int position = 0;
std::chrono::milliseconds timespan(1000);
while(true) {
    channel -> getPosition(&position, FMOD_TIMEUNIT_MS);
    std::cout << postion / 1000 << "\n"; //Display seconds
    std::this_thread::sleep_for(timespan);
}

Тем не менее, я получаю некоторые ошибки:

0
1
...
13
13
14
16
...

13 появляется дважды и 15даже не появляется.В другом случае дважды появляется число 5.

Я думаю о округлении в большую или меньшую сторону числа, полученного из Channel::getPosition(), чтобы исправить вывод.

Как это исправить?

Примечание: Проверка ошибок для простоты опущена

Ответы [ 2 ]

1 голос
/ 22 апреля 2019
  1. Используйте <chrono> даже для тривиальных функций синхронизации.

  2. Используйте функцию C ++ 17 round для сокращения миллисекунд до секунд в этом примере.Если у вас нет C ++ 17, украдите round из здесь .

  3. Используйте sleep_until вместо sleep_for, чтобы сохранитьболее точный «временной интервал» для каждой итерации цикла.

Собираем все вместе:

#include <chrono>
#include <iostream>
#include <memory>
#include <thread>

enum unit{FMOD_TIMEUNIT_MS};

struct Channel
{
    void getPosition(unsigned int* position, unit)
    {
        using namespace std::chrono;
        static auto start = steady_clock::now();
        *position = duration_cast<milliseconds>(steady_clock::now()-start).count();
    } 
};

int
main()
{
    using namespace std::chrono;
    auto channel = std::make_unique<Channel>();
    auto constexpr timespan = 1s;
    auto next_start = system_clock::now() + timespan;
    while (true)
    {
        unsigned int position_as_integral;
        channel->getPosition(&position_as_integral, FMOD_TIMEUNIT_MS);
        milliseconds position{position_as_integral};
        std::cout << round<seconds>(position).count() << '\n';
        std::this_thread::sleep_until(next_start);
        next_start += timespan;
    }
}
1 голос
/ 22 апреля 2019

Проблема, с которой вы столкнулись, состоит в том, что position / 1000 округляется до ближайшего целого числа, и std::this_thread::sleep_for не гарантированно спит ровно в указанное вами время, поэтому вы можете получить дубликат или пропустить его.

Попробуйте вместо этого:

unsigned int position = 0;
std::chrono::milliseconds timespan(100);
unsigned last_sec = 0x7fffffff;

while(true) {
    channel -> getPosition(&position, FMOD_TIMEUNIT_MS);
    unsigned sec = position / 1000;
    if (sec != last_sec)
    {
        std::cout << sec << "\n"; //Display seconds
        last_sec = sec;
    }
    std::this_thread::sleep_for(timespan);
}
...