Accuracy of Task.Delay - windows-runtime

I'm developing Windows 10 Universal App in C#/Xaml, I'm using await Task.Delay(delayInMilliseconds) to suspend a method for given time. My scenario is somewhat realtime, so it's very sensitive to time changes, and I need to make sure that when i suspend a method for let's say 8 millisecods it is suspended for 8 millisecods. I have noticed that the actual time span for which ** Task.Delay ** suspends the method differes from what is passed as delay parameter, for 1 up to 30 ms, the length of "deviation" being different in each call. So, when I want to sleep for 8 milliseconds, my system sleeps for 9 to 39 milliseconds, and this completly ruins my scenario.
So, my question what is the best way to substitute ** Task.Delay ** and to achieve good precision? For the time being I use this method:
public static void Delay1(int delay)
{
long mt = delay * TimeSpan.TicksPerMillisecond;
Stopwatch s = Stopwatch.StarNew();
while (true)
{
if (s.Elapsed.TotalMilliseconds > delay)
{
return;
}
}
}
but it guees it consumes a lot of resources, that is 100% of a processor's core. If an user has small number of processor's cores, this would be very insufficient.

According to msdn it's not possible to achieve more accuracy due to system clock resolution:
This method depends on the system clock. This means that the time
delay will approximately equal the resolution of the system clock if
the millisecondsDelay argument is less than the resolution of the
system clock, which is approximately 15 milliseconds on Windows
systems.

Seems like I've found a sattisfactory solution: using ManualResetEvent(false).WaitOne(delay) instead of await Task.Delay(delayInMilliseconds).
I've used following code to test both methods:
async void Probe()
{
for (int i = 0; i < 1000; i++)
{
// METHOD 1
await Task.Delay(3);
// METHOD 2
new System.Threading.ManualResetEvent(false).WaitOne(3);
}
}
The code above should take exactly 3 seconds to execute. With METHOD 2 it took around 3300 ms, so the error is 0.3 ms per call. Acceptable for me. But the METHOD 1 took around 15 seconds (as mentioned by others and explained above) to execute which gives totally unacceptable error for my scenario.
EDIT: WaitOne() is a blocking call, so you'll probably want to run it as a task to get it off the UI thread (or any other thread with a message pump). #Abel has pointed out another high-res timer approach that is already baked into a task and will run in an alternate thread as shown here: (https://stackoverflow.com/a/62588903/111575). That approach makes cpu-intensive calls to Thread.Spinwait() and Thread.Sleep(0) for small intervals.

You should use multi-media timers. Those are much accurate.
Take a look here:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/2024e360-d45f-42a1-b818-da40f7d4264c/accurate-timer

After working hard I found a solution to sleep the thread for specific time and the error is just 3 to 4 microseconds on my Core 2 Duo CPU 3.00 GHz.
Here it is:
Here is code.(C# code is also given at the end.) Use "ThreadSleepHandler":
Public Class ThreadSleepHandler
Private Stopwatch As New Stopwatch
Private SpinStopwatch As New Stopwatch
Private Average As New TimeSpan
Private Spinner As Threading.SpinWait
Public Sub Sleep(Time As TimeSpan)
Stopwatch.Restart()
If Average.Ticks = 0 Then Average = GetSpinTime()
While Stopwatch.Elapsed < Time
If Stopwatch.Elapsed + Average < Time Then
Average = TimeSpan.FromTicks((Average + GetSpinTime()).Ticks / 2)
End If
End While
End Sub
Public Function GetSpinTime() As TimeSpan
SpinStopwatch.Restart()
Spinner.SpinOnce()
SpinStopwatch.Stop()
Return SpinStopwatch.Elapsed
End Function
End Class
Here is example code:
Sub Main()
Dim handler As New ThreadSleepHandler
Dim stopwatch As New Stopwatch
Do
stopwatch.Restart()
handler.Sleep(TimeSpan.FromSeconds(1))
stopwatch.Stop()
Console.WriteLine(stopwatch.Elapsed)
Loop
End Sub
For c# programmers here is code (I have converted this code but I am not sure):
static class Main
{
public static void Main()
{
ThreadSleepHandler handler = new ThreadSleepHandler();
Stopwatch stopwatch = new Stopwatch();
do {
stopwatch.Restart();
handler.Sleep(TimeSpan.FromSeconds(1));
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
} while (true);
}
}
public class ThreadSleepHandler
{
private Stopwatch Stopwatch = new Stopwatch();
private Stopwatch SpinStopwatch = new Stopwatch();
private TimeSpan Average = new TimeSpan();
private Threading.SpinWait Spinner;
public void Sleep(TimeSpan Time)
{
Stopwatch.Restart();
if (Average.Ticks == 0)
Average = GetSpinTime();
while (Stopwatch.Elapsed < Time) {
if (Stopwatch.Elapsed + Average < Time) {
Average = TimeSpan.FromTicks((Average + GetSpinTime()).Ticks / 2);
}
}
}
public TimeSpan GetSpinTime()
{
SpinStopwatch.Restart();
Spinner.SpinOnce();
SpinStopwatch.Stop();
return SpinStopwatch.Elapsed;
}
}
Note:
"ThreadSleepHandler" is thread unsafe. You cannot use a single "ThreadSleepHandler" for multiple threads.
The first sleep time will not be enough accurate.

In my tests, I found that DispatcherTimer at 20ms intervals will deliver sufficiently smooth animation if you must do it in code. Doing it in XAML is another alternative as already mentioned.

Related

How can I record sound with 16 bits per sample (16 bit depth)?

I try to record PCM sound from flash (using Microphone class). I use org.bytearray.micrecorder.MicRecorder helper class.
In Microphone class I cannot find property like bitDepth or bitsPerSample.
I always get 32 bits.
Is it possible to do?
UPDATE: The asker John812 was able to solve this by using..
bit16_bytes.writeShort( data.readFloat() * 32767 ); see comments below for context
METHOD #2: Based on my experience with using the LoadPCMfromByteArray method
I have something you could try but I've only used it with an actual 32bit WAVE file and played via the LoadPCMFromByteArray command.
The AS3 Microphone Class records 32 bits. You have to write the conversion of samples to a different bit-depth by yourself. I have no idea how many samples you are processing but the general code below shows you how to convert. Note: * 512 means use your actual samples amount (example: * 4096? or * 8192?) If you get the numbers wrong there'll be hiss/distortion so either experiment from small or provide the full details in your question for a more helpful edit/answer.
CONVERT: Assuming your recorded byteArray is called data
public var bit16_bytes : ByteArray; //will hold the 16bit version
public function convert_to16Bit () : void
{
bit16_bytes = new ByteArray(); data.position = 0;
while (bit16_bytes.position < data.length - 4)
//if you get noise/distortion try either: 256, 512, 1024, 2048, 4096 or 8192
{ bit16_bytes.writeShort( data.readInt() * 512 ); } //multiply by samples amount
data = new ByteArray(); //recycle for re-use
bit16_bytes.position = 0; //reset or else E-O-File error
bit16_bytes.readBytes( data ); //copy 16bit back into Data byte-array
}
To run the above function whenever you're ready just add the line convert_to16Bit(); inside whatever function deals with your "recording complete" situation.

Atmel Studio Dummy_Handler

Occasionally I will get an unexpected interrupt, and my code will hang inside Dummy_Handler() in exceptions.c of the Atmel Studio Framework (ASF). I am using the ATSAM3X8E microcontroller of the Arduino Due.
void Dummy_Handler(void)
{
while(1) {
}
}
Any ideas how to determine which interrupt it was?
Of course I could replace this single handler with unique dummy handlers, one for each exception. (There are about fifty of them.) For example change each line in the same exceptions.c file:
void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_Handler")));
to this
void HardFault_Handler ( void ) __attribute__ ((weak, alias("Dummy_HardFault_Handler")));
Etc... Or try to reason how my code could have generated which interrupt. But who has that kind of time?
This MCU has an Interrupt Program Status Register that gives some clue as to source. ASF has wrapped it in a function __get_IPSR() in core_cmFunc.h:
uint32_t phantomISR = 9999;
void Dummy_Handler(void)
{
while(1) {
phantomISR = __get_IPSR();
}
}
Then this global variable can be monitored at runtime. (In my case I paused the assembly code for this loop-of-death and saw the value 3 in the R3 register.) The Atmel MCU doc explains its value:
ISR_NUMBER
This is the number of the current exception:
0 = Thread mode
1 = Reserved
2 = NMI
3 = Hard fault
4 = Memory management fault
5 = Bus fault
6 = Usage fault
7-10 = Reserved
11 = SVCall
12 = Reserved for Debug
13 = Reserved
14 = PendSV
15 = SysTick
16 = IRQ0
45 = IRQ29
Both times this happened to me it was the Hard Fault, a kind of blue-screen-of-death for the Ardunio Due. So I also installed a Hard Fault handler of my own.
ISR(HardFault_Handler)
{
while (1) {
}
}
Also, detectable in debug mode by pausing. Of course the sequel is, what causes a Hard Fault? I'm guessing memory wipe or infinite recursion.

5 Minute Countdown With Buttons

I have to make a 5 minute countdown clock as an assignment. I was given the basis of a as3 and told to add 'Start' - 'Reset' - 'Stop' buttons. So far I have a respectable countdown going, but no way to control it. I'm new to as2 and flash so I hope this isn't one of those "If you know that, you should know your answer" situations. Anything i try to find on the web as far as tuts don't really help me so if anyone could just tell me if I'm on the right path or eve if it's possible to ass buttons to this code to do whats stated above. Thanks in adv :)
var secs = "0" + 0;
var mins = 5;
timerDisplay.text = mins + ":" + secs;
var timerInterval = setInterval(countDown,1000);
//DISPLAYS DYNAMIC TEXT
function countDown()
{
secs--;
if (secs < 0)
{
secs = 59;
mins--;
}
if (secs < 10)
{
var secs2 = "0" + secs;
}
else
{
var secs2 = secs;
}
if (mins == 0 && secs == 0)
{
clearInterval(timerInterval);//STOPS TIME # ZERO
}
timerDisplay.text = mins + ":" + secs2;
}
As this is an assignment, I won't give you any code, just some ideas to get you on your way to writing your own.
You may want to add two (possibly three) buttons to the stage. One button could be the reset button and another could be a button that trades off between being start and stop (depending on whether the timer is currently running).
The only code necessary for a reset button, is something that sets your min variable and your secs variable back to their original values (possibly plus 1 second because of your interval code). If you need help getting started with buttons clicks throwing functions check out the mc.onPress method.
The only code necessary for a stop button, is something that stops your interval counter from continuing to count. I believe you already have something doing that when "clear" your timer at zero.
The only code necessary for a start button, is something that restarts your interval counter. You do something of the sort when you first start your timerInterval.
This won't work if someone decides to click on the start button after you have finished the countdown or if someone decides to click the start button multiple times.
In the first case, the countdown will continue into negative numbers, so you may want to write an if statement that doesn't allow that to happen (inside of the start button function).
And in the second case, the countdown will get faster and faster each time the button is pressed. Creating a boolean that keeps track of whether the program is stopped could possibly help with that problem.
To clarify a statement I made above about the interval code: Your code will forever decrement every 1000 milliseconds. The text box is only ever being refreshed when you decrement, so if you try to reset with exactly 5 minutes and zero seconds, you will see the numbers jump to 4:59 and then keep decrementing. If you reset to 5 minutes and 1 second, the numbers will appear to jump to 5:00 and then decrement from there.
I hope this helps!
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Test extends MovieClip {
private var _timer:Timer = null;
private var _repeatCount:int = 0;
private var _totalMinutes:int = 5;
public function Test() : void {
addEventListener(Event.ADDED_TO_STAGE, _Init);
}
private function _Init(e:Event) : void {
_repeatCount = _totalMinutes * 60;
_timer = new Timer(1000, _repeatCount);
_timer.addEventListener(TimerEvent.TIMER, _OnTimerFired);
_timer.start();
}
private function _OnTimerFired(e:TimerEvent) : void {
var minRem:int = (_repeatCount - _timer.currentCount) / 60 ;
var secRem:int = (_repeatCount - _timer.currentCount) % 60;
trace(minRem + ":" + secRem);
}
}
}

