如何知道什么时候声音播放完毕播放声音 [英] How to know when SoundPlayer has finished playing a sound

查看:167
本文介绍了如何知道什么时候声音播放完毕播放声音的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用下面的code动态异步在内存中创建一个频率音调并播放了口气:

I am using the following code to dynamically create a frequency tone in memory and play the tone asynchronously:

public static void PlayTone(UInt16 frequency, int msDuration, UInt16 volume = 16383)
{
    using (var mStrm = new MemoryStream())
    {
        using (var writer = new BinaryWriter(mStrm))
        {
            const double tau = 2*Math.PI;
            const int formatChunkSize = 16;
            const int headerSize = 8;
            const short formatType = 1;
            const short tracks = 1;
            const int samplesPerSecond = 44100;
            const short bitsPerSample = 16;
            const short frameSize = (short) (tracks*((bitsPerSample + 7)/8));
            const int bytesPerSecond = samplesPerSecond*frameSize;
            const int waveSize = 4;
            var samples = (int) ((decimal) samplesPerSecond*msDuration/1000);
            int dataChunkSize = samples*frameSize;
            int fileSize = waveSize + headerSize + formatChunkSize + headerSize + dataChunkSize;

            writer.Write(0x46464952);
            writer.Write(fileSize);
            writer.Write(0x45564157);
            writer.Write(0x20746D66);
            writer.Write(formatChunkSize);
            writer.Write(formatType);
            writer.Write(tracks);
            writer.Write(samplesPerSecond);
            writer.Write(bytesPerSecond);
            writer.Write(frameSize);
            writer.Write(bitsPerSample);
            writer.Write(0x61746164);
            writer.Write(dataChunkSize);

            double theta = frequency*tau/samplesPerSecond;
            double amp = volume >> 2;
            for (int step = 0; step < samples; step++)
            {
                writer.Write((short) (amp*Math.Sin(theta*step)));
            }

            mStrm.Seek(0, SeekOrigin.Begin);
            using (var player = new System.Media.SoundPlayer(mStrm))
            {
                player.Play();
            }
        }
    }
}

在code是工作的罚款。唯一的问题是,我怎么知道什么时候语气也停止播放?似乎没有要上的SoundPlayer类已完成的事件,我可以订阅。

The code is working fine. The only issue is, how do I know when the tone has stopped playing? There doesn't appear to be a Completed event on the SoundPlayer class that I can subscribe to.

推荐答案

您知道吗,如果你想要做的就是打单色调,还有的 Console.Beep 。当然,它不会做它在后台,但我在下面描述的技术将工作的优良 Console.Beep ,而且美元,你不必产生p $ pvents内存流只是起到一个音。

You know, if all you want to do is play a single tone, there is Console.Beep. Granted, it doesn't do it in the background, but the technique I describe below will work fine for Console.Beep, and it prevents you having to create a memory stream just to play a tone.

在任何情况下,声音播放没有你想要的功能,但是你可以模拟它。

In any case, SoundPlayer doesn't have the functionality that you want, but you can simulate it.

首先,创建事件处理程序:

First, create your event handler:

void SoundPlayed(object sender, EventArgs e)
{
    // do whatever here
}

更改普雷通公司方法,以便它需要一个回调函数的参数:

Change your PlayTone method so that it takes a callback function parameter:

public static void PlayTone(UInt16 frequency, int msDuration, UInt16 volume = 16383, EventHandler doneCallback = null)

然后,改变方法的末尾,以便它调用 PlaySync ,而不是播放,并调用 doneCallback ,它的完成之后:

Then, change the end of the method so that it calls PlaySync rather than Play, and calls the doneCallback after it's done:

using (var player = new System.Media.SoundPlayer(mStrm))
{
    player.PlaySync();
}    
if (doneCallback != null)
{
    // the callback is executed on the thread.
    doneCallback(this, new EventArgs());
}

然后,在一个线程或任务执行。例如:

Then, execute it in a thread or a task. For example:

var t = Task.Factory.StartNew(() => {PlayTone(100, 1000, 16383, SoundPlayed));

与此主要问题是,在后台线程时发生的事件的通知。也许,如果你需要影响的用户界面是让事件处理程序的UI线程同步的最好的事情。所以在 SoundPlayed 方法,你会打电话 Form.Invoke (为的WinForms)或 Dispatcher.Invoke (WPF)执行任何UI操作。

The primary problem with this is that the event notification occurs on the background thread. Probably the best thing to do if you need to affect the UI is to have the event handler synchronize with the UI thread. So in the SoundPlayed method, you'd call Form.Invoke (for WinForms) or Dispatcher.Invoke (WPF) to execute any UI actions.

这篇关于如何知道什么时候声音播放完毕播放声音的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