android audiorecord 频谱图,代码实现
时间: 2023-06-27 14:03:54 浏览: 309
Android代码-音乐频谱波形图生成
5星 · 资源好评率100%
实现 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 算法的基本原理,再来理解这段代码。
阅读全文