c# - 如何使用 SoundPlayer 淡出 .wav 文件的音频而不是立即停止?

标签 c# winforms soundplayer

我试图在松开按钮后立即停止声音,但结果是该文件已完全播放。 我不想像 sp.Stop() 那样突然停止声音。 有办法做到这一点吗?

private void button1_MouseDown(object sender, MouseEventArgs e)
{
    if(sender == mk)
    {
        if(e.Button == MouseButtons.Left)
        {
            SoundPlayer sp = new SoundPlayer();

            sp.SoundLocation = (@"C:\my path\sound.wav");
            sp.Play();
        }
    }
}

private void button1_MouseUp(object sender, MouseEventArgs e)
{
    if(sender == mk)
    {
        if(e.Button == MouseButtons.Left)
        { /*some code here (without sp.Stop())*/ }
    }
}

最佳答案

我将您的问题解释为:

How do I fade out the audio of a .wav file using SoundPlayer instead of stopping it immediately?

简短的回答是,您不能单独使用 SoundPlayer 来做到这一点。您需要使用 winmm.dll 库中的几个 API。

如果您熟悉 WPF,那么在其体积属性上使用 MediaElementDoubleAnimation 可能是更好的方法。参见 this有关信息的问题。

但是,如果您真的想使用 WinForms,下面是一个应该可行的实现。

关于 Form1 的注释:

  • 两个按钮,分别命名为startButtonstopButton
  • 一个名为 timer1 的计时器,我用它来淡出声音

下面是实现这个功能的代码:

using System;
using System.Media;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{

    public partial class Form1 : Form
    {

        [DllImport("winmm.dll", EntryPoint = "waveOutGetVolume")]
        private static extern int WaveOutGetVolume(IntPtr hwo, out uint dwVolume);

        [DllImport("winmm.dll", EntryPoint="waveOutSetVolume")]
        private static extern int WaveOutSetVolume(IntPtr hwo, uint dwVolume);

        private SoundPlayer player = new SoundPlayer();

        // a crude delta time field
        private float totalElapsedTime;

        // tweak this value to determine how quickly you want the fade to happen
        private const float Velocity = 0.001f;

        public Form1()
        {
            this.InitializeComponent();

            // i was using 100 milliseconds as my "frame rate"
            this.timer1.Interval = 100;
            this.stopButton.Enabled = false;
        }

        private void startButton_Click(object sender, EventArgs e)
        {
            // sets the audio device volume to the max.
            // this is not the computer's volume so it won't
            // blast out your ear drums by doing this unless you
            // have the computer volume super high - which is not this
            // code's fault
            WaveOutSetVolume(IntPtr.Zero, uint.MaxValue);

            this.startButton.Enabled = false;
            this.stopButton.Enabled = true;

            this.totalElapsedTime = 0f;
            this.player.SoundLocation = @"Music File.wav";
            this.player.Load();
            this.player.Play();
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            // being the stop
            this.timer1.Start();
            this.stopButton.Enabled = false;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            // amount to interpolate (value between 0 and 1 inclusive)
            float amount = Math.Min(1f, this.totalElapsedTime * Velocity);

            // the new channel volume after a lerp
            float lerped = Lerp(ushort.MaxValue, 0, amount);

            // each channel's volume is actually represented as a ushort
            ushort channelVolume = (ushort)lerped;

            // the new volume for all the channels
            uint volume = (uint)channelVolume | ((uint)channelVolume << 16);

            // sets the volume 
            WaveOutSetVolume(IntPtr.Zero, volume);

            // checks if the interpolation is finished
            if (amount >= 1f)
            {
                // stop the timer 
                this.timer1.Stop();

                // stop the player
                this.player.Stop();

                // stop is complete so let user start again
                this.startButton.Enabled = true;
            }

            // add the elapsed milliseconds (very crude delta time)
            this.totalElapsedTime += this.timer1.Interval;
        }

        public static float Lerp(float value1, float value2, float amount)
        {
            // does a linear interpolation
            return (value1 + ((value2 - value1) * amount));
        }

    }

}

希望这应该是不言自明的。我认为大多数人会认为这是一种粗略的“游戏循环式”方法,但它似乎运作良好。这里需要注意的是,调整淡入淡出的速度是 Velocity 常量。

代码设置为淡出超过 1 秒。通过查看 timer1.IntervalVelocity 很容易弄清楚这一点。 1000 毫秒(10 个计时器滴答)后,1000 * 0.001 = 1 导致停止代码完成。

更改 timer1.Interval 的唯一原因是为了让更多的“淡入淡出”发生。当前设置在停止前执行 10 次音量衰减。

关于c# - 如何使用 SoundPlayer 淡出 .wav 文件的音频而不是立即停止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34277066/

相关文章:

c# - 如何将按钮添加到 DataGridView 中的列

c# - XML声音的字节格式

c# - 从内存中播放 wav/mp3

C# SoundPlayer 类未在指定路径找到文件

c# - 将图像文件保存到数据库中

C# 抽象类,用于数组初始化

c# - HttpClient - 任务被取消异常

c# - 如何将内存流转换为 System.Data.Linq.Binary?

c# - 发布版本中 visual studio 2010 中的核心转储

c# - 是否有Visual Studio之类的代码编辑器控件?