Итак, я написал небольшую тестовую программу, которая использует адаптивный эхоподавитель 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
Speex Echo Canceller добавляет глючный звук C# ⇐ C#
Место общения программистов C#
-
Anonymous
1729408417
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);
}
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79106554/speex-echo-canceller-adds-glitchy-audio-c-sharp[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия