Android,实时振幅和音调检测
Android, live amplitude and pitch detection
我正在编写一个应用程序,它需要听麦克风并给我一个实时的振幅和音调输出。我已经弄清楚如何进行音高识别。我一直在对 fft 进行大量研究。找到了 Android 库 TarsosDSP,它使音高的监听变得极其简单:
AudioDispatcher dispatcher =
AudioDispatcherFactory.fromDefaultMicrophone(22050,1024,0);
PitchDetectionHandler pdh = new PitchDetectionHandler() {
@Override
public void handlePitch(PitchDetectionResult res, AudioEvent e){
final float pitchInHz = res.getPitch();
runOnUiThread(new Runnable() {
@Override
public void run() {
processPitch(pitchInHz);
}
});
}
};
AudioProcessor pitchProcessor = new PitchProcessor(PitchEstimationAlgorithm.FFT_YIN, 22050, 1024, pdh);
dispatcher.addAudioProcessor(pitchProcessor);
Thread audioThread = new Thread(dispatcher, "Audio Thread");
audioThread.start();
我还想出了如何通过使用内置 android .getMaxAmplitude() 方法进行振幅检测。
但我的问题是我这辈子都想不出如何同时做这两件事。问题是您显然可以 运行 多个麦克风实例。就像您尝试 运行 在不同的线程上进行两个单独的现场录音一样。我浏览了整个互联网,试图寻找一些示例代码来让我继续下去,但我找不到任何东西。有没有人做过类似的事情?
编辑
我发现您可以使用 Pitchdetectionhandler 中的 AudioEvent。
audioevent.getbytebuffer() returns 一个字节数组,其中包含以字节为单位的音频数据,根据文档:https://0110.be/releases/TarsosDSP/TarsosDSP-latest/TarsosDSP-latest-Documentation/ .
如果我在转换为短[]时没有弄错的话,最高值就是最高振幅对吗?
但是:
final byte[] audioBytes = e.getByteBuffer();
short[] shortArray = new short[audioBytes.length];
for (int index = 0; index < audioBytes.length; index++) {
shortArray[index] = (short) audioBytes[index];
float item = shortArray[index];
if (item > amp){
amp = item;
}
}
在这种情况下,放大器总是 returns 127。而且这种方法在现场真的行不通吗?
所以还有三个问题。我的基本想法是正确的,如果是这样,为什么它总是 return 127,我将如何在实时环境中使用它。
我自己找到了解决方案。您可以 audioEvent.getFloatBuffer() 然后 运行 通过一些 fft 方法缓冲,然后您可以从缓冲区中提取振幅值。缓冲区非常小,所以我最终从缓冲区中获得了最大振幅,而它的 运行 宁,这会让你每秒读出多次振幅,这对我来说已经足够了。
编辑
示例:
public void handlePitch(PitchDetectionResult result, final AudioEvent e) {
final float pitchInHz = result.getPitch();
final float[] amplitudes = new float[e.getBufferSize()];
new Thread(new Runnable() {
public void run() {
if (pitchInHz > pitch) {
pitch = pitchInHz;
}
float[] audioFloatBuffer = e.getFloatBuffer();
float[] transformBuffer = new float[e.getBufferSize() * 2];
FFT fft = new FFT(e.getBufferSize());
System.arraycopy(audioFloatBuffer, 0, transformBuffer, 0, audioFloatBuffer.length);
fft.forwardTransform(transformBuffer);
fft.modulus(transformBuffer, amplitudes);
for (int index = 0; index < amplitudes.length; index++) {
if (amplitudes[index] > amp) {
amp = amplitudes[index];
}
}
}
}).start();
}
我正在编写一个应用程序,它需要听麦克风并给我一个实时的振幅和音调输出。我已经弄清楚如何进行音高识别。我一直在对 fft 进行大量研究。找到了 Android 库 TarsosDSP,它使音高的监听变得极其简单:
AudioDispatcher dispatcher =
AudioDispatcherFactory.fromDefaultMicrophone(22050,1024,0);
PitchDetectionHandler pdh = new PitchDetectionHandler() {
@Override
public void handlePitch(PitchDetectionResult res, AudioEvent e){
final float pitchInHz = res.getPitch();
runOnUiThread(new Runnable() {
@Override
public void run() {
processPitch(pitchInHz);
}
});
}
};
AudioProcessor pitchProcessor = new PitchProcessor(PitchEstimationAlgorithm.FFT_YIN, 22050, 1024, pdh);
dispatcher.addAudioProcessor(pitchProcessor);
Thread audioThread = new Thread(dispatcher, "Audio Thread");
audioThread.start();
我还想出了如何通过使用内置 android .getMaxAmplitude() 方法进行振幅检测。
但我的问题是我这辈子都想不出如何同时做这两件事。问题是您显然可以 运行 多个麦克风实例。就像您尝试 运行 在不同的线程上进行两个单独的现场录音一样。我浏览了整个互联网,试图寻找一些示例代码来让我继续下去,但我找不到任何东西。有没有人做过类似的事情?
编辑 我发现您可以使用 Pitchdetectionhandler 中的 AudioEvent。 audioevent.getbytebuffer() returns 一个字节数组,其中包含以字节为单位的音频数据,根据文档:https://0110.be/releases/TarsosDSP/TarsosDSP-latest/TarsosDSP-latest-Documentation/ .
如果我在转换为短[]时没有弄错的话,最高值就是最高振幅对吗?
但是:
final byte[] audioBytes = e.getByteBuffer();
short[] shortArray = new short[audioBytes.length];
for (int index = 0; index < audioBytes.length; index++) {
shortArray[index] = (short) audioBytes[index];
float item = shortArray[index];
if (item > amp){
amp = item;
}
}
在这种情况下,放大器总是 returns 127。而且这种方法在现场真的行不通吗?
所以还有三个问题。我的基本想法是正确的,如果是这样,为什么它总是 return 127,我将如何在实时环境中使用它。
我自己找到了解决方案。您可以 audioEvent.getFloatBuffer() 然后 运行 通过一些 fft 方法缓冲,然后您可以从缓冲区中提取振幅值。缓冲区非常小,所以我最终从缓冲区中获得了最大振幅,而它的 运行 宁,这会让你每秒读出多次振幅,这对我来说已经足够了。 编辑 示例:
public void handlePitch(PitchDetectionResult result, final AudioEvent e) {
final float pitchInHz = result.getPitch();
final float[] amplitudes = new float[e.getBufferSize()];
new Thread(new Runnable() {
public void run() {
if (pitchInHz > pitch) {
pitch = pitchInHz;
}
float[] audioFloatBuffer = e.getFloatBuffer();
float[] transformBuffer = new float[e.getBufferSize() * 2];
FFT fft = new FFT(e.getBufferSize());
System.arraycopy(audioFloatBuffer, 0, transformBuffer, 0, audioFloatBuffer.length);
fft.forwardTransform(transformBuffer);
fft.modulus(transformBuffer, amplitudes);
for (int index = 0; index < amplitudes.length; index++) {
if (amplitudes[index] > amp) {
amp = amplitudes[index];
}
}
}
}).start();
}