gpt4 book ai didi

Android AudioTrack 缓冲问题

转载 作者:可可西里 更新时间:2023-11-01 18:46:09 27 4
gpt4 key购买 nike

好的,我有一个频率发生器,它使用 AudioTrack 将 PCM 数据发送到硬件。这是我为此使用的代码:

private class playSoundTask extends AsyncTask<Void, Void, Void> {
float frequency;
float increment;
float angle = 0;
short samples[] = new short[1024];

@Override
protected void onPreExecute() {
int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );
track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minSize, AudioTrack.MODE_STREAM);
track.play();
}

@Override
protected Void doInBackground(Void... params) {
while( Main.this.isPlaying)
{
for( int i = 0; i < samples.length; i++ )
{
frequency = (float)Main.this.slider.getProgress();
increment = (float)(2*Math.PI) * frequency / 44100;
samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
angle += increment;
}

track.write(samples, 0, samples.length);
}
return null;
}
}

频率与滑动条相关联,样本生成循环中报告了正确的值。当我启动应用程序时,一切都很好。当您沿着滑动条拖动手指时,您会听到美妙的扫过声音。但在玩了大约 10 秒后,音频开始变得不稳定。它不是平滑的扫描,而是交错的,并且仅每 1000 Hz 左右改变音调。关于可能导致此问题的任何想法?

如果问题出在其他地方,这里是所有代码:

    public class Main extends Activity implements OnClickListener, OnSeekBarChangeListener {
AudioTrack track;
SeekBar slider;
ImageButton playButton;
TextView display;

boolean isPlaying=false;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

display = (TextView) findViewById(R.id.display);
display.setText("5000 Hz");

slider = (SeekBar) findViewById(R.id.slider);
slider.setMax(20000);
slider.setProgress(5000);
slider.setOnSeekBarChangeListener(this);


playButton = (ImageButton) findViewById(R.id.play);
playButton.setOnClickListener(this);

}

private class playSoundTask extends AsyncTask<Void, Void, Void> {
float frequency;
float increment;
float angle = 0;
short samples[] = new short[1024];

@Override
protected void onPreExecute() {
int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );
track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minSize, AudioTrack.MODE_STREAM);
track.play();
}

@Override
protected Void doInBackground(Void... params) {
while( Main.this.isPlaying)
{
for( int i = 0; i < samples.length; i++ )
{
frequency = (float)Main.this.slider.getProgress();
increment = (float)(2*Math.PI) * frequency / 44100;
samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
angle += increment;
}

track.write(samples, 0, samples.length);
}
return null;
}
}



@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
display.setText(""+progress+" Hz");
}

public void onClick(View v) {
if (isPlaying) {
stop();
} else {
start();
}
}

public void stop() {
isPlaying=false;
playButton.setImageResource(R.drawable.play);
}

public void start() {
isPlaying=true;
playButton.setImageResource(R.drawable.stop);
new playSoundTask().execute();
}

@Override
protected void onResume() {
super.onResume();

}

@Override
protected void onStop() {
super.onStop();
//Store state
stop();

}


@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub

}


@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub

}
}

最佳答案

我找到原因了!

问题是 AudioTrack 缓冲区的大小。如果您不能足够快地生成样本,样本就会用完,播放会暂停,并在再次有足够的样本时继续。

唯一的解决方案是确保您可以足够快地生成样本 (44100/s)。作为快速修复,尝试将采样率降低到 22000(或增加缓冲区的大小)。

至少这对我来说是这样的——当我优化我的样本生成例程时,跳跃就消失了。

(增加缓冲区的大小会使声音稍后开始播放,因为等待一些保留 - 直到缓冲区填满。但是,如果您生成样本的速度不够快,样本最终会用完) .


哦,你应该把不变变量放在循环之外!并且可能使样本数组更大,以便循环运行更长的时间。

short samples[] = new short[4*1024];
...

frequency = (float)Main.this.slider.getProgress();
increment = (float)(2 * Math.PI) * frequency / 44100;
for(int i = 0; i < samples.length; i++)
{
samples[i] = (short)((float)Math.sin(angle) * Short.MAX_VALUE);
angle += increment;
}

您还可以预先计算频率为 200Hz-8000Hz 的所有正弦值,步长为 10Hz。或者按需执行此操作:当用户选择频率时,使用您的方法生成样本一段时间,并将它们保存到数组中。当您生成足够多的样本以获得一个完整的正弦波时,您可以继续在数组上循环(因为 sin 是一个周期函数)。实际上,声音中可能存在一些小的不一致,因为您从未准确地击中一个周期(因为您将角度增加 1,并且一个完整正弦波的长度是 sampleRate/(double)frequency 样本) .但取周期的正确倍数会使不一致变得不明显。

另请参阅 http://developer.android.com/guide/practices/design/performance.html

关于Android AudioTrack 缓冲问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3305598/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com