Акустическое эхоподавление в Java - PullRequest
8 голосов
/ 04 августа 2010

Я реализую приложение VOIP, которое использует чистую Java. Существует проблема эха, которая возникает, когда пользователи не используют гарнитуры (в основном на ноутбуках со встроенными микрофонами).

Что сейчас происходит

Основные черты приложения VOIP - это простые данные медиа-инфраструктуры Java. По сути, я хотел бы выполнить некоторую цифровую обработку сигнала для аудиоданных, прежде чем записать их в динамик для вывода.

  public synchronized void addAudioData(byte[] ayAudioData)
  {
    m_oBuffer.enqueue(ayAudioData);
    this.notify();
  }

Как видите, аудиоданные поступают и помещаются в буфер. Это должно обслуживать хитрые соединения и учитывать разные размеры пакетов. Это также означает, что у меня есть доступ к столько аудиоданных, сколько мне нужно для любых необычных операций DSP, прежде чем я воспроизведу аудиоданные на линию динамика.

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

Ручной эхоподавитель

public static byte[] removeEcho(int iDelaySamples, float fDecay, byte[] aySamples)
  {
    m_awDelayBuffer = new short[iDelaySamples];
    m_aySamples = new byte[aySamples.length];
    m_fDecay = (float) fDecay;
    System.out.println("Removing echo");
    m_iDelayIndex = 0;

    System.out.println("Sample length:\t" + aySamples.length);
    for (int i = 0; i < aySamples.length; i += 2)
    {
      // update the sample
      short wOldSample = getSample(aySamples, i);

      // remove the echo
      short wNewSample = (short) (wOldSample - fDecay * m_awDelayBuffer[m_iDelayIndex]);
      setSample(m_aySamples, i, wNewSample);

      // update the delay buffer
      m_awDelayBuffer[m_iDelayIndex] = wNewSample;
      m_iDelayIndex++;

      if (m_iDelayIndex == m_awDelayBuffer.length)
      {
        m_iDelayIndex = 0;
      }
    }

    return m_aySamples;
  }

Адаптивные фильтры

Я читал, что адаптивные фильтры - это путь. В частности, фильтр наименьших средних квадратов. Тем не менее, я застрял. Большинство примеров кода для вышеперечисленного написаны на C и C ++, и они плохо переводятся на Java.

У кого-нибудь есть советы, как реализовать их на Java? Любые другие идеи также будут высоко оценены. Заранее спасибо.

Ответы [ 4 ]

4 голосов
/ 13 апреля 2011

Уже давно! Надеюсь, что это даже правильный класс, но вы идете:

/**
 * This filter performs a pre-whitening Normalised Least Means Square on an
 * array of bytes. This does the actual echo cancelling.
 * 
 * Echo cancellation occurs with the following formula:
 * 
 * e = d - X' * W
 * 
 * e represents the echo-free signal. d represents the actual microphone signal
 * with the echo. X' is the transpose of the loudspeaker signal. W is an array
 * of adaptive weights.
 * 
 */
public class cNormalisedLeastMeansSquareFilter
  implements IFilter
{
  private byte[] m_ayEchoFreeSignal;// e
  private byte[] m_ayEchoSignal;// d
  private byte[] m_ayTransposeOfSpeakerSignal;// X'
  private double[] m_adWeights;// W

  /**
   * The transpose and the weights need to be updated before applying the filter
   * to an echo signal again.
   * 
   * @param ayEchoSignal
   * @param ayTransposeOfSpeakerSignal
   * @param adWeights
   */
  public cNormalisedLeastMeansSquareFilter(byte[] ayEchoSignal, byte[] ayTransposeOfSpeakerSignal, double[] adWeights)
  {
    m_ayEchoSignal = ayEchoSignal;
    m_ayTransposeOfSpeakerSignal = ayTransposeOfSpeakerSignal;
    m_adWeights = adWeights;
  }

  @Override
  public byte[] applyFilter(byte[] ayAudioBytes)
  {
    // e = d - X' * W
    m_ayEchoFreeSignal = new byte[ayAudioBytes.length];
    for (int i = 0; i < m_ayEchoFreeSignal.length; ++i)
    {
      m_ayEchoFreeSignal[i] = (byte) (m_ayEchoSignal[i] - m_ayTransposeOfSpeakerSignal[i] * m_adWeights[i]);
    }
    return m_ayEchoFreeSignal;
  }
4 голосов
/ 23 сентября 2010

На случай, если кому-то будет интересно, мне удалось создать честный, работающий эхоподавитель, в основном, преобразовав метод акустического эхоподавления метод , упомянутый Полом R , который использует нормализованный квадрат наименьших средних алгоритм и несколько фильтров из C в Java. JNI-маршрут, вероятно, все еще лучше, но мне нравится придерживаться чистой Java, если это вообще возможно. Видя, как работают их фильтры, и читая много о фильтрах на DSP Tutor , мне удалось получить некоторый контроль над тем, сколько шума удаляется, как удалять высокие частоты и т. Д.

Несколько советов:

  1. Имейте в виду, что вы удалите откуда. Я должен был переключить это несколько раз.
  2. Наиболее важной переменной этого метода является скорость сходимости. Эта переменная называется Stepsize в приведенном выше коде ссылки.
  3. Я принимал отдельные компоненты по одному, выяснял, что они делают, собирал и тестировал их по отдельности. Например, я взял детектор двойного разговора и проверил его на работоспособность. Затем я взял фильтры один за другим и проверил их на аудио-файлах, чтобы убедиться, что они работают, затем я взял нормализованную часть наименьших средних и проверил ее, прежде чем собрать все вместе.

Надеюсь, это поможет кому-то еще!

4 голосов
/ 09 марта 2011

Используйте Speex AEC .Это открытый исходный код, он написан на C (используйте его с JNI), и он работает.Я успешно использовал его в 2 разных приложениях VoIP, и большинство эхо-сигналов было отменено.

1 голос
/ 04 августа 2010

Это очень сложная область, и чтобы получить работоспособное решение AEC, вам потребуется немало исследований и разработок. Все хорошие AEC являются проприетарными, и для подавления эха есть много больше, чем просто применение адаптивного фильтра, такого как LMS. Я предлагаю вам разработать свой алгоритм эхоподавления, первоначально используя MATLAB (или Octave) - когда у вас есть что-то, что, по-видимому, достаточно хорошо работает с "реальными" телекомами, вы можете реализовать алгоритм на C и протестировать / оценить его в режиме реального времени. Как только это сработает, вы можете использовать JNI для вызова реализации C из Java.

...