我正在尝试构建一个合成并播放音符的Android应用程序。我正在使用AudioTrack。由于生成音频信息的延迟,我的程序似乎无法足够快地填充轨道缓冲区。我正在从音符的傅里叶系数生成音频信息。因此,在每次写入之前,程序必须创建并采样2048个正弦波,每个正弦波的样本大小为2400,采样率为44100!
因此,我听到间歇性的哔哔声而不是连续的声音。 Logcat在蜂鸣声之间发出以下警告:
W/AudioTrack﹕ obtainBuffer() track 0x177ff80 disabled, restarting
我的代码如下。任何人都可以找出我可以优化代码的方法吗?
package com.alantaar.alantaar;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import java.util.Arrays;
public class AudioGenerator {
private AudioTrack audio;
private double[] coefficients;
private int bufferSize;
private int sampleRate;
private double[] phases;
private double frequency;
public AudioGenerator(double[] coefficients, double frequency, int sampleRate, int bufferSize){
int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
this.bufferSize = bufferSize > minBufferSize ? bufferSize : minBufferSize;
audio = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, this.bufferSize, AudioTrack.MODE_STREAM);
this.coefficients = coefficients;
this.sampleRate = sampleRate;
this.frequency = frequency;
this.phases = new double[coefficients.length];
Arrays.fill(this.phases, 0.0);
Log.i("length", Integer.toString(coefficients.length));
audio.play();
}
public void playNote(){
while(true){
short[] waveSample = sampleWave();
audio.write(waveSample, 0, waveSample.length);
}
}
private short[] sampleWave(){
short [] waveSample = new short[bufferSize];
Arrays.fill(waveSample, (short)0);
for(int i = 0; i < coefficients.length; i++){
double coefficient = coefficients[i];
short[] sineSamples = sampleSineWave(coefficient, i);
for(int j = 0; j < waveSample.length; j++){
waveSample[j] += sineSamples[j];
}
}
return waveSample;
}
private short [] sampleSineWave(double coefficient, int index){
double freq = frequency * index;
short [] samples = new short[bufferSize];
for(int i = 0; i < bufferSize; i++){
samples[i] = (short) (coefficient * Short.MAX_VALUE * Math.cos(phases[index]));
phases[index] += 2 * Math.PI * freq/sampleRate;
}
return samples;
}
public void pauseNote(){
audio.stop();
}
public void stopNote(){
audio.release();
}
}
答案 0 :(得分:1)
以下是一些突然出现的事情:
2*pi*freq/sampleRate
可以在for
之前完成。与coefficient * Short.MAX_VALUE
相同。audio.write
阻止时间来生成更多样本。我不知道AudioTrack
的流媒体模式的行为,但您的计划很可能会将大部分时间用于阻止通话。