-1

我对 Java Sound(javax.sound 包)有一个不那么简单的问题。

我正在实现具有交叉淡入淡出和平滑音量和搜索控件的 MP3 播放器。

我正在以 4096 字节块的形式将声音读取为流,并以毫秒为单位手动计算位置。

当我想 seek() (从流变为红色的位置更改基本位置)时,我听到声波中有一个非常难看的“跳跃”。我尝试检查 JLayer 和其他 MP3 API,但它们根本没有 seek() 函数,或者它们也有这种“丑陋的声音跳跃”。

我的问题是:我怎样才能使从一个声波块到另一个声波块的跳跃更平滑?我尝试了插值,但“听不到跳跃”的合理时间是 300 毫秒,这对于 seek() 函数来说太长了。

你遇到过这个问题吗?

你知道解决办法吗?

为了确定,我将在此处粘贴代码示例。

public void seek( long pPosition )
{
  sourceDataLine.flush();

  seekIndex = ( sourceDataLine.getMicrosecondPosition() / 1000 ) - currentPositionInMilliseconds;

}

public long getPositionInMilliseconds()
{ return ( sourceDataLine.getMicrosecondPosition() / 1000 ) - seekIndex; }

由于 javax.sound 的 DataLine API,需要“以毫秒为单位的位置”

谢谢,郁闷...

4

2 回答 2

0

我知道这样做的唯一方法是直接处理每帧级别的数据。您必须“打开”声音以获取字节并直接进行计算。大多数内置Java 控件的粒度受到缓冲区大小的限制,即实际上每个声音数据缓冲区只能处理一个音量变化。

即使您在每帧级别上工作,也有一些问题需要克服,因为 Java 缺乏实时保证。但它们是可以克服的。

例如,我制作了一个“剪辑切片器”,它使用剪辑的等价物作为源声音。它随机抽取样本切片并将它们串在一起。仅 16 帧的重叠插值就可以保持声音流畅。使用具有 16 帧重叠的 1/10 秒片段非常适合从 4 秒的录制中制作出无尽的流小溪。

我制作了一个 Theremin,它将鼠标运动听众的位置用于音量和音高。我让它在大约 30 或 40 帧延迟的情况下工作得非常顺利。诀窍是对鼠标运动侦听器的输出进行时间标记,并将控制基于基于该数据进行的计算,因为事件不会实时到达或得到平滑处理,从而产生拉链或其他不连续性。

另一件需要考虑的事情是,数据的范围不能很好地映射到分贝。因此,低端的小音量差异比高端的相同音量间隔更不连续(并且容易出现咔嗒声)。我通过将音频数据映射到分贝音量来解决这个问题,并根据幅度映射为音量变化量提供动力。我希望其中一些想法对您有所帮助!

于 2013-07-15T01:04:56.997 回答
0

如果要过渡的块太短而无法进行交叉淡化,则无法真正创建平滑过渡,但您可以消除边界中最糟糕的伪影。

我所指的不良伪像通常听起来像咔哒声或爆裂声,但如果有很多连续的声音,它可能听起来像一种颠簸的声音,或者如果间隔是规则的,它甚至可能引入自己的特定音高。这种伪影是创建任意音频块的结果,因为边界处的音频幅度可能会从一个块跳到下一个块,或者从块的末尾跳到静音。有几种方法可以消除它,其中最常见的是将边界从任意位置移动到最近的“零交叉”,这样就不再有跳跃或不连续性。或者,由于您的块在彼此的顶部腐烂,您可以做一些事情来找到块的值相互交叉的地方,最好是朝着相同的方向。

于 2013-07-14T20:24:26.247 回答