【发布时间】:2018-07-17 01:09:32
【问题描述】:
我在让 AudioTrack 类做我想做的事情时遇到了一些麻烦。我正在尝试制作一个应用程序,它首先让用户在屏幕上绘制一个单周期波形,然后通过耳机输出以任意频率输出该波形的任意数量的周期。对于主要用途,频率将低于可听范围,例如 1/60Hz - 20Hz(如果有人熟悉 Eurorack/模块化合成器,我希望将耳机输出用作 CV 源)。
我遇到的问题是,AudioTrack 似乎在此频率范围的低端输出了非常不准确的波形再现,即使它确实在高端输出了准确的再现。频率越低,波形在我的示波器上被“挤压”到左侧的次数就越多。下面的图片显示了波形上的这种现象,该波形本应从每个周期低开始并线性增加到最大值,但这种现象也发生在其他波形上。
到目前为止,我已经设置了应用程序 (1) 创建一个 ArrayList 来保存来自用户输入的数据点,(2) 将 ArrayList 转换为 float[] 以提供给 AudioTrack,以及 (3 ) 设置 AudioTrack 并在需要时将 float[] 写入其中。由于 ArrayList 和 float[] 都保持波形的准确再现,我很确定我的问题在 (3),否则它是我的手机/示波器的硬件限制。
这是 AudioTrack 的相关代码。
(重新)初始化 AudioTrack 的方法:
public void updateTrackForWave(Waveform wave, Context context) {
if (wave.getInterpolatedWaveData() == null) return;
int sampleRate = Integer.parseInt(
((AudioManager) context.getSystemService(Context.AUDIO_SERVICE))
.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
if (wave.getOutputChannel() == Waveform.OutputChannelEnum.left) {
if (mTrackL != null) mTrackL.release();
mTrackL = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_FLOAT,
Float.BYTES * wave.getInterpolatedWaveData().length,
AudioTrack.MODE_STATIC);
mTrackL.setVolume(AudioTrack.getMaxVolume());
} else if (wave.getOutputChannel() == Waveform.OutputChannelEnum.right) {
if (mTrackR != null) mTrackR.release();
mTrackR = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_FLOAT,
Float.BYTES * wave.getInterpolatedWaveData().length,
AudioTrack.MODE_STATIC);
mTrackR.setVolume(AudioTrack.getMaxVolume());
}
}
播放 AudioTrack 的方法:
private void playWaveOnTrack(Waveform wave, AudioTrack track) {
if (track == null) return;
if (track.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
return;
} else {
if (wave.isCycleMode()) track.setLoopPoints(0,
wave.getInterpolatedWaveData().length, -1);
else if (wave.isOneShotMode()) track.setLoopPoints(0,
wave.getInterpolatedWaveData().length, 0);
if (track.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) {
track.play();
} else if (track.getPlayState() == AudioTrack.PLAYSTATE_STOPPED) {
track.write(wave.getInterpolatedWaveData(), 0,
wave.getInterpolatedWaveData().length, AudioTrack.WRITE_BLOCKING);
track.play();
}
}
}
值得注意的是,wave.getInterpolatedWaveData() 从上面的 (3) 中返回 float[]。
无论如何,如果您能在这方面提供任何帮助,我们将不胜感激!不确定我是否在我的代码中犯了错误,或者我是否应该添加一些代码(可能是某种 AudioEffect?),或者我是否对我的手机要求太多,或者什么。
PS 我是新来的 Android 编程新手,所以请指出我应该遵循但不遵循的任何论坛规范,或者我可能不知道的任何替代编码方法。
图片:
【问题讨论】: