【问题标题】:Android DSP - Trouble with AudioTrack and Sub-Audible SignalsAndroid DSP - AudioTrack 和亚音频信号的问题
【发布时间】: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 编程新手,所以请指出我应该遵循但不遵循的任何论坛规范,或者我可能不知道的任何替代编码方法。

图片:

Waveform at 100Hz

Waveform at 10Hz

Waveform at 2Hz

【问题讨论】:

    标签: android signal-processing


    【解决方案1】:

    这是您手机的硬件限制。为了避免恒定的直流电流流过每个耳机扬声器,它们是capacitively coupled——每个声道都与一个或多个电容器串联。这使您的输出波形为time constant;波形的平均电压电平总是趋于0(GND),无法输出直流,甚至是低频信号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      • 1970-01-01
      • 1970-01-01
      • 2014-11-15
      • 2020-12-20
      相关资源
      最近更新 更多