Stopwatch based on timer showing wrong time AS3

I have created stopwatch which consist of two classes. First is stopwatchModel. Second is stopwatchView. My stopwatch is working but it is showing less time than how much time it last for real. It looks like my stopwatch is slower than reality.
StopwatchModel
private function initStopwatchModel():void{
timer = new Timer(100,0);
timer.addEventListener(TimerEvent.TIMER,onTimer);
}
private function onTimer(e:TimerEvent):void{
decsec++;
if (decsec == 10){
sec++;
decsec=0;
if (sec == 60){
sec = 0;
min++;
}
}
playerTimeString = min + ":" + sec + ":" + decsec + "0";
dispatchEvent(new Event("NEW_TIME"));
}
StopwatchView
private function initModelEventListeners(){
_model.addEventListener("NEW_TIME",onNewTime);
}
//update textoveho pola, vzdy ked sa zmeni cas
private function onNewTime(e:Event):void{
textFieldStopWatch.text = _model.playerTimeString;
}
Thank you for answer
Because timer is not fully accurate but it is somehow dependent on the frame rate so it finds the closest interval that is multiple to one frame time.
I would recommend you to save getTimer() return using http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#getTimer() when the application starts and then measure it on timer and calculate the difference - this will work for sure.
The problem is also documented at http://www.computus.org/journal/?p=22
You should be using the getTimer function, not the Timer class. See for example https://stackoverflow.com/a/12495538/842685

