如何使用 FMOD 和 C++ 显示当前音乐位置?
How to display current music position using FMOD and C++?
我想实时显示音乐播放经过的时间。
FMOD的核心API提供了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()
获得的数字四舍五入或四舍五入以更正输出。
我该如何解决这个问题?
注意:为简单起见省略了错误检查
您遇到的问题是 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);
}
使用 <chrono>
即使是微不足道的计时功能。
在此示例中,使用 C++17 round
函数将毫秒截断为秒。如果您没有 C++17,请从 here.
窃取 round
使用 sleep_until
而不是 sleep_for
以便在循环的每次迭代中保持更准确的 "timespan"。
综合起来:
#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;
}
}
我想实时显示音乐播放经过的时间。
FMOD的核心API提供了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()
获得的数字四舍五入或四舍五入以更正输出。
我该如何解决这个问题?
注意:为简单起见省略了错误检查
您遇到的问题是 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);
}
使用
<chrono>
即使是微不足道的计时功能。在此示例中,使用 C++17
round
函数将毫秒截断为秒。如果您没有 C++17,请从 here. 窃取 使用
sleep_until
而不是sleep_for
以便在循环的每次迭代中保持更准确的 "timespan"。
round
综合起来:
#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;
}
}