|Thanks that does explain one glitch I got with GetTickCount and timeGetTime.
With the HPC though after dealing with the core changing issues, then it wasn't doing any sudden big jumps. Just measuring the time wrong.
I'm doing this to measure musical notes. But I've found a solution at last .
The key was discovery of yet another MS Windows timing routine, KeQueryUnbiasedInterruptTime which looked like the type of precise timing I need, but unfortunately only accessible in kernel mode
However, then I found, that there is a little known structure called KUSER_SHARED_DATA which is added to the process address space of every user mode process at the address 0x7FFE0000 which is a system wide shared memory location. It is volatile, and gets updated with the kernel interrupt time continuously. This means that to check the kernel interrupt time, all you need to do is to look at the correct address location in your process address space.
This apparently is a hardware timer, not affected by changes in cycle rate of the processor cores. It might be using either the RTC or the HPET though I don't know which it is. And since it is just a memory look up then there is far less overhead involved than in any of the other timers used in Windows.
Combining this with the code I have already, which does a sleep that stops slightly short of the desired time followed by a busy wait time checking loop at real time time critical mode until the time is reached - and you get sub microsecond "sample perfect" timing of midi in Windows.
Here is the code:
typedef struct _KSYSTEM_TIME
} KSYSTEM_TIME, *PKSYSTEM_TIME;
typedef struct _KUSER_SHARED_DATA
volatile ULONG TickCountLow;
volatile KSYSTEM_TIME InterruptTime;
volatile KSYSTEM_TIME SystemTime;
volatile KSYSTEM_TIME TimeZoneBias;
} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
#define MM_SHARED_USER_DATA_VA 0x7FFE0000
#define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)MM_SHARED_USER_DATA_VA)
ts.SysTime.High1Time = USER_SHARED_DATA->InterruptTime.High1Time;
ts.SysTime.LowPart = USER_SHARED_DATA->InterruptTime.LowPart;
I got this by modifying source code available here
which is part of Microsoft's "Invisible computing" real time operating system also known as MMLite. Microsoft Invisible Computing[^]
So it is documented Microsoft code and not just a hack using undocumented structures. It requires Windows NT or later.
This is an actual recording made in real time using my program to play the notes via midi on the Microsoft GS Wavetable synth:
This is a test of the use of the Windows interrupt timer to time notes in Bounce Metronome.[^]
Here is a screen shot of the recording where you can see the sample precise alignment of the notes. You can tell it is sample precise because all the details of the waveform are exactly the same - all the irregularities that you get which will look slightly different if you move the waveform by a sample or so and then look at it zoomed out like this.
screen shot of recording with sample precise timing[^]
This also seems like a great way to do performance testing too, without all that averaging we are used to, and with almost no overhead.