Difference between Date.getTime() and getTimer

How is the running time of the virtual machine calculated vs. how system time is calculated? I know I can get the current running time of the AVM by calling:
getTimer();
And I can get the current unix system time by doing:
new Date().getTime();
I know that the Timer class and Event.ENTER_FRAME event each come with their ups and downs, but I figured the 2 values I was comparing should stay consistently relative to each other. Here's how I'm testing it:
private var _appRunTime:int;
private var _appStartTime:int;
private var _systemTime:int;
private var _systemCurrentTime:int;
//called at application launch
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
_systemTime = new Date().getTime();
_appStartTime = getTimer();
}
//called on button click to see values
protected function button1_clickHandler(event:MouseEvent):void
{
_systemCurrentTime = new Date().getTime();
_appRunTime = getTimer();
trace(_systemCurrentTime - _systemTime, _appRunTime - _appStartTime);
}
I don't understand why those numbers would slowly get out of sync. Using that code, I've found, at least on my computer, that the values grow apart from each other by about 3 milliseconds per minute, with the value coming from system time being the higher value and the value coming from AVM time being the lower.
Can anyone offer me an explanation what those are calculated on and why there would be that small, yet growing gap in their values as time passes?
On my system the same code gives no difference between getTimer() and getTime()
after ~10 mins the difference is always between 0 and 1 ms.
Maybe it's an issue of you system or the specific to the player you're running?
I'm running flash player 11 on Win 7 x64.
On my computer (Win 7 64-Bit), sometimes getTimer runs slower than Date.getTime() (system time), but sometimes getTimer() runs faster. The difference can range from -0.57ms/sec to 0.1ms/sec.
The result is independent of running in browser or Flash standalone player.
It will help you...
public static function getDaysBetweenDates(date1:Date,date2:Date):int
{
var one_day:Number = 1000 * 60 * 60 * 24
var date1_ms:Number = date1.getTime();
var date2_ms:Number = date2.getTime();
var difference_ms:Number = Math.abs(date1_ms - date2_ms)
return Math.round(difference_ms/one_day);
}