最近做的项目需要用到C#的录音功能,在网上找了不少资源,大部分都是说使用DX来录音,下载下来demo大部分都是缺少东西,也确实是没有弄明白。下面介绍一个简单的录音方式,这也是翻阅了大神的博客了解到的,在这里进行了一些本地化的扩展。

在这个操作类下公开了两个方法和两个事件,方法分别是开始录音和结束录音,在结束录音时,可以传递一个参数作为取消录音的控制,传入true后将不会保存出文件。

这两个事件,一个时实时反馈进度的事件,可以使你实时控制进度条的显示,一个是录制完成的事件,即当你控制录制结束时,就会产生该事件,这个时间返回了录制的时间(采用进1法),录制的语音文件地址,是否是被取消的状态。事件的参数类这里没有给出,可以根据传递的参数自行添加或修改。

/// <summary>
/// 语音录制控制类
/// </summary>
public class RecordingAudio
{
/// <summary>
/// 录制完成事件,该事件只会在UI线程上执行
/// </summary>
public event EventHandler<RecordingFinishEventArgs> OnRecordingFinish;
/// <summary>
/// 录制进度事件,该事件只会在UI线程上执行
/// </summary>
public event EventHandler<RecordingProgressEventArgs> OnRecordingProgress;


private int duration = 0;
private Timer timer;

/// <summary>
/// 接收的主线程控件,使跨线程的操作回归到主线程上产生事件
/// </summary>
private Control control;

/// <summary>
/// 锁
/// </summary>
private object _obj = new object();

public RecordingAudio(Control control)
{
this.control = control;
this.timer = new Timer(200);
this.timer.Elapsed += timer_Tick;
}

/// <summary>
/// 获取当前是否是正在录制状态
/// </summary>
public bool IsRecordingAudio { get; private set; }


[DllImport("winmm.dll", EntryPoint = "mciSendString", CharSet = CharSet.Auto)]
public static extern int mciSendString(
string lpstrCommand,
string lpstrReturnString,
int uReturnLength,
int hwndCallback
);

/// <summary>
/// 更新进度
/// </summary>
/// <param name="p">进度值</param>
private void UpdateProgress(double p)
{
if (OnRecordingProgress != null)
{
this.control.Dispatcher.Invoke(new Action(() =>
{
OnRecordingProgress(this, new RecordingProgressEventArgs(p));
}));
}
}

/// <summary>
/// 录制完成
/// </summary>
private void RecordingFinish(int t, string path, bool isCancle)
{
if (OnRecordingFinish != null)
{
this.control.Dispatcher.Invoke(new Action(() =>
{
OnRecordingFinish(this, new RecordingFinishEventArgs(t, path, isCancle));
}));
}
}


/// <summary>
/// 开始录制
/// </summary>
public void Start()
{
lock (_obj)
{
if (IsRecordingAudio) return;

mciSendString("set wave bitpersample 8", "", 0, 0);

mciSendString("set wave samplespersec 20000", "", 0, 0);
mciSendString("set wave channels 2", "", 0, 0);
mciSendString("set wave format tag pcm", "", 0, 0);
mciSendString("open new type WAVEAudio alias movie", "", 0, 0);

mciSendString("record movie", "", 0, 0);

duration = 0;
timer.Enabled = true;

IsRecordingAudio = true;

UpdateProgress(duration);
}
}

private void timer_Tick(object sender, ElapsedEventArgs e)
{
duration++;
UpdateProgress(duration * 200 / 1000.0);
}

/// <summary>
/// 停止录制
/// </summary>
/// <param name="isCancle">是否是取消录制,默认为false</param>
/// <returns></returns>
public void Stop(bool isCancle = false)
{
lock (_obj)
{
if (!IsRecordingAudio) return;
timer.Enabled = false;

FileUtils.CheckAndCreateFolder();
string wavPath = "resource/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".wav";
string mp3Path = "resource/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".mp3";
string basePath = AppDomain.CurrentDomain.BaseDirectory;

mciSendString("stop movie", "", 0, 0);
if (!isCancle)
{
mciSendString("save movie " + wavPath, "", 0, 0);
}
mciSendString("close movie", "", 0, 0);

IsRecordingAudio = false;

int s = duration * 200;
RecordingFinish(s % 1000 == 0 ? s / 1000 : s / 1000 + 1, basePath + mp3Path, isCancle);
}
}
} 
<Grid x:Name="soundGrid" Visibility="Visible" Margin="0,0,0,125" Height="35" VerticalAlignment="Bottom" Background="#FFECECEC">
            <!--<ProgressBar x:Name="soundProgress" Maximum="55" Margin="60,10,205,10" Background="#FFBDBDBD" BorderBrush="{x:Null}"/>-->
            <local:ProgressBarControl x:Name="soundProgress" Maximum="55" ProgressBackground="#FFECECEC" ProgressColor="#FF7DFF41"/>
            <Label Content="语音录制中" HorizontalAlignment="Left" Margin="10,5,0,0" VerticalAlignment="Top"/>
            <Button x:Name="enterSendSound" Cursor="Hand" Margin="0,5,70,0" Background="#FF75BDFF" VerticalAlignment="Top" HorizontalAlignment="Right" Width="50" Click="enterSendSound_Click">
                <Button.Template>
                    <ControlTemplate>
                        <Border Background="#FF75BDFF" CornerRadius="5,5,5,5">
                            <Label  Content="确定" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
            <Button x:Name="cancelSendSound" Cursor="Hand" Margin="0,5,10,0" Background="#FFFFB924" VerticalAlignment="Top" HorizontalAlignment="Right" Width="50" Click="cancelSendSound_Click">
                <Button.Template>
                    <ControlTemplate>
                        <Border Background="#FFFFB924" CornerRadius="5,5,5,5">
                            <Label  Content="取消" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
                        </Border>
                    </ControlTemplate>
                </Button.Template>
            </Button>
            <!--<Label x:Name="soundTip" Content="55s/55s" Margin="0,5,140,0" VerticalAlignment="Top" HorizontalAlignment="Right" Width="60"/>-->

        </Grid>

只是有一个录制的进度。

​编辑ProgressBarControl 自定义控件

XAML:

<Grid>
        <Rectangle x:Name="progressBG" Fill="White" StrokeThickness="0" />
        <Rectangle x:Name="progressValue" HorizontalAlignment="Left" Width="0" StrokeThickness="0" />
        <Label x:Name="progressTip" Content="" Padding="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>

代码:

/// <summary>
    /// ProgressBarControl.xaml 的交互逻辑
    /// </summary>
    public partial class ProgressBarControl : UserControl
    {
        public ProgressBarControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 获取或设置进度条的背景色
        /// </summary>
        [Description("获取或设置进度条的背景色")]
        public System.Windows.Media.Brush ProgressBackground
        {
            get { return progressBG.Fill; }
            set { progressBG.Fill = value; }
        }

        /// <summary>
        /// 获取或设置进度条的边框色
        /// </summary>
        [Description("获取或设置进度条的边框色")]
        public System.Windows.Media.Brush ProgressStroke
        {
            get { return progressBG.Stroke; }
            set { progressBG.Stroke = value; }
        }

        /// <summary>
        /// 获取或设置进度条的边框粗细
        /// </summary>
        [Description("获取或设置进度条的边框粗细")]
        public double ProgressStrokeThickness
        {
            get { return progressBG.StrokeThickness; }
            set { progressBG.StrokeThickness = value; }
        }

        /// <summary>
        /// 获取或设置进度条的进度色
        /// </summary>
        [Description("获取或设置进度条的进度色")]
        public System.Windows.Media.Brush ProgressColor
        {
            get { return progressValue.Fill; }
            set { progressValue.Fill = value; }
        }

        /// <summary>
        /// 获取或设置进度条提示信息
        /// </summary>
        [Description("获取或设置进度条提示信息")]
        public string HintProgress
        {
            get { return progressTip.Content.ToString(); }
            set { progressTip.Content = value; }
        }

        /// <summary>
        /// 获取或设置进度条提示信息文字大小
        /// </summary>
        [Description("获取或设置进度条提示信息文字大小")]
        public double HintFontSize
        {
            get { return progressTip.FontSize; }
            set { progressTip.FontSize = value; }
        }

        /// <summary>
        /// 获取或设置进度条提示信息字体颜色
        /// </summary>
        [Description("获取或设置进度条提示信息字体颜色")]
        public System.Windows.Media.Brush HintForeground
        {
            get { return progressTip.Foreground; }
            set { progressTip.Foreground = value; }
        }

        private double _Maximum = 100.0;

        /// <summary>
        /// 获取或设置进度条的最大进度值,默认值为100
        /// </summary>
        /// <exception cref="InvalidOperationException">进度值不可小于等于零</exception>
        [Description("获取或设置进度条的最大进度值")]
        public double Maximum
        {
            get { return _Maximum; }
            set 
            {
                if (value <= 0)
                    throw new InvalidOperationException("进度值不可小于等于零");
                _Maximum = value;
            }
        }

        private double _Value;

        /// <summary>
        /// 获取或设置进度条的进度值
        /// </summary>
        /// <exception cref="InvalidOperationException">进度值不能小于0且不能大于进度最大值</exception>
        [Description("获取或设置进度条的进度值")]
        public double Value
        {
            get { return _Value; }
            set
            {
                if (value < 0)
                    throw new InvalidOperationException("进度值不可小于零");
                else if(value > _Maximum)
                    throw new InvalidOperationException("进度值不可大于最大进度值");
                _Value = value;

                this.progressValue.Width = (_Value / _Maximum) * this.progressBG.ActualWidth;
            }
        }




    }

这里录制完成时wav文件,某些需求可能是需要装换为MP3格式,针对音频装换也有开源的代码。