Speex Echo Canceller добавляет глючный звук C#C#

Место общения программистов C#
Ответить
Anonymous
 Speex Echo Canceller добавляет глючный звук C#

Сообщение Anonymous »

Итак, я написал небольшую тестовую программу, которая использует адаптивный эхоподавитель Speex с NAudio в моей оболочке FFI libspeexdsp C#. Это работает правильно, но, к сожалению, при использовании эхокомпенсатора на выходе возникают некоторые шумные артефакты. Подключение буфера непосредственно к выводу не приводит к появлению этих артефактов, так это как-то связано с таймингом и тем, как они взаимодействуют друг с другом, или это что-то еще, о чем я не знаю?
This is the main program file
using NAudio.Wave;
using Tester;

var format = new WaveFormat(48000, 1);
var buffer = new BufferedWaveProvider(format) { ReadFully = true };
var echo = new EchoCancellationWaveProvider(20, 100, buffer);
var recorder = new WaveInEvent()
{
WaveFormat = format,
BufferMilliseconds = 20
};
var output = new WaveOutEvent()
{
DesiredLatency = 100
};

recorder.DataAvailable += Recorder_DataAvailable;

output.Init(echo);
output.Play();
recorder.StartRecording();

void Recorder_DataAvailable(object? sender, WaveInEventArgs e)
{
try
{
echo.Cancel(e.Buffer);
buffer.AddSamples(e.Buffer, 0, e.BytesRecorded);
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}

Console.ReadLine();


The echo cancellation wrapper over the native functions
using SpeexDSPSharp.Core.SafeHandlers;
using System;

namespace SpeexDSPSharp.Core
{
public class SpeexEchoCanceller
{
private readonly SpeexEchoStateSafeHandler _handler;
private bool _disposed;

public SpeexEchoCanceller(int frame_size, int filter_length)
{
_handler = NativeHandler.speex_echo_state_init(frame_size, filter_length);
}

public SpeexEchoCanceller(int frame_size, int filter_length, int nb_mic, int nb_speaker)
{
_handler = NativeHandler.speex_echo_state_init_mc(frame_size, filter_length, nb_mic, nb_speaker);
}

~SpeexEchoCanceller()
{
Dispose(false);
}

public void Reset()
{
ThrowIfDisposed();
NativeHandler.speex_echo_state_reset(_handler);
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

public unsafe void EchoCancel(short[] rec, short[] play, out short[] output)
{
ThrowIfDisposed();
output = new short[rec.Length];

fixed (short* recPtr = rec)
fixed (short* playPtr = play)
fixed (short* outPtr = output)
{
NativeHandler.speex_echo_cancellation(_handler, recPtr, playPtr, outPtr);
}
}

public unsafe void EchoCapture(short[] rec, out short[] output)
{
ThrowIfDisposed();
output = new short[rec.Length];

fixed (short* recPtr = rec)
fixed (short* outPtr = output)
{
NativeHandler.speex_echo_capture(_handler, recPtr, outPtr);
}
}

public unsafe void EchoPlayback(short[] play)
{
ThrowIfDisposed();
fixed (short* playPtr = play)
{
NativeHandler.speex_echo_playback(_handler, playPtr);
}
}

public unsafe int Ctl(EchoCancellationCtl request, ref int value)
{
ThrowIfDisposed();
var result = NativeHandler.speex_echo_ctl(_handler, (int)request, ref value);
CheckError(result);
return result;
}

protected virtual void Dispose(bool disposing)
{
if (_disposed) return;

if (disposing)
{
if (!_handler.IsClosed)
_handler.Close();
}

_disposed = true;
}

protected virtual void ThrowIfDisposed()
{
if (_disposed)
throw new ObjectDisposedException(GetType().FullName);
}

protected static void CheckError(int result)
{
if (result < 0)
throw new SpeexException(result.ToString());
}
}
}

The NAudio implementation of the speexdsp wrapper
using NAudio.Wave;
using SpeexDSPSharp.Core;

namespace Tester
{
public class EchoCancellationWaveProvider : IWaveProvider
{
private IWaveProvider _source;
private SpeexEchoCanceller _canceller;

public WaveFormat WaveFormat => _source.WaveFormat;

public EchoCancellationWaveProvider(int frame_size_ms, int filter_length_ms, IWaveProvider source)
{
_source = source;
var sampleRate = WaveFormat.SampleRate;
var frame_size = frame_size_ms * sampleRate / 1000;
var filter_length = filter_length_ms * sampleRate / 1000;

_canceller = new SpeexEchoCanceller(frame_size, filter_length);
_canceller.Ctl(EchoCancellationCtl.SPEEX_ECHO_SET_SAMPLING_RATE, ref sampleRate);
}

public int Read(byte[] buffer, int offset, int count)
{
int samplesRead = _source.Read(buffer, offset, count);
var shortBuffer = new short[buffer.Length / 2];

Buffer.BlockCopy(buffer, 0, shortBuffer, 0, samplesRead);
_canceller.EchoPlayback(shortBuffer);
return samplesRead;
}

public void Cancel(byte[] buffer)
{
var shortBuffer = new short[buffer.Length / 2];
Buffer.BlockCopy(buffer, 0, shortBuffer, 0, buffer.Length);
_canceller.EchoCapture(shortBuffer, out var output);

Buffer.BlockCopy(output, 0, buffer, 0, output.Length);
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/791 ... io-c-sharp
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»