【问题标题】:AudioTrack - how to know when a sound begins/ends?AudioTrack - 如何知道声音何时开始/结束?
【发布时间】:2012-09-07 18:47:42
【问题描述】:

我正在使用音轨以流模式播放不同的声音。 我想知道是否有办法知道每个声音何时/结束播放。

我这样创建音轨:

AudioTrack tmpAudioTrack = new AudioTrack(
        STREAM_TYPE, 
        SAMPLE_RATE, 
        CHANNEL_CONFIG_TYPE, 
            AUDIO_FORMAT_TYPE, 
        getOptimalBufferSize(), 
        AUDIO_TRACK_MODE);'

并在后台线程中启动它:

backround_thread = new Thread(new MyRunnable(aTrack));
    backround_thread.start();   

我在 runnable 中这样写每个声音:

byte generatedSnd[] = new byte[2 * beepSamples];
<code for filling the buffer with sound here>
int bytesWritten = track.write(generatedSnd, 0, generatedSnd.length);

是否可以使用任何 AudioTrack API(例如 setNotificationMarkerPosition、setLoopPoints 或 setPositionNotificationPeriod)来完成此操作?它们是如何工作的?

每种声音可以有不同的持续时间。我认为这是关键。

我并不完全理解这些 API 的文档。每一帧都与样本相同吗?如何为每个声音的开始/结束位置指定标记?

谢谢,

【问题讨论】:

  • 至少有人知道 setNotificationMarkerPosition 和 setPositionNotificationPeriod 的区别吗?

标签: android marker audiotrack


【解决方案1】:

这是我发现的:

对我来说,帧就是样本——声音的持续时间乘以采样率。

要使用 AudioTrack.setPositionNotificationPeriod,您需要传递一定数量的样本。这意味着如果您传递 200 个样本,回调将每 200 个样本调用一次,循环。

tmpAudioTrack.setPositionNotificationPeriod(duration * sampleRate);

要使用 .setNotificationMarkerPosition,您还需要传递一定数量的样本。但是,这是绝对的,不像 period API 那样是相对的。因此,如果您想确定声音何时结束,请传递样本量(总音轨持续时间 * sampleRate)。

tmpAudioTrack.setNotificationMarkerPosition(duration * sampleRate);

但是,如果你已经在播放,在你的音轨中间,并且想要添加一个标记以便你会在 3 秒后被回调,那么你需要添加音频的当前播放头跟踪,像这样:(你的持续时间是 3 秒)

tmpAudioTrack.setNotificationMarkerPosition(tmpAudioTrack.getPlaybackHeadPosition() + (duration * sampleRate));

这就是您注册期间和标记通知的方式:

tmpAudioTrack.setPlaybackPositionUpdateListener(new OnPlaybackPositionUpdateListener(){

    @Override
    public void onMarkerReached(AudioTrack arg0) {

    }

    @Override
    public void onPeriodicNotification(AudioTrack arg0) {

    }

});

【讨论】:

  • 我相信您可以使用以下公式将写入的位转换为帧:bits / bit depth for your AudioFormat,注意字节为 8 位,短 16 位,浮点 24 位。
  • 根据我的经验,在 API 29 上使用本地模拟器,您必须设置如下标记才能获得通知: int lastFrame = (int) (fileSize / frameSizeInBytes); int endMarker = lastFrame - audioTrack.getBufferSizeInFrames() -1; int res2 = audioTrack.setNotificationMarkerPosition(endMarker);
  • @mikemeli 那么在 AudioTrack 的上下文中,术语“帧”和“样本”是完全相同的,可以互换使用吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-15
  • 2018-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
相关资源
最近更新 更多