I'm trying to implement a MIDI-like clocked sample player.
There is a timer, which increments pulse counter, and every 480 pulses is a quarter, so pulse period is 1041667 ns for 120 beats per minute.
Timer is not sleep-based and running in separate thread, but it seems like delay time is inconsistent: period between samples played in a test file is fluctuating +- 20 ms (in some occasions period is OK and steady, I can't find out dependency of this effect).
Audio backend influence is excluded: i've tried OpenAL as well as SDL_mixer.
void Timer_class::sleep_ns(uint64_t ns){
auto start = std::chrono::high_resolution_clock::now();
bool sleep = true;
while(sleep)
{
auto now = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(now - start);
if (elapsed.count() >= ns) {
TestTime = elapsed.count();
sleep = false;
//break;
}
}
}
void Timer_class::Runner(void){
// this running as thread
while(1){
sleep_ns(BPMns);
if (Run) Transport.IncPlaybackMarker(); // marker increment
if (Transport.GetPlaybackMarker() == Transport.GetPlaybackEnd()){ // check if timer have reached end, which is 480 pulses
Transport.SetPlaybackMarker(Transport.GetPlaybackStart());
Player.PlayFile(1); // period of this event fluctuates severely
}
}
};
void Player_class::PlayFile(int FileNumber){
#ifdef AUDIO_SDL_MIXER
if(Mix_PlayChannel(-1, WaveData[FileNumber], 0)==-1) {
printf("Mix_PlayChannel: %s\n",Mix_GetError());
}
#endif // AUDIO_SDL_MIXER
}
Am i doing something wrong in terms of an approach? Is there any better way to implement timer of this kind?
Deviation higher than 4-5 ms is too much in case of audio.
I see a large error and a small error. The large error is that your code assumes that the main processing in Runner consistently takes zero time:
if (Run) Transport.IncPlaybackMarker(); // marker increment
if (Transport.GetPlaybackMarker() == Transport.GetPlaybackEnd()){ // check if timer have reached end, which is 480 pulses
Transport.SetPlaybackMarker(Transport.GetPlaybackStart());
Player.PlayFile(1); // period of this event fluctuates severely
}
That is, you're "sleeping" for the time you want your loop iteration to take, and then you're doing processing on top of that.
The small error is presuming that you can represent your ideal loop iteration time with an integral number of nanoseconds. This error is so small that it doesn't really matter. However I amuse myself by showing people how they can get rid of this error too. :-)
First lets correct the small error by exactly representing the idealized loop iteration time:
using quarterPeriod = std::ratio<1, 2>;
using iterationPeriod = std::ratio_divide<quarterPeriod, std::ratio<480>>;
using iteration_time = std::chrono::duration<std::int64_t, iterationPeriod>;
I know nothing of music, but I'm guessing the above code is right because if you convert iteration_time{1} to nanoseconds, you get approximately 1041667ns. iteration_time{1} is intended to be the precise amount of time you want each iteration of your loop in Timer_class::Runner to take.
To correct the large error, you need to sleep until a time_point, as opposed to sleeping for a duration. Here's a generic utility to help you do that:
template <class Clock, class Duration>
void
delay_until(std::chrono::time_point<Clock, Duration> tp)
{
while (Clock::now() < tp)
;
}
Now if you code Timer_class::Runner to use delay_until instead of sleep_ns, I think you'll get better results:
void
Timer_class::Runner()
{
auto next_start = std::chrono::steady_clock::now() + iteration_time{1};
while (true)
{
if (Run) Transport.IncPlaybackMarker(); // marker increment
if (Transport.GetPlaybackMarker() == Transport.GetPlaybackEnd()){ // check if timer have reached end, which is 480 pulses
Transport.SetPlaybackMarker(Transport.GetPlaybackStart());
Player.PlayFile(1);
}
delay_until(next_start);
next_start += iteration_time{1};
}
}
I ended up using #howard-hinnant version of delay, and reducing buffer size in openal-soft, that's what made a huge difference, fluctuations is now about +-5 ms for 1/16th at 120BPM (125 ms period) and +-1 ms for quarter beats. Leaves a lot to be desired, but i guess it's okay
Related
I'm making a simple meteor and rocket game in the console. And I want to increase the spawnrate of the meteors every five seconds. I have already tried the Sleep() function but that will of course not work and sleep the whole application. So does a while loop.
I will only post the Logic() function where it must increase because it's a program
of like 100 lines and I didn't feel like posting it all in here. If you do need context just ask me and I will post everything.
void Logic() {
Sleep(5000); // TODO Increase meteors every Five seconds
nMeteors++;
}
I'm pretty stuck on this so it would be nice if someone could help me :)
There are mainly two ways to approach this problem. One would be to spawn a new thread and put the loop there. You can use C++11's standard libraries <thread> and <chrono. Putting the thread to sleep for 5 seconds is as simple as std::this_thread::sleep_for(std::chrono::seconds{5});
But dedicating an entire thread to such a trivial task is unnecessary. In a videogame you usually have some sort of time keeping variable.
What you'd want to do is probably have a variable like std::chrono::time_point<std::chrono::steady_clock> previous_time = std::chrono::steady_clock::now(); (or simply auto previous_time = std::chrono::steady_clock::now()) outside of your loop. Now you have a reference point you can use to know where you are in time while running your loop. Inside of your loop you create another variable like auto current_time = std::chrono::steady_clock::now();, this is your current time. Now it's a simple matter of calculating the difference between current_time and previous_time and check if 5 seconds have passed. If they have, increase your variable and don't forget to set previous_time = current_time; to update the time, if not then just skip and keep doing whatever else you need to do in your main game loop.
To check if 5 seconds have passed, you do if (std::chrono::duration_cast<std::chrono::seconds>(current_time - previous_time).count() >= 5) { ... }.
You can find a lot more info here for the chrono library and here for the thread library. Plus, Google is your friend.
The typical way to write a game is to have an event loop.
The event loop polls various inputs for status, updates the state of the game, and then repeats. Some clever event loops even sleep for short periods and get notifications when inputs change or state has to be updated.
In your meteor spawning code, keep track of a timestamp when the last increase in spawnrate occurred. When you check if a meteor should spawn or spawn meteors 5 seconds after that point, update the spawn rate and record a new timestamp (possibly retroactively, and possibly in a loop to handle more than 10 seconds passing between checks for whatever reason).
An alternative solution involving an extra thread of execution is possible, but not a good idea.
As an aside, most games want to support pausing; so you want to distinguish between wall-clock time and nominal game-play time.
One way you can do this is by making your value a function of elapsed time. For example:
// somewhere to store the beginning of the
// time period.
inline std::time_t& get_start_timer()
{
static std::time_t t{};
return t;
}
// Start a time period (resets meteors to zero)
inline void start_timer()
{
get_start_timer() = std::time(nullptr); // current time in seconds
}
// retrieve the current number of meteors
// as a function of time.
inline int nMeteors()
{
return int(std::difftime(std::time(nullptr), get_start_timer())) / 5;
}
int main()
{
start_timer();
for(;;)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "meteors: " << nMeteors() << '\n';
}
}
Here is a similar version using C++11 <chrono> library:
// somewhere to store the beginning of the
// time period.
inline auto& get_time_point()
{
static std::chrono::steady_clock::time_point tp{};
return tp;
}
// Start a time period (resets meteors to zero)
inline void start_timing()
{
get_time_point() = std::chrono::steady_clock::now(); // current time in seconds
}
// retrieve the current number of meteors
// as a function of time.
inline auto nMeteors()
{
return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - get_time_point()).count() / 5;
}
int main()
{
start_timing();
for(;;)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "meteors: " << nMeteors() << '\n';
}
}
I found this easier than using chrono
Open to feedbacks:
Code:-
include "time.h"
main(){
int d;
time_t s,e;
time(&s);
time(&e);
d=e-s;
while(d<5){
cout<<d;
time(&e);
d=e-s;
}
}
This is my code using QueryPeformanceCounter as timer.
//timer.h
class timer {
private:
...
public:
...
double get(); //returns elapsed time in seconds
void start();
};
//a.cpp
void loop() {
timer t;
double tick;
double diff; //surplus seconds
t.start();
while( running ) {
tick = t.get();
if( tick >= 1.0 - diff ) {
t.start();
//things that should be run exactly every second
...
}
Sleep( 880 );
}
}
Without Sleep this loop would go on indefinitely calling t.get() every time which causes high CPU usage. For that reason, I make it sleep for about 880 milliseconds so that it wouldn't call t.get() while not necessary.
As I said above, I'm currently using Sleep to do the trick, but what I'm worried about is the accuracy of Sleep. I've read somewhere that the actual milliseconds the program pauses may vary - 20 to 50 ms - the reason I set the parameter to 880. I want to reduce the CPU usage as much as possible; I want to, if possible, pause more than 990 milliseconds EDIT: and yet less than 1000 milliseconds between every loop. What would be the best way to go?
I don't get why you are calling t.start() twice (it resets the clock?), but I would like to propose a kind of solution for the Sleep inaccuracy. Let's take a look at the content of while( running ) loop and follow the algorithm:
double future, remaining, sleep_precision = 0.05;
while (running) {
future = t.get() + 1.0;
things_that_should_be_run_exactly_every_second();
// the loop in case of spurious wakeup
for (;;) {
remaining = future - t.get();
if (remaining < sleep_precision) break;
Sleep(remaining);
}
// next, do the spin-lock for at most sleep_precision
while (t.get() < future);
}
The value of sleep_precision should be set empirically - OSes I know can't give you that.
Next, there are some alternatives of the sleeping mechanism that may better suit your needs - Is there an alternative for sleep() in C?
If you want to pause more than 990 milliseconds, write a sleep for 991 milliseconds. Your thread is guaranteed to be asleep for at least that long. It won't be less, but it could be multiples of 20-50ms more (depending on the resolution of your OS's time slicing, and on the the cost of context switching).
However, this will not give you something running "exactly every second". There is just no way to achieve that on a time-shared operating system. You'll have to program closer to the metal, or rely on an interrupt from a PPS source and just pray your OS lets you run your entire loop iteration in one shot. Or, I suppose, write something to run in kernel modeā¦?
code segment as follows, code come frome chromium, why?
// Initilalize initial_ticks and initial_time
void InitializeClock() {
initial_ticks = TimeTicks::Now();
// Initilalize initial_time
initial_time = CurrentWallclockMicroseconds();
}// static
Time Time::Now() {
if (initial_time == 0)
InitializeClock();
// We implement time using the high-resolution timers so that we can get
// timeouts which are smaller than 10-15ms. If we just used
// CurrentWallclockMicroseconds(), we'd have the less-granular timer.
//
// To make this work, we initialize the clock (initial_time) and the
// counter (initial_ctr). To compute the initial time, we can check
// the number of ticks that have elapsed, and compute the delta.
//
// To avoid any drift, we periodically resync the counters to the system
// clock.
while (true) {
TimeTicks ticks = TimeTicks::Now();
// Calculate the time elapsed since we started our timer
TimeDelta elapsed = ticks - initial_ticks;
// Check if enough time has elapsed that we need to resync the clock.
if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
InitializeClock();
continue;
}
return Time(elapsed + Time(initial_time));
}
}
I assume your answer lies in the comment of the code you pasted:
// We implement time using the high-resolution timers so that we can get
// timeouts which are smaller than 10-15ms. If we just used
// CurrentWallclockMicroseconds(), we'd have the less-granular timer.
So Now gives a time value of high resolution, which is beneficial when you need higher resolution than 10-15ms, as they state in the comment. For instance, if you want to reschedule a task every 100 ns, you need the higher resolution, or if you want to measure the execution time of something - 10-15 ms is an eternity.
What is the best way to ensure that real-time performance are achieved, with a 2 thread program running on 1 or 2 cores ? boost::timer or RDTSC ?
We started from that code
boost::timer t;
p.f(frame);
max_time_per_frame = std!::max(max_time_per_frame, t.ellapsed());
... where p is an instance of Proc.
class Proc {
public:
Proc() : _frame_counter(0) {}
// that function must be call for each video frame and take less than 1/fps seconds
// 24 fps => 1/24 => < 0.04 seconds.
void f(unsigned char * const frame)
{
processFrame(frame); //that's the most important part
//that part run every 240 frame and should not affect
// the processFrame flow !
if(_frame_counter % 240 == 0)
{
do_something_more();
}
_frame_counter++;
}
private:
_frame_counter;
}
So it run in a Single-Thread/Single-Core way and we observed that the max_time_per_frame is higher than the target time because of the do_something_more processing.
To remove those processing time spikes, we started every do_something_more in a separate thread, like in the pseudo-code below.
class Proc {
public:
Proc() : _frame_counter(0) {
t = start_thread ( do_something_more_thread );
}
// that function must be call for each video frame and take less than 1/fps seconds
// 24 fps => 1/24 => < 0.04 seconds.
void f(unsigned char * const frame)
{
processFrame(frame); //that's the most important part
//that part run every 240 frame and should not affect
// the processFrame flow !
if(_frame_counter % 240 == 0)
{
sem.up();
}
_frame_counter++;
}
void do_something_more_thread()
{
while(1)
{
sem.down();
do_something_more();
}
}
private:
_frame_counter;
semaphore sem;
thread t;
}
I always start my program on 1 and 2 core. So i use start /AFFINITY 1 pro.exe or start /AFFINITY 3 prog.exe
And from time point of view, every thing is ok, max_time_per_frame stay below our target, close to the average at 0.02 second/frame.
But if I dump the number of tick spent in f, using RDTSC.
#include <intrin.h>
...
unsigned long long getTick()
{
return __rdtsc();
}
void f(unsigned char * const frame)
{
s = getTick();
processFrame(frame); //that's the most important part
//that part run every 240 frame and should not affect
// the processFrame flow !
if(_frame_counter % 240 == 0)
{
sem.up();
}
_frame_counter++;
e = getTick();
dump(e - s);
}
start /AFFINITY 3 prog.exe the max_tick_per_frame was stable and as expected i saw 1 thread(100% of 1 core) and the 2nd thread started at a normal pace on the 2nd core.
start /AFFINITY 1 pro.exe, i saw only 1 core at 100% (as expected), but the do_something_more computation time doesn't seem spead over the time, interleaved thread execution. In fact, at regular interval, i saw a huge spike of the tick count.
So the question is why ? does the only interesting measure is time ? does tickhave sense when running sofware on 1 core (frequency boost) ?
Although you'll never get true real time performance out of windows, you can reduce the pitfalls of RDTSC by using the Windows API.
Here is a small code chunk that takes advantage of the API.
#include <Windows.h>
#include <stdio.h>
int
main(int argc, char* argv[])
{
double timeTaken;
LARGE_INTEGER frequency;
LARGE_INTEGER firstCount;
LARGE_INTEGER endCount;
/*-- give us the higheest priority avaliable --*/
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
/*-- get the frequency of the timer we are using --*/
QueryPerformanceFrequency(&frequency);
/*-- get the timers current tick --*/
QueryPerformanceCounter(&firstCount);
/*-- some pause --*/
Sleep(1);
/*-- get the timers current tick --*/
QueryPerformanceCounter(&endCount);
/*-- calculate time passed --*/
timeTaken = (double)(doubleendCount.QuadPart-firstCount.QuadPart)/(double)(frequency.QuadPart/1000);
printf("Time: %lf", timeTaken);
return 0;
}
You can also use:
#include <Mmsystem.h>
if(timeBeginPeriod(1) == TIMERR_NOCANDO) {
printf("TIMER could not be set to 1ms\n");
}
/*-- your code here --*/
timeEndPeriod(1);
But this will change the global windows timer resolution to what ever interval you set it to (or at least attempt it), so i wouldn't recommend this approach unless you are 100% certain you are the only one that will use this program as this may have unintended side effects on other programs.
Based on the comment about the REALTIME_PRIORITY_CLASS, I added the following line in a test program.
#define NOMINMAX
#include <windows.h>
....
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
And now the tick count i got from RDTSC looks better, the huge spike I saw before on 1 frame, is now spread over multiple frames.
As i wanted to keep my code portable and create some scheduling opportunities, I yielded the additional thread at some specific point using:
boots::this_thread::yield();
and with that change, I obtain the scheduling and the RDTSC value I expected without having to configure the priority!
Thank for all help and advice.
First off, I found a lot of information on this topic, but no solutions that solved the issue unfortunately.
I'm simply trying to regulate my C++ program to run at 60 iterations per second. I've tried everything from GetClockTicks() to GetLocalTime() to help in the regulation but every single time I run the program on my Windows Server 2008 machine, it runs slower than on my local machine and I have no clue why!
I understand that "clock" based function calls return CPU time spend on the execution so I went to GetLocalTime and then tried to differentiate between the start time and the stop time then call Sleep((FPS / 1000) - millisecondExecutionTime)
My local machine is quite faster than the servers CPU so obviously the thought was that it was going off of CPU ticks, but that doesn't explain why the GetLocalTime doesn't work. I've been basing this method off of http://www.lazyfoo.net/SDL_tutorials/lesson14/index.php changing the get_ticks() with all of the time returning functions I could find on the web.
For example take this code:
#include <Windows.h>
#include <time.h>
#include <string>
#include <iostream>
using namespace std;
int main() {
int tFps = 60;
int counter = 0;
SYSTEMTIME gStart, gEnd, start_time, end_time;
GetLocalTime( &gStart );
bool done = false;
while(!done) {
GetLocalTime( &start_time );
Sleep(10);
counter++;
GetLocalTime( &end_time );
int startTimeMilli = (start_time.wSecond * 1000 + start_time.wMilliseconds);
int endTimeMilli = (end_time.wSecond * 1000 + end_time.wMilliseconds);
int time_to_sleep = (1000 / tFps) - (endTimeMilli - startTimeMilli);
if (counter > 240)
done = true;
if (time_to_sleep > 0)
Sleep(time_to_sleep);
}
GetLocalTime( &gEnd );
cout << "Total Time: " << (gEnd.wSecond*1000 + gEnd.wMilliseconds) - (gStart.wSecond*1000 + gStart.wMilliseconds) << endl;
cin.get();
}
For this code snippet, run on my computer (3.06 GHz) I get a total time (ms) of 3856 whereas on my server (2.53 GHz) I get 6256. So it potentially could be the speed of the processor though the ratio of 2.53/3.06 is only .826797386 versus 3856/6271 is .614893956.
I can't tell if the Sleep function is doing something drastically different than expected though I don't see why it would, or if it is my method for getting the time (even though it should be in world time (ms) not clock cycle time. Any help would be greatly appreciated, thanks.
For one thing, Sleep's default resolution is the computer's quota length - usually either 10ms or 15ms, depending on the Windows edition. To get a resolution of, say, 1ms, you have to issue a timeBeginPeriod(1), which reprograms the timer hardware to fire (roughly) once every millisecond.
In your main loop you can
int main()
{
// Timers
LONGLONG curTime = NULL;
LONGLONG nextTime = NULL;
Timers::GameClock::GetInstance()->GetTime(&nextTime);
while (true) {
Timers::GameClock::GetInstance()->GetTime(&curTime);
if ( curTime > nextTime && loops <= MAX_FRAMESKIP ) {
nextTime += Timers::GameClock::GetInstance()->timeCount;
// Business logic goes here and occurr based on the specified framerate
}
}
}
using this time library
include "stdafx.h"
LONGLONG cacheTime;
Timers::SWGameClock* Timers::SWGameClock::pInstance = NULL;
Timers::SWGameClock* Timers::SWGameClock::GetInstance ( ) {
if (pInstance == NULL) {
pInstance = new SWGameClock();
}
return pInstance;
}
Timers::SWGameClock::SWGameClock(void) {
this->Initialize ( );
}
void Timers::SWGameClock::GetTime ( LONGLONG * t ) {
// Use timeGetTime() if queryperformancecounter is not supported
if (!QueryPerformanceCounter( (LARGE_INTEGER *) t)) {
*t = timeGetTime();
}
cacheTime = *t;
}
LONGLONG Timers::SWGameClock::GetTimeElapsed ( void ) {
LONGLONG t;
// Use timeGetTime() if queryperformancecounter is not supported
if (!QueryPerformanceCounter( (LARGE_INTEGER *) &t )) {
t = timeGetTime();
}
return (t - cacheTime);
}
void Timers::SWGameClock::Initialize ( void ) {
if ( !QueryPerformanceFrequency((LARGE_INTEGER *) &this->frequency) ) {
this->frequency = 1000; // 1000ms to one second
}
this->timeCount = DWORD(this->frequency / TICKS_PER_SECOND);
}
Timers::SWGameClock::~SWGameClock(void)
{
}
with a header file that contains the following:
// Required for rendering stuff on time
#pragma once
#define TICKS_PER_SECOND 60
#define MAX_FRAMESKIP 5
namespace Timers {
class SWGameClock
{
public:
static SWGameClock* GetInstance();
void Initialize ( void );
DWORD timeCount;
void GetTime ( LONGLONG* t );
LONGLONG GetTimeElapsed ( void );
LONGLONG frequency;
~SWGameClock(void);
protected:
SWGameClock(void);
private:
static SWGameClock* pInstance;
}; // SWGameClock
} // Timers
This will ensure that your code runs at 60FPS (or whatever you put in) though you can probably dump the MAX_FRAMESKIP as that's not truly implemented in this example!
You could try a WinMain function and use the SetTimer function and a regular message loop (you can also take advantage of the filter mechanism of GetMessage( ... ) ) in which you test for the WM_TIMER message with the requested time and when your counter reaches the limit do a PostQuitMessage(0) to terminate the message loop.
For a duty cycle that fast, you can use a high accuracy timer (like QueryPerformanceTimer) and a busy-wait loop.
If you had a much lower duty cycle, but still wanted precision, then you could Sleep for part of the time and then eat up the leftover time with a busy-wait loop.
Another option is to use something like DirectX to sync yourself to the VSync interrupt (which is almost always 60 Hz). This can make a lot of sense if you're coding a game or a/v presentation.
Windows is not a real-time OS, so there will never be a perfect way to do something like this, as there's no guarantee your thread will be scheduled to run exactly when you need it to.
Note that in the remarks for Sleep, the actual amount of time will be at least one "tick" and possible one whole "tick" longer than the delay you requested before the thread is scheduled to run again (and then we have to assume the thread is scheduled). The "tick" can vary a lot depending on hardware and the version of Windows. It is commonly in the 10-15 ms range, and I've seen it as bad as 19 ms. For 60 Hz, you need 16.666 ms per iteration, so this is obviously not nearly precise enough to give you what you need.
What about rendering (iterating) based on the time elapsed between rendering of each frame? Consider creating a void render(double timePassed) function and render depending on the timePassed parameter instead of putting program to sleep.
Imagine, for example, you want to render a ball falling or bouncing. You would know it's speed, acceleration and all other physics that you need. Calculate the position of the ball based on timePassed and all other physics parameters (speed, acceleration, etc.).
Or if you prefer, you could just skip the render() function execution if time passed is a value to small, instead of puttin program to sleep.