作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想播放一个短于 1 秒的生成声音。但是,AudioTrack
的 minBufferSize 似乎总是 1 秒或更长。在某些设备上,我可以将 bufferSize 设置为小于使用 AudioTrack.getMinBufferSize
评估的值,但这并非在所有设备上都可行。我想知道是否可以为 AudioTrack 生成更短的声音。我目前正在使用这段代码(它包含一些平滑,因为我不断获得新的频率):
int buffSize = AudioTrack.getMinBufferSize(sampleRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, buffSize,
AudioTrack.MODE_STREAM);
short samples[] = new short[buffSize];
int amp = 10000;
double twopi = 8. * Math.atan(1.);
double phase = 0.0;
audioTrack.play();
double currentFrequency = getFrequency();
double smoothing = 300;
double deltaTime = buffSize / 500;
while (playing && PreferenceManager.getDefaultSharedPreferences(
MainActivity.this).getBoolean("effect_switch", true))
{
double newFrequency = getFrequency();
for (int i = 0; i < buffSize; i++)
{
currentFrequency += deltaTime * (newFrequency - currentFrequency) / smoothing;
samples[i] = (short) (amp * Math.sin(phase));
phase += twopi * currentFrequency / sampleRate;
}
audioTrack.write(samples, 0, buffSize);
}
audioTrack.stop();
audioTrack.release();
事实上,我希望声音更频繁地更新,这就是我需要较短样本的原因。
最佳答案
我想我有一个解决方案。由于我的最小缓冲区似乎比 1 秒小得多,我通过加载一个包含 5 秒数据的缓冲区来模拟你的问题,但只播放其中的 0.5 秒,然后立即播放另一个频率。这个音调我还创建了 5 秒的数据但只播放了 0.5 秒并重复了几个音调。这一切都适合我。
另外,由于我将它塞进了我正在处理的当前项目中,所以我很难仅仅剪切和粘贴我的代码。虽然我已经测试了我的解决方案,但我在此处发布的内容并未完全按照所写内容进行测试。其中一些是剪切和粘贴,一些是伪代码。
关键功能是使用 OnPlaybackPositionUpdateListener。
private AudioTrack.OnPlaybackPositionUpdateListener audioTrackListener = new AudioTrack.OnPlaybackPositionUpdateListener() {
@Override
public void onMarkerReached(AudioTrack audioTrack) {
int marker = audioTrack.getNotificationMarkerPosition();
// I just used 8 tones of 0.5 sec each to determine when to stop but you could make
// the condition based on a button click or whatever is best for you
if(marker < MAX_FRAME_POSITION) {
audioTrack.pause();
newSamples();
audioTrack.play();
} else {
audioTrack.stop();
}
audioTrack.setNotificationMarkerPosition(marker + FRAME_MARKER);
Log.d(TAG, "MarkerReached");
}
@Override
public void onPeriodicNotification(AudioTrack audioTrack) {
int position = audioTrack.getPlaybackHeadPosition();
if(position < MAX_FRAME_POSITION) {
audioTrack.pause();
newSamples();
audioTrack.play();
} else {
audioTrack.stop();
}
Log.d(TAG, "PeriodNotification");
}
};
然后
audioTrack.setPlaybackPositionUpdateListener(AudioTrackListener);
我在测试中使用了标记(必须反复重新初始化)...
audioTrack.setNotificationMarkerPosition(MARKER_FRAMES);
但您也应该能够使用定期通知。
audioTrack.setPositionNotificationPeriod(PERIODIC_FRAMES);
以及从监听器调用的 newSamples()
方法
public void newSamples() {
/*
* generate buffer, I'm doing similar to you, without the smoothing
*/
// AudioTrack write is a blocking operation so I've moved it off to it's own Thread.
// Could also be done with an AsyncTask.
Thread thread = new Thread(writeSamples);
thread.start();
}
private Runnable writeSamples = new Runnable() {
@Override
public void run() {
audioTrack.write(samples, 0, buffSize);
}
};
关于android - 播放短促的声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44354985/
我是一名优秀的程序员,十分优秀!