【问题标题】:Play short generated sound播放短生成的声音
【发布时间】:2017-06-14 03:50:04
【问题描述】:

我想播放短于 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();

事实上,我希望更频繁地更新声音,这就是我需要更短样本的原因。

【问题讨论】:

  • 与其专注于较短的声音片段,您就不能同时运行多个音轨吗?
  • 我一直在玩这个,我得到了大约 80 毫秒的 minBufferSize(我相信)。 1280 字节用于 8kHz 采样(常见的电信音频采样率)和 7056 字节用于 44.1kHz 采样(最大值)。我只试过一种设备。您是否获得了多个设备的最大最小值?我使用相同的参数来获取minBufferSizeCHANNEL_OUT_MONOENCODING_PCM_16BIT
  • @Gary99 我在两台设备上测试过
  • @RemyKabel 我觉得这听起来很糟糕,但我会试试看。
  • 一个捷径可能是用零填充缓冲区中的剩余索引。

标签: android audio


【解决方案1】:

我想我有一个适合你的解决方案。由于我的最小缓冲区似乎远小于 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);
    }
};

【讨论】:

  • 我稍后试试。
猜你喜欢
  • 1970-01-01
  • 2014-02-06
  • 2012-05-06
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-04
相关资源
最近更新 更多