开发者

Gapless (looping) audio playback with DirectX in 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 smal开发者_StackOverflow社区l 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