如何使用 SoundPlayer 淡出 .wav 文件的音频而不是立即停止?
How do I fade out the audio of a .wav file using SoundPlayer instead of stopping it immediately?
我试图在松开按钮后立即停止声音,但结果是该文件已完全播放。
我不想像 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,那么使用 MediaElement
和 DoubleAnimation
的卷 属性 可能是更好的方法。有关这方面的信息,请参阅 this 问题。
但是,如果您真的想使用 WinForms,下面是一个应该可行的实现。
关于Form1
的注释:
- 两个按钮,名为
startButton
和 stopButton
- 一个名为
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));
}
}
}
希望这应该是不言自明的。我认为大多数人会认为这是一种粗略的 "game-loop-esqe" 方法,但它似乎运作良好。这里需要注意的是,调整淡入淡出的速度是 Velocity
常数。
代码设置为在 1 秒内淡出。通过查看 timer1.Interval
和 Velocity
很容易看出这一点。 1000 毫秒(10 个计时器滴答声)后 1000 * 0.001 = 1 导致停止代码完成。
更改 timer1.Interval
的唯一原因是为了让更多 "fades" 发生。当前设置在停止前执行 10 次音量衰减。
我试图在松开按钮后立即停止声音,但结果是该文件已完全播放。
我不想像 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,那么使用 MediaElement
和 DoubleAnimation
的卷 属性 可能是更好的方法。有关这方面的信息,请参阅 this 问题。
但是,如果您真的想使用 WinForms,下面是一个应该可行的实现。
关于Form1
的注释:
- 两个按钮,名为
startButton
和stopButton
- 一个名为
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));
}
}
}
希望这应该是不言自明的。我认为大多数人会认为这是一种粗略的 "game-loop-esqe" 方法,但它似乎运作良好。这里需要注意的是,调整淡入淡出的速度是 Velocity
常数。
代码设置为在 1 秒内淡出。通过查看 timer1.Interval
和 Velocity
很容易看出这一点。 1000 毫秒(10 个计时器滴答声)后 1000 * 0.001 = 1 导致停止代码完成。
更改 timer1.Interval
的唯一原因是为了让更多 "fades" 发生。当前设置在停止前执行 10 次音量衰减。