C# NAudio:保留最后一次录制的音频,并随时保存

C# NAudio:保留最后一次录制的音频,并随时保存,c#,.net,naudio,C#,.net,Naudio,我正在用NAudio编写一个音板,作为一个库来管理我的音频。我想要实现的功能之一是能够连续录制一个(或多个)音频输入,并能够随时保存它们 我认为这是可能的,因为它保留了一个循环缓冲区,用于存储音频输入拾取的最后一个示例:5s的样本 我还想避免将所有数据保留到启动时的状态,因为我不想过度使用内存 我尝试了很多方法来解决这个问题: 使用循环缓冲区并向其提供来自“DataAvailable”事件的数据 使用“队列”和“BufferedWaveProvider”添加缓冲区 数据并将其转换为样本 我试着使

我正在用NAudio编写一个音板,作为一个库来管理我的音频。我想要实现的功能之一是能够连续录制一个(或多个)音频输入,并能够随时保存它们

我认为这是可能的,因为它保留了一个循环缓冲区,用于存储音频输入拾取的最后一个示例:5s的样本

我还想避免将所有数据保留到启动时的状态,因为我不想过度使用内存

我尝试了很多方法来解决这个问题:

  • 使用循环缓冲区并向其提供来自“DataAvailable”事件的数据
  • 使用“队列”和“BufferedWaveProvider”添加缓冲区 数据并将其转换为样本
  • 我试着使用2“BufferedWaveProvider”,结果wich得到了 已满取决于哪个已满
  • 我还尝试使用2个波形输入和定时器来交替 录音
  • 我尝试使用字节数组并将其用作循环缓冲区。我使用“WaveInEvent”中的“DataAvailable”事件填充了缓冲区。“WaveInEventArgs”有一个缓冲区,所以我将其中的数据添加到循环缓冲区中

    private int _start = 0, _end = 0;
    private bool _filled = false;
    private byte[] _buffer; // the size was set in the constructor
                            // its an equation to figure out how many samples
                            // a certain time needs.
    
    private void _dataAvailable(object sender, WaveInEventArgs e)
    {
    
        for (int i = 0; i < e.BytesRecorded; i++)
        {
            if (_filled)
            {
                _start = _end + 1 > _buffer.Length - 1 ? _end + 1 : 0;
            }
            if (_end > _buffer.Length - 1 && !_filled) _filled = true;
            _end = _end > _buffer.Length - 1 ? _end + 1 : 0;
    
            _buffer[_end] = e.Buffer[i];
        }
    }
    
    private int _start=0,_end=0;
    private bool _filled=假;
    专用字节[]_缓冲区;//大小是在构造函数中设置的
    //这是一个计算有多少样本的方程式
    //需要一定的时间。
    私有无效数据可用(对象发送方,WaveInEventArgs e)
    {
    for(int i=0;i\u buffer.Length-1?\u结束+1:0;
    }
    如果(\u end>\u buffer.Length-1&&!\u filled)\u filled=true;
    _end=\u end>\u buffer.Length-1?\u end+1:0;
    _缓冲区[_end]=e.buffer[i];
    }
    }
    
    我所做的一些尝试是有效的,但大多数情况下,它们在最初的5秒钟内都有效(我知道使用“BufferredWaveProvider”可能会导致这个问题。我认为问题的一部分是缓冲区的开头需要一定量的数据,一旦缓冲区开始覆盖这些数据,音频播放器就会停止播放 问题的另一个很可能的原因是我刚刚开始使用NAudio,还没有完全理解它

    我已经被这个问题困扰了一段时间,我感谢所有人能给我的帮助

    我还有一些代码可以添加,但我认为这个问题已经很长了


    提前谢谢!

    您的
    \u dataAvailable
    方法中的代码对我来说很奇怪。我只需从开始到结束再从头开始写入字节,以此类推。然后,当您想要获取实际字节来保存它们时,创建一个新数组,从当前位置到结尾,从开始到结束当前位置。请检查下面的代码

    private int _pos = 0;
    private bool _isFull = false;
    private byte[] _buffer; // intialized in the constructor with the correct length
    
    private void _dataAvailable(object sender, WaveInEventArgs e)
    {
        for(int i = 0; i < e.BytesRecorded; ++i) {
            // save the data
            _buffer[_pos] = e.Buffer[i];
            // move the current position (advances by 1 OR resets to zero if the length of the buffer was reached)
            _pos = (_pos + 1) % _buffer.Length;
            // flag if the buffer is full (will only set it from false to true the first time that it reaches the full length of the buffer)
            _isFull |= (_pos == 0);
        }
    }
    
    public byte[] GetBytesToSave()
    {
        int length = _isFull ? _buffer.Length : _pos;
        var bytesToSave = new byte[length];
        int byteCountToEnd = _isFull ? (_buffer.Length - _pos) : 0;
        if(byteCountToEnd > 0) {
            // bytes from the current position to the end
            Array.Copy(_buffer, _pos, bytesToSave, 0, byteCountToEnd);
        }
        if(_pos > 0) {
            // bytes from the start to the current position
            Array.Copy(_buffer, 0, bytesToSave, byteCountToEnd, _pos);
        }
        return bytesToSave;
    }
    
    private int\u pos=0;
    private bool _isFull=false;
    私有字节[]\u buffer;//在构造函数中初始化,长度正确
    私有无效数据可用(对象发送方,WaveInEventArgs e)
    {
    对于(int i=0;i0){
    //从当前位置到结尾的字节数
    复制(_buffer,_pos,bytesToSave,0,byteCountToEnd);
    }
    如果(_pos>0){
    //从起始位置到当前位置的字节数
    复制(_buffer,0,bytesToSave,byteCountToEnd,_pos);
    }
    返回bytesToSave;
    }
    
    如果其他人想做类似的事情,我就离开全班。你想用就用吧

    using System;
    using NAudio.Wave;
    using System.Diagnostics;
    
    public class AudioRecorder
    {
        public WaveInEvent MyWaveIn;
        public readonly double RecordTime;
    
        private WaveOutEvent _wav = new WaveOutEvent();
        private bool _isFull = false;
        private int _pos = 0;
        private byte[] _buffer;
        private bool _isRecording = false;
    
        /// <summary>
        /// Creates a new recorder with a buffer
        /// </summary>
        /// <param name="recordTime">Time to keep in buffer (in seconds)</param>
        public AudioRecorder(double recordTime)
        {
            RecordTime = recordTime;
            MyWaveIn = new WaveInEvent();
            MyWaveIn.DataAvailable += DataAvailable;
            _buffer = new byte[(int)(MyWaveIn.WaveFormat.AverageBytesPerSecond * RecordTime)];
        }
    
        /// <summary>
        /// Starts recording
        /// </summary>
        public void StartRecording()
        {
            if (!_isRecording)
            {
                try
                {
                    MyWaveIn.StartRecording();
                }
                catch (InvalidOperationException)
                {
                    Debug.WriteLine("Already recording!");
                }
            }
    
            _isRecording = true;
        }
    
        /// <summary>
        /// Stops recording
        /// </summary>
        public void StopRecording()
        {
            MyWaveIn.StopRecording();
            _isRecording = false;
        }
    
        /// <summary>
        /// Play currently recorded data
        /// </summary>
        public void PlayRecorded() 
        {
            if (_wav.PlaybackState == PlaybackState.Stopped)
            {
                var buff = new BufferedWaveProvider(MyWaveIn.WaveFormat);
                var bytes = GetBytesToSave();
                buff.AddSamples(bytes, 0, bytes.Length);
                _wav.Init(buff);
                _wav.Play();
            }
    
        }
    
        /// <summary>
        /// Stops replay
        /// </summary>
        public void StopReplay()
        {
            if (_wav != null) _wav.Stop();
        }
    
        /// <summary>
        /// Save to disk
        /// </summary>
        /// <param name="fileName"></param>
        public void Save(string fileName)
        {
            var writer = new WaveFileWriter(fileName, MyWaveIn.WaveFormat);
            var buff = GetBytesToSave();
            writer.Write(buff, 0 , buff.Length);
            writer.Flush();
        }
    
    
        private void DataAvailable(object sender, WaveInEventArgs e)
        {
    
            for (int i = 0; i < e.BytesRecorded; ++i)
            {
                // save the data
                _buffer[_pos] = e.Buffer[i];
                // move the current position (advances by 1 OR resets to zero if the length of the buffer was reached)
                _pos = (_pos + 1) % _buffer.Length;
                // flag if the buffer is full (will only set it from false to true the first time that it reaches the full length of the buffer)
                _isFull |= (_pos == 0);
            }
        }
    
        public byte[] GetBytesToSave()
        {
            int length = _isFull ? _buffer.Length : _pos;
            var bytesToSave = new byte[length];
            int byteCountToEnd = _isFull ? (_buffer.Length - _pos) : 0;
            if (byteCountToEnd > 0)
            {
                // bytes from the current position to the end
                Array.Copy(_buffer, _pos, bytesToSave, 0, byteCountToEnd);
            }
            if (_pos > 0)
            {
                // bytes from the start to the current position
                Array.Copy(_buffer, 0, bytesToSave, byteCountToEnd, _pos);
            }
            return bytesToSave;
        }
    
        /// <summary>
        /// Starts recording if WaveIn stopped
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Stopped(object sender, StoppedEventArgs e)
        {
            Debug.WriteLine("Recording stopped!");
            if (e.Exception != null) Debug.WriteLine(e.Exception.Message);
            if (_isRecording)
            {
                MyWaveIn.StartRecording();
            }
        }
    }
    
    使用系统;
    使用NAudio.波;
    使用系统诊断;
    公共级录音机
    {
    公共WaveInEvent MyWaveIn;
    公共只读双记录时间;
    私有WaveOutEvent_wav=新的WaveOutEvent();
    private bool _isFull=false;
    私有int_pos=0;
    专用字节[]_缓冲区;
    私有bool _isRecording=false;
    /// 
    ///创建带有缓冲区的新记录器
    /// 
    ///保留在缓冲区中的时间(秒)
    公共录音机(双记录时间)
    {
    记录时间=记录时间;
    MyWaveIn=新的WaveInEvent();
    MyWaveIn.DataAvailable+=DataAvailable;
    _缓冲区=新字节[(int)(MyWaveIn.WaveFormat.AverageBytesPerSecond*记录时间)];
    }
    /// 
    ///开始录音
    /// 
    公共无效开始记录()
    {
    如果(!\u正在记录)
    {
    尝试
    {
    MyWaveIn.StartRecording();
    }
    捕获(无效操作异常)
    {
    Debug.WriteLine(“已录制!”);
    }
    }
    _isRecording=true;
    }
    /// 
    ///停止录制
    /// 
    公开作废停止录制()
    {
    MyWaveIn.StopRecording();
    _isRecording=false;
    }
    /// 
    ///播放当前录制的数据
    /// 
    公众假期
    {
    如果(_wav.PlaybackState==PlaybackState.Stopped)
    {
    var buff=新的BufferedWaveProvider(MyWaveIn.WaveFormat);
    var bytes=GetBytesToSave();
    buff.AddSamples(字节,0,字节.长度);
    _初始波形(浅黄色);
    _wav.Play();
    }
    }
    /// 
    ///停止重播
    /// 
    公共void StopReplay()
    {
    如果(_wav!=null)_wav.S