Подготовка звуковых данных при необходимости

Я использую libPd для генерации звука. LibPd может обрабатывать предопределенное количество тиков, а затем заполнять float[] сгенерированным выводом. Затем я использую BufferedWaveProvider для хранения float[] после преобразования в byte[].

Генерация звука может быть очень быстрой, поэтому можно вычислить 1 секунду звука за довольно короткое время, но она также может быть медленной, в зависимости от патча Pd. Есть ли способ инициировать обработку данных, когда в BufferedWaveProvider осталось меньше предопределенного объема данных?

В настоящее время я генерирую звук в фоновом потоке, просто сплю некоторое время и надеюсь, что этого достаточно, и надеюсь, что BufferedWaveProvider не переполнится, и даже когда, а затем отбрасываю эти данные.

public void ProcessData(float[] output, int ticks)
{
    while (LibPD.Process(ticks, new float[0], output) == 0)
    {
        if (BufferReady != null)
        {
            BufferReady(this, new BufferReadyEventArgs(output));
        }
        Thread.Sleep(999*BlockSize * ticks / 44100);
    }
} 

public void StartProcessing(float[] output)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(SetPdOutput), output);
}

private void SetPdOutput(object state)
{
    float[] output = state as float[];
    if (state == null)
    {
        return;
    }
    ProcessData(output, Ticks);
}

В то время как мой код для склеивания libPd и NAudio таков:

Buffer = new float[2 * _player.Ticks * _player.BlockSize]; // stereo, number of Ticks
_soundOutput = new WasapiOut(AudioClientShareMode.Shared, 100);
_audioBuffer = new BufferedWaveProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 2))
{
    BufferDuration = TimeSpan.FromSeconds(10),
    DiscardOnBufferOverflow = true
};
_soundOutput.Init(_audioBuffer);
_soundOutput.Play();

_player.BufferReady += ((sender, eventArgs) =>
{
    _audioBuffer.AddSamples(PcmFromFloat(output), 0, output.Length * 4);
});
_player.StartProcessing(Buffer);

person Residuum    schedule 29.01.2016    source источник


Ответы (1)


Прочитав исходный код NAudio, я пришел к другому решению: написать собственный IWaveProvider, который использует CircularBuffer, аналогичный BufferedWaveProvider, но запрашивает новый обработанный звук из lidPd всякий раз, когда пороговое значение ниже порога.

Суть операции:

class PdProvider : IWaveProvider
{
    readonly CircularBuffer _circularBuffer;

    public PdProvider()
    {
        _buffer = new float[BufferSize];
        _player.BufferReady += PdBufferReady;
        _circularBuffer =  new CircularBuffer(SampleRate * 5); // 5 seconds should be enough for anybody
        _minBuffer =  SampleRate / 2; // 0.5 second
        RefillBuffer();
    }

    void RefillBuffer()
    {
        if (_circularBuffer.Count < _minBuffer)
        {
            // Get data from libPd and add to _circularBuffer
        }
    }

    public int Read(byte[] buffer, int offset, int count)
    {
        var read = _circularBuffer.Read(buffer, offset, count);
        RefillBuffer();
        return read;
    }

    public WaveFormat WaveFormat
    {
        get
        {
            return WaveFormat.CreateIeeeFloatWaveFormat(_player.SampleRate, 2);
        }
    }
}
person Residuum    schedule 31.01.2016
comment
да, это предпочтительный способ ведения дел - создание собственного собственного IWaveProvider - person Mark Heath; 10.02.2016