Gapless (looping) audio playback with DirectX in C# - c#

I'm currently using the following code (C#):
private static void PlayLoop(string filename)
{
Audio player = new Audio(filename);
player.Play();
while (player.Playing)
{
if (player.CurrentPosition >= player.Duration)
{
player.SeekCurrentPosition(0, SeekPositionFlags.AbsolutePositioning);
}
System.Threading.Thread.Sleep(100);
}
}
This code works, and the file I'm playing is looping. But, obviously, there is a small gap between each playback.
I tried reducing the Thread.Sleep it to 10 or 5, but the gap remains.
I also tried removing it completely, but then the CPU usage raises to 100% and there's still a small gap.
Is there any (simple) way to make playback in DirectX gapless? It's not a big deal since it's only a personal project, but if I'm doing something foolish or otherwise completely wrong, I'd love to know.
Thanks in advance.

The problem with your approach is that you have a thread spinning, checking the position of the player. The longer you increase your sleep, the less CPU it drains but the later it will notice the end of the clip. The shorter the sleep, the quicker it will notice but the more CPU your checker thread consumes.
I can see nothing in the docs to tell the clip to loop. The only suggestion I have is to use the Audio.Ending event to start the clip playing again. This will remove the need for your separate monitoring thread but I am not sure whether this will be quick enough to eliminate the gap.
You will also want to check to ensure your audio clip does not begin or end with a period of silence.

Since you know the duration of the song, just use a timer to regularly call you "rewind" method and give the timer an interval sligthly shorter than the real song duration.
private static void PlayLoop(string filename)
{
Audio player = new Audio(filename);
player.Play();
//System.Timers.Timer (i reduce the length by 100 ms to try to avoid blank)
var timer = new Timer((player.Duration - TimeSpan.FromMilliseconds(100)).TotalMilliseconds());
timer.Elapsed += (sender, arg) =>
{
player.SeekCurrentPosition(0, SeekPositionFlags.AbsolutePositioning);
};
timer.Start();
}
Of course, you'll need to stop the timer so make it an instance member instead of a local variable of your method, so you can disable it with a Stop() method.
I hope this will help you.
Manitra

Related

Timer stops entire program

so I've just made a simple snake game in WinForms and I've only got one problem left. The idea is that I'm gonna implement a power-up that speeds up the player for 10 seconds. I've tried using thread. sleep method to create a timer but that sleeps the entire program. I've also tried playing with the task.delay method but without success.
Am I going about this problem the wrong way or am I just missing something? Do you have any tips to get me on the right path? I'm quite new to this so this might be an easy fix.
var watch = new Stopwatch();
watch.Start();
using (var task = Task.Delay(10000))
{
speedUp = true;
task.Wait();
}
watch.Stop();
speedUp = false;
This is my attempt at the delay. But it seems to pause the entire program for 10 seconds before it continues.
Thanks
You may want to check the past time by looking at a clock within your game loop. The property Environment.TickCount provides you with the milliseconds since the last boot or you could do it with DateTime or Timespan. Now instead of sleeping you could check if 10'000 milliseconds have past since the activation of the power-up. This way nothing will get blocked and collecting multiple power-ups within 10 seconds won't screw up the deactivation process.

Program stops responding when I try to increment and print a number in a loop

I have the following code in C#:
void Update () {
for (int m=0;m<122132343243243;m++)
{
print(m);
}
}
When I try run this Unity stops responding. How can I get this function to finish executing?
The main problem with your code is that you're asking the computer to do a massive amount of work all at once, so it stops responding. Counting up to 122 trillion is a lengthy task, which by itself would take at least 20 days (see Counting up to one trillion for estimation) and is only compounded by the fact that you're printing every number.
What you need to do is allow the computer to spread this work out over multiple frames, through the use of coroutines. (You could use another thread instead to prevent locking, but coroutines are the simpler Unity approach to this problem.)
Your code could be rewritten as follows:
void Start() {
StartCoroutine("CountAndPrint");
}
IEnumerator CountAndPrint() {
for (long m=0; m<122132343243243; m++) {
print(m);
yield return null;
}
}
Note: I also switched long in for int, as Daniel noted that the value of m will otherwise overflow should you let it run for long enough.
The main difference in this code is that it basically allows the program to "pause" execution of the method after each time it counts up, saving the rest of the work for future frames. This will allow you to continue interacting with the program while the counter increases.
Hope this helps! Let me know if you have any questions.

How to make an accurate decimal Timer?

I'm pretty frustrated about this one ..
I have a timer called timer1 and a text box called TimeElapsedTextBox and a double variable called TimeTakenToFinish
the timer ticks every 1 second (1000 millisecond)
in the text box, I want it to display the time in this format:
Seconds.PartsOfSecond
Here is the Tick event:
private void timer1_Tick(object sender, EventArgs e)
{
TimeTakenToFinish += (double)timer1.Interval / 10000;
TimeElapsedTextBox.Text = TimeTakenToFinish;
}
it is actually displaying it in the text box the way i want it,
but it's not counting properly ..
I mean, it's counting less than a real second..
could you please tell me how to fix this ..
Your problem here is a misunderstanding of the way your OS works. Sure, you can set the interval to 1000ms, but you cannot expect it to actually tick every second. You are running code on Windows, not a hard (or soft) real time operating system.
As an aside, you should also know that the resolution of your timer is finite, and as of today, limited to the accuracy of your system timer, which is probably about 15ms.
You cannot expect your code to perform that deterministically in that sort of environment. At any point the OS can preemptively kick you out of the CPU and start working on another task.
You simply cannot get the accuracy you desire, though I would ask; is it actually required? Probably not, but you haven't told us what you are actually trying to accomplish here, so who knows?
Also, this is wrong:
TimeTakenToFinish += (double)timer1.Interval / 10000;
Interval is a property which is used to tell the timer roughly how often it should fire the Tick event. You are not actually measuring anything, you may as well just be adding 1000.0 / 10000 to your counter every time.
If you need more precision use the StopWatch class which uses your CPU's high performance timer if available. You can still use a timer to periodically update the UI based on the current elapsed value of the Stopwatch, i.e.,
void timer1_Tick(...)
{
var totalSeconds = _someStopwatch.ElapsedMilliseconds / 1000.0;
TimeElapsedTextBox.Text = totalSeconds.ToString();
}
Instead of using a timer, record the start time using DateTime.Now and then subtract the current time (DateTime.Now) from the start time. This will give you a more accurate timer as it uses the system clock instead which isn't affected so much by CPU performance.
Alternatively you can use System.Diagnostics.Stopwatch which does this for you.
You can still use an ordinary timer with an interval of less than a second to refresh the label displaying the time.

PerformanceCounter in while loop

I am currently trying to write an application that runs the same code exactly 100 times a second. I have done some testing using the built-in timers of the .NET framework. I've tested the System.Threading.Timer class, the System.Windows.Forms.Timer class and the System.Timers.Timer class. None of them seem to be accurate enough for what I am trying to do.
I've found out about PerformanceCounters and am currently trying to implement such in my application.
However, I am having a bit of trouble with my program taking up a whole core of my CPU when idling.
I only need it to be active 100 times a second. My loop looks like this:
long nextTick, nextMeasure;
QueryPerformanceCounter(out start);
nextTick = start + countsPerTick;
nextMeasure = start + performanceFrequency;
long currentCount;
while (true)
{
QueryPerformanceCounter(out currentCount);
if (currentCount >= nextMeasure)
{
Debug.Print("Ticks this second: " + tickCount);
tickCount = 0;
nextMeasure += performanceFrequency;
}
if (currentCount >= nextTick)
{
Calculations();
tickCount++;
nextTick += countsPerTick;
}
}
As you can see, most of the time the program will be waiting to run Calculations() again by running through the while loop constantly. Is there a way to stop this from happening? I don't want to slow the computers my program will be run on down.
System.Thread.Thread.Sleep unfortunately is also pretty "inaccurate", but I would be okay with using it if there is no other solution.
What I am basically asking is this: Is there a way to make an infinite loop less CPU-intensive? Is there any other way of accurately waiting for a specific amount of time?
As I'm sure you're aware, Windows is not a real-time O/S, so there can never be any guarantee that your code will run as often as you want.
Having said that, the most efficient in terms of yielding to other threads is probably to use Thread.Sleep() as the timer. If you want higher accuracy than the default you can issue a timeBeginPeriod with the desired resolution down to a millisecond. The function must be DLLImported from winmm.dll.
timeBeginPeriod(1) together with a normal timer or Thread.Sleep should work decently.
Note that this has a global effect. There are claims that it increases power consumption, since it forces the windows timer to run more often, shortening the CPU sleeping periods. This means you should generally avoid it. But if you need highly accurate timing, it's certainly a better choice than a busy-wait.

Greater time resolution using .NET Micro Framework on Netduino board (for dimming an LED)?

I'm programming a Netduino board using the .NET Micro Framework 4.1 and want to get a higher time resolution than milliseconds. This is because I'm attempting to dim an LED by blinking it really fast.
The issue is that the sample code uses Thread.Sleep(..) which takes a number of milliseconds.
Sample code from http://netduino.com/projects/ showing the issue in question:
OutputPort ledOnboard = new OutputPort(Pins.ONBOARD_LED, false);
while (true)
{
ledOnboard.Write(true);
Thread.Sleep(1); // << PROBLEM: Can only get as low as 1 millisecond
Even if there's another way to accomplish dimming by not using a greater time resolution, I'm game.
This doesn't answer your question about getting a better time resolution, but it does solve your problem with changing the brightness on an LED. You should be using the PWM module for the Netduino.
Netduino Basics: Using Pulse Width Modulation (PWM) is a great article on how to use it.
I have had a similar problem in the past and used the following method to time in the microsecond range. The first line determines how many ticks are in a millisecond (its been a while since I used this, but I think 1 tick was 10 microseconds). The second line gets the amount of time the system has been on (in ticks). I hope this helps.
public const Int64 ticks_per_millisecond = System.TimeSpan.TicksPerMillisecond;
public static long GetCurrentTimeInTicks()
{
return Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks;
}
You can use a timer to raise an event instead of using sleep.
The Interval property on a timer is a double so you can have less than a millisecond on it.
http://msdn.microsoft.com/en-us/library/0tcs6ww8(v=VS.90).aspx
In his comment to Seidleroni's answer BrainSlugs83 suggests "sit in a busy loop and wait for the desired number of ticks to elapse. See the function I added in the edit". But I cannot see the function added to the edit. I assume it would be something like this:
using System;
using Microsoft.SPOT.Hardware;
private static long _TicksPerMicroSecond = TimeSpan.TicksPerMillisecond/1000;
private void Wait(long microseconds)
{
var then = Utility.GetMachineTime().Ticks;
var ticksToWait = microseconds * _TicksPerNanoSecond;
while (true)
{
var now = Utility.GetMachineTime().Ticks;
if ((now - then) > ticksToWait) break;
}
}
A point that you might not be thinking about is that your code is relying on the .NET System namespace, which is based on the real time clock in your PC. Notice that the answers rely on the timer in the device.
Moving forward, I would suggest that you take a moment to qualify the source of the information you are using in your code -- is it .NET proper (Which is fundamentally based on your PC), or the device the code is running on (Which will have a namespace other than System, for example)?
PWM is a good way to control DC current artificially (by varying the pulse width), but varying the PWM frequency will still be a function of time at the end of the day.
Rather than use delays....like Sleep....you might want to spawn a thread and have it manage the brightness. Using Sleep is still basically a straight line procedural method and your code will only be able to do this one thing if you use a single thread.

Categories