Audio 关键字以及示意图

Acoustic Echo Cancellation(AEC)

AEC is an essential part of providing speech enhancement (or voice quality enhancement) to any telephone communication. An acoustic echo canceller (AEC) operates on the digitally sampled audio signals of the communication device. The transfer function of the acoustic environment from the loudspeaker to the microphone on the device is estimated to cancel the received echoes from the microphone signal
在这里插入图片描述

SNR:(Signal-to-noise Ratio)

信噪比(訊噪比),是科学和工程中所用的一种度量,用于比较所需信号的强度与背景噪声的强度。其定义为信号功率与噪声功率的比率,以分贝(dB)为单位表示。大于比率1:1(高于0分贝)表示信号多于噪声

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现 Android 音频频谱图需要用到 Android 的 `AudioRecord` 类和 `FFT`(快速傅里叶变换)算法。下面是一个简单的示例代码: ```java import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.util.Arrays; public class MainActivity extends AppCompatActivity { private static final String TAG = "AudioRecord"; private static final int SAMPLE_RATE = 44100; // 采样率 private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO; // 声道 private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; // 采样精度 private static final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT); // 缓冲区大小 private static final int MSG_UPDATE_VIEW = 1; // 更新 UI 的消息 private AudioRecord mAudioRecord; private boolean mIsRecording; private Handler mHandler; private FFT mFft; private TextView mTextView; private Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = findViewById(R.id.text_view); mButton = findViewById(R.id.button); mFft = new FFT(BUFFER_SIZE); mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_UPDATE_VIEW: updateView((double[]) msg.obj); break; } } }; } public void onClick(View view) { if (mIsRecording) { stopRecording(); } else { startRecording(); } } private void startRecording() { mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, BUFFER_SIZE); mAudioRecord.startRecording(); mIsRecording = true; mButton.setText(R.string.stop_recording); new Thread(new Runnable() { @Override public void run() { short[] buffer = new short[BUFFER_SIZE]; double[] fftBuffer = new double[BUFFER_SIZE]; while (mIsRecording) { int readSize = mAudioRecord.read(buffer, 0, BUFFER_SIZE); for (int i = 0; i < readSize; i++) { fftBuffer[i] = buffer[i] / 32768.0; } mFft.fft(fftBuffer); double[] spectrum = new double[BUFFER_SIZE / 2]; for (int i = 0; i < spectrum.length; i++) { double re = fftBuffer[i * 2]; double im = fftBuffer[i * 2 + 1]; spectrum[i] = Math.sqrt(re * re + im * im); } Message msg = mHandler.obtainMessage(MSG_UPDATE_VIEW, spectrum); mHandler.sendMessage(msg); } } }).start(); } private void stopRecording() { mIsRecording = false; mButton.setText(R.string.start_recording); mAudioRecord.stop(); mAudioRecord.release(); mAudioRecord = null; } private void updateView(double[] spectrum) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < spectrum.length; i++) { sb.append(String.format("%d Hz: %.2f\n", i * SAMPLE_RATE / BUFFER_SIZE, spectrum[i])); } mTextView.setText(sb.toString()); } private static class FFT { private int n; private double[] cosTable; private double[] sinTable; FFT(int n) { this.n = n; this.cosTable = new double[n / 2]; this.sinTable = new double[n / 2]; for (int i = 0; i < n / 2; i++) { cosTable[i] = Math.cos(-2 * Math.PI * i / n); sinTable[i] = Math.sin(-2 * Math.PI * i / n); } } void fft(double[] data) { int bits = (int) (Math.log(n) / Math.log(2)); for (int j = 1; j < n / 2; j++) { int swapPos = reverseBits(j, bits); double temp = data[j]; data[j] = data[swapPos]; data[swapPos] = temp; } int size = 2; int halfSize = 1; for (int i = 1; i <= bits; i++) { for (int j = 0; j < n; j += size) { for (int k = 0; k < halfSize; k++) { int evenIndex = j + k; int oddIndex = j + k + halfSize; double even = data[evenIndex]; double odd = data[oddIndex]; double cos = cosTable[k * n / size]; double sin = sinTable[k * n / size]; data[evenIndex] = even + odd * cos - sin * odd; data[oddIndex] = even + odd * cos + sin * odd; } } size *= 2; halfSize *= 2; } } private int reverseBits(int x, int bits) { int y = 0; for (int i = 0; i < bits; i++) { y <<= 1; y |= (x & 1); x >>= 1; } return y; } } } ``` 上面的代码实现了一个简单的录音和频谱图显示功能。当用户点击“开始录音”按钮时,程序会创建一个 `AudioRecord` 对象并开始录音。录音过程中,程序会不断从缓冲区读取音频数据,并计算出其频谱。频谱计算使用了 FFT 算法,该算法可以将时域信号转换为频域信号。最后,程序将计算出的频谱显示在界面上。 需要注意的是,程序中使用了一个自己实现的 FFT 类。如果你对 FFT 算法不熟悉,可以先了解一下 FFT 算法的基本原理,再来理解这段代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值