Recently, I want to take a good look at Echo elimination. I didn't know how to fix it. Now I am collecting data. I am dedicated to audio signal processing.
Repost a post written by a netizenArticleIn the future, we will analyze the problems he encountered.
Http://blog.csdn.net/aladdin_1983/archive/2007/06/26/1667316.aspx
An open-source acoustic echo Eliminator
Some time ago, an acoustic echo was eliminated, and it was very depressing because it was not successful. But I can say I learned something, at least theoretically.
Why does it need acoustic echo cancellation? In a general VoIP Software or video conferencing system, suppose we only have two people a and B talking. First, the voice of a is transmitted to B, and B is then speakers, at this time, the MIC of B will capture the sound from the Horn and then return it to a. If the delay during the transmission is large enough, A will hear the same sound as he said just now. This is Echo. the acoustic echo eliminator is used to process the sound collected by B on the B side, remove the sound of a collected to the sound and pass it to A. In this way, a will not hear what he said.
I will not talk about the principle of acoustic echo elimination. There are many documents on the Internet, but what is missing on the internet is implementation. So here I will introduce an open-source acoustic echo eliminator, I hope some of them will be used. If someone knows how to use the real-time stream-based VoIP Software for this eliminator, I hope to share it with you.
This acoustic echo eliminator is part of a well-known audio codecs speex. The echo eliminator After version 1.1.9 does not work. It is also used in previous versions. tests show that, with the same simulated file, it works better than intel
The acoustic echo eliminator in IPP library version 4.1 is even better.
First, compile. First, download Source code Decompress the package and open libspeex. DSW in speex \ Win32 \ libspeex. There are two projects in this workspace: libspeex and libspeex_dynamic. Then, add the MDF. c file in libspeex to the libspeex project and compile it.
The following is a class encapsulated according to the document. There is a test in it. Program :
// File name: speexec. h
# Ifndef speex_ec_h
# Define speex_ec_h
# Include <stdio. h>
# Include <stdlib. h>
# Include "speex/speex_echo.h"
# Include "speex/speex_preprocess.h"
Class cspeexec
{
Public:
Cspeexec ();
~ Cspeexec ();
Void Init (INT frame_size = 160, int filter_length = 1280, int sampling_rate = 8000 );
Void doaec (short * mic, short * ref, short * out );
Protected:
Void reset ();
PRIVATE:
Bool m_bhasinit;
Speexechostate * m_pstate;
Speexpreprocessstate * m_ppreprocessorstate;
Int m_nframesize;
Int m_nfilterlen;
Int m_nsamplerate;
Float * m_pfnoise;
};
# Endif
// Fine name: speexec. cpp
# Include "speexec. H"
Cspeexec: cspeexec ()
{
M_bhasinit = false;
M_pstate = NULL;
M_ppreprocessorstate = NULL;
M_nframesize = 160;
M_nfilterlen = 160*8;
M_nsamplerate = 8000;
M_pfnoise = NULL;
}
Cspeexec ::~ Cspeexec ()
{
Reset ();
}
Void cspeexec: Init (INT frame_size, int filter_length, int sampling_rate)
{
Reset ();
If (frame_size <= 0 | filter_length <= 0 | sampling_rate <= 0)
{
M_nframesize = 160;
M_nfilterlen = 160*8;
M_nsamplerate = 8000;
}
Else
{
M_nframesize = frame_size;
M_nfilterlen = filter_length;
M_nsamplerate = sampling_rate;
}
M_pstate = speex_echo_state_init (m_nframesize, m_nfilterlen );
M_ppreprocessorstate = speex_preprocess_state_init (m_nframesize,
M_nsamplerate );
M_pfnoise = new float [m_nframesize + 1];
M_bhasinit = true;
}
Void cspeexec: reset ()
{
If (m_pstate! = NULL)
{
Speex_echo_state_destroy (m_pstate );
M_pstate = NULL;
}
If (m_ppreprocessorstate! = NULL)
{
Speex_preprocess_state_destroy (m_ppreprocessorstate );
M_ppreprocessorstate = NULL;
}
If (m_pfnoise! = NULL)
{
Delete [] m_pfnoise;
M_pfnoise = NULL;
}
M_bhasinit = false;
}
Void cspeexec: doaec (short * mic, short * ref, short * out)
{
If (! M_bhasinit)
Return;
Speex_echo_cancel (m_pstate, mic, ref, out, m_pfnoise );
Speex_preprocess (m_ppreprocessorstate, (_ int16 *) Out, m_pfnoise );
}
it can be seen that this echo eliminator class is very simple and can be called after initialization. However, it should be noted that the two sound signals sent to the echo eliminator must be well synchronized, that is, after receiving what a said on the B side, to transmit the voice data to the echo Eliminator for reference, and then to the sound card, and then to the sound card. This delay occurs. Then, B collects the data and sends it to the echo eliminator, compared with the reference data, the same part of the frequency domain and reference data is eliminated from the collected data. If the two signals sent to the Eliminator are not well synchronized, that is, the two signals cannot find the same part in the frequency domain, there is no way to eliminate it.
test procedure:
# define NN 160
void main ()
{< br> file * ref_fd, * mic_fd, * out_fd;
short Ref [NN], MIC [NN], out [NN];
ref_fd = fopen ("Ref. PCM "," rb "); // open the reference file, that is, the sound to be eliminated
mic_fd = fopen (" mic. PCM "," rb "); // open the audio file collected by MIC, which contains the echo.
out_fd = fopen (" Echo. PCM "," WB "); // The file after Echo is eliminated
Cspeexec EC;
EC. INIT ();
While (fread (MIC, 1, NN * 2, mic_fd ))
{
Fread (ref, 1, NN * 2, ref_fd );
EC. doaec (MIC, ref, out );
Fwrite (Out, 1, NN * 2, out_fd );
}
Fclose (ref_fd );
Fclose (mic_fd );
Fclose (out_fd );
}
The above programs use files to simulate echo and MIC, but the real-time stream is very different. In general VOIP software, it is done in one thread to receive the sound from the other party and transmit it to the sound card, while collecting the local sound and transmitting it to the other party is done in another thread, while the acoustic echo eliminator eliminates the echo of the collected sound, it also needs the data in the playing thread as a reference. It is very difficult to synchronize the data in the two threads, because of some non-synchronization, the adaptive filter in the acoustic echo eliminator will be divergent, which not only does not eliminate the echo, but also destroys the originally collected sound, making the destroyed sound difficult to distinguish. I have tried a lot and I have never been able to use software to synchronize the data in these two threads, leading to implementation failure. I hope experienced netizens can share their experiences in this area.
This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/aladdin_1983/archive/2007/06/26/1667316.aspx