2

我正在尝试使用 mp3 文件播放无间隙循环。我已经阅读了一些教程并了解到有类似编码器/装饰延迟之类的东西,并且可以使用一些工具用适当的音乐数据来填补这个空白。它甚至可以正常工作,但是当我尝试在 Flash 中播放该音乐时(实际上是 haxe nme,但我认为这没有任何区别),我发现还有另一个延迟,我猜这是由 flash 造成的.media.Sound(好吧,实际上在互联网的代码中找到了一些这样的评论)。

太好了,因为我有时需要更快或更慢地播放声音,这就是我的播放器的工作方式:

  • 提取的字节存储在 bytes var
  • speed 是一个浮点变量,默认 = 1
  • 有位置变量以字节表示实际位置(字节由许多声音对象共享,所以我不能轻易使用 bytes.position)
  • 当我播放声音时,在 SampleDataEvent 处理程序中,我设置 bytes.position = position * 8,然后读取并播放两个浮点数并更新 position += speed

如果我已经做错了什么 - 请指出。

为了摆脱这种延迟,我尝试:

  • 添加延迟变量
  • 硬编码从 audacity 读取的声音长度(看起来 flash.media.Sound object.length 不准确,我不确定,但我猜是因为 mp3 解码器/编码器延迟)
  • 假设每个声音是 128kbps, 44.1kHz
  • 设置 DELAY 所以 flash.media.Sound 对象 bytesTotal - DELAY = 硬编码长度 * 128kbps

它可以播放,但是:

  1. Audacity 的 mp3 仍然有令人讨厌的差距。
  2. mp3 来自填补 mp3 空白的工具(来自这里http://www.compuphase.com/mp3/mp3loops.htm)播放效果更好,但开头的声音并不清晰。
  3. 停止声音后,我可以听到恼人的“咔哒”声。

您能帮我理解为什么(1)会发生以及如何解决所有 3 个问题吗?

4

1 回答 1

0

使用 Flash 完成无间隙循环很烦人,但这是可能的。

  • 尝试制作无缝 MP3 是很困难的,所以完全避免这个问题!将循环导入为 WAV 文件,而不是 MP3。WAV 没有任何编码器延迟,并且可以轻松产生无缝循环。

  • 使用Sound.play()的 loops 参数循环播放声音。如果音频真的是无缝的,这应该会产生一个无缝的循环。不要尝试使用SOUND_COMPLETE事件来循环声音。此事件与帧速率相关,并在声音完成后不久触发,而不是在实际完成时触发,因此它总是会导致间隙。

  • 正如您所注意到的,Sound.length 通常并不准确。如果您确实需要准确的样本计数,请使用Sound.extract()提取完整的音频数据。它返回提取的样本数。

  • 如果由于某种原因您无法嵌入无缝 WAV 文件,或者您必须从外部位置流式传输 MP3,您可以这样做:

    1. 使用 Sound.extract() 提取音频数据。
    2. 切掉数据开头和结尾的静音部分。您可以使用一些硬编码的值来做到这一点,或者通过将样本与一些小 epsilon 进行比较来聪明并切断。
    3. 使用Sound.loadPCMFromByteArray()将裁剪的数据重新加载到声音剪辑中。
    4. 现在可以使用 Sound.play 和 loops 参数循环裁剪的剪辑。

这是一些示例代码:

// load our original audio track and extract the samples
var music:Sound = new Music();
var data:ByteArray = new ByteArray();
music.extract(data,99999999);
data.position = 0;

// crop off silent samples from the beginning
// TODO: you should also do this for the end
var i:uint = 0;
const EPSILON:Number = 0.05;
var sample:Number = 0;
// step forward until the magnitude exceeds some threshold
while(data.bytesAvailable > 8 && sample < EPSILON) {
    sample = Math.abs(data.readFloat()) + Math.abs(data.readFloat());
}

// now, data.position is the location where the audio first kicks in
// let's crop it
var croppedData:ByteArray = new ByteArray();
croppedData.writeBytes(data, data.position);
croppedData.position = 0;

// load our newly cropped data and loop
music = new Sound();
music.loadPCMFromByteArray(croppedData, croppedData.length / 8);
music.play(0,99999);

与尝试使用 SampleDataEvent 实时跳过间隙相比,这更容易且处理器密集度更低。如果您确实需要使用 SampleDataEvent 进行动态播放,那么此方法仍然有助于为您提供大量没有间隙的音频数据。

请注意,上述内容仅适用于 Flash。由于您使用的是 NME,这增加了一层额外的皱纹,因为 NME 可能会在打包过程中摆弄声音,并且上述功能并非在所有目标上都可用。但是,如果您只是为 Flash 目标发布,这些技术应该仍然有效。

于 2013-03-15T12:07:04.430 回答