NAudio: Сохранение последних записей: 5 с записанного звука и сохранение его в любое время - PullRequest
1 голос
/ 15 июня 2019

Я кодирую деки, используя NAudio в качестве библиотеки для управления звуком.Одной из функций, которые я хочу реализовать, является возможность непрерывной записи одного (или нескольких) аудиовходов и возможность в любое время сохранять их.

Способ, которым я вижу это, заключается в том, чтобы держать циркулярбуфер последних примеров: 5 сэмплов, взятых аудиовходом.

Я также хочу избежать сохранения всех данных до того момента, когда они начались, поскольку я не хочу чрезмерно использовать память.

Я пробовал много подходов к этой проблеме:

  1. Использование кругового буфера и подача его с данными из события «DataAvailable»;
  2. Использование «Queue» и «BufferedWaveProvider»чтобы добавить данные буфера и преобразовать его в образец.
  3. Я попытался использовать 2 "BufferedWaveProvider" и чередование, которое заполнялось, в зависимости от того, что было заполнено.
  4. Я также пытался использовать 2 волнывходы и таймеры для чередования, который записывал.

Я попытался использовать массив байтов и использовать его в качестве циклического буфера.Я заполнил буфер, используя событие «DataAvailable» из «WaveInEvent».«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];
    }
}

Некоторые из попыток, которые я предпринял, сработали, но в большинстве случаев они работали в первый раз.5 секунд (я знаю, что использование «BufferredWaveProvider» может вызвать эту проблему. Я думаю, что часть проблемы заключается в том, что существует определенный объем данных, который требуется в начале буфера, и как только буфер запускаетсяПерезаписывая эти данные, аудиопроигрыватель не

Другая очень вероятная причина проблемы заключается в том, что я только начинаю использовать NAudio и пока не совсем понимаю его.

Я застрял сЭта проблема уже давно, и я благодарен за любую помощь, которую кто-либо может мне дать.

У меня есть еще немного кода, который я мог бы добавить, но я думал, что этот вопрос уже удлиняется.

Спасибозаранее!

Ответы [ 2 ]

1 голос
/ 15 июня 2019

Если кто-то еще захочет сделать что-то похожее, я ухожу из всего класса. Используйте его как хотите.

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();
        }
    }
}
0 голосов
/ 15 июня 2019

Код внутри вашего _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;
}
...