Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的回声消除_Java_Echo_Signal Processing_Javasound_Cancellation - Fatal编程技术网

Java中的回声消除

Java中的回声消除,java,echo,signal-processing,javasound,cancellation,Java,Echo,Signal Processing,Javasound,Cancellation,我正在实现一个使用纯Java的VOIP应用程序。当用户不使用耳机(主要是内置麦克风的笔记本电脑)时,会出现回声问题 当前发生的情况 VOIP应用程序的基本要素只是Java媒体框架的简单数据线。基本上,我希望在将音频数据写入扬声器输出之前,对其执行一些数字信号处理 public synchronized void addAudioData(byte[] ayAudioData) { m_oBuffer.enqueue(ayAudioData); this.notify();

我正在实现一个使用纯Java的VOIP应用程序。当用户不使用耳机(主要是内置麦克风的笔记本电脑)时,会出现回声问题

当前发生的情况

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;
  }
public static byte[]removeEcho(int-iDelaySamples,float-fDecay,byte[]aySamples)
{
m_awDelayBuffer=新短[iDelaySamples];
m_aySamples=新字节[aySamples.length];
m_fDecay=(浮动)fDecay;
System.out.println(“删除回音”);
m_iDelayIndex=0;
System.out.println(“样本长度:\t”+aySamples.length);
对于(int i=0;i
自适应滤波器

我已经读过了,这是一条路要走。具体来说,是一个最小均方滤波器。然而,我被卡住了。上面的大多数代码都是C和C++,它们不能很好的翻译成java。
有人对如何在Java中实现它们有什么建议吗?任何其他想法也将不胜感激。提前谢谢

这是一个非常复杂的领域,要使可用的AEC解决方案发挥作用,您需要做大量的研发工作。所有好的AEC都是专有的,回声消除远不止实现LMS之类的自适应滤波器。我建议您首先使用MATLAB(或Octave)开发回声消除算法-当您有一些似乎与“现实世界”电信公司合作得相当好的东西时,您可以用C语言实现该算法并实时测试/评估它。一旦这项工作开始,您就可以使用JNI从Java调用C实现。

如果有人感兴趣,我通过将使用标准化最小均方算法和一些过滤器的方法从C转换为Java,构建了一个公平、有效的回声消除器。JNI路线可能仍然是一条更好的道路,但如果可能的话,我喜欢坚持使用纯Java。通过观察他们的滤波器是如何工作的,并阅读大量关于滤波器的内容,我设法控制了去除多少噪声以及如何去除高频等

一些提示:

  • 记住你从哪里移除了什么。我不得不换了几次
  • 该方法最重要的变量是收敛速度。这是在上面链接的代码中称为步长的变量
  • 我一次取一个单独的组件,找出它们做了什么,构建它们并分别进行测试。例如,我使用双话检测器进行测试,以确保它工作正常。然后我把过滤器一个接一个地拿出来,在音频文件上测试它们,以确保它们能正常工作,然后我把标准化的最小均方误差部分拿出来测试,然后把它们放在一起
  • 希望这对其他人有帮助

    使用。它是开源的,是用C编写的(与JNI一起使用),并且可以正常工作。
    我已经在两个不同的VoIP应用程序中成功地使用了它,它取消了大部分回音。

    已经很久了!希望这门课是对的,但你会发现:

    /**
     * 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;
      }
    
    /**
    *此过滤器在图像上执行预白化归一化最小均方
    *字节数组。这将进行实际的回声消除。
    * 
    *回声消除使用以下公式进行:
    * 
    *e=d-X'*W
    * 
    *e表示无回声信号。d表示实际的麦克风信号
    *随着回声。X'是扬声器信号的转置。W是一个数组
    *自适应权重的设计。
    * 
    */
    公共类cNormalisedLeastMeansSquareFilter
    执行IFilter
    {
    私有字节[]m_ayEchoFreeSignal;//e
    专用字节[]m_ayEchoSignal;//d
    专用字节[]m_ayTransposeOfSpeakerSignal;//X'
    私有双[]m_adWeights;//W
    /**
    *在应用过滤器之前,需要更新转置和权重
    *再次发出回声信号。
    * 
    *@param-ayecho信号
    *@param ayTransposeOfSpeakerSignal
    *@param adWeights
    */
    public cNormalisedLeastMeansSquareFilter(字节[]ayEchoSignal,字节[]AYTransposeOfSpeakersSignal,双[]adWeights)
    {
    m_ayEchoSignal=ayEchoSignal;
    m_ayTransposeOfSpeakerSignal=ayTransposeOfSpeakerSignal;
    m_adWeights=adWeights;
    }
    @凌驾
    公共字节[]applyFilter(字节[]ayAudioBytes)
    {
    //e=d-X'*W
    m_ayEchoFreeSignal=新字节[ayAudioBytes.length];
    对于(int i=0;i
    谢谢你的回复。我一直在努力避免使用JNI,但却迫不及待地想尝试任何东西。你可能会发现你需要在AEC中做平台特定的事情,例如低级操作系统/音频API调用,所以最好是C+JNI。我发现