我对Java Sound(javax.sound包)有一个不那么简单的问题。
我正在实现具有交叉渐变和平滑音量的MP3播放器并寻求控制。
我正在以4096byte块的形式读取声音,并以毫秒为单位手动计算位置。
当我想寻找()(改变流将变为红色的基准位置)时,我听到声波中有一个非常丑陋的“跳跃”。我试过检查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 ,需要“以毫秒为单位的位置”
谢谢,我很沮丧......
答案 0 :(得分:0)
如果要转换的块太短而不能交叉淡入淡出,则无法真正创建平滑过渡,但是您可以从边界消除最坏的伪像。
我所指的不好的神器经常听起来像是咔嗒声或砰砰声,但是如果有很多短暂的连续声,它可能听起来像是一种颠簸的声音,或者如果间隔是规则的话甚至可能引入它自己的特定音高。这种伪像是创建任意音频块的结果,因为边界处的音频幅度可以从一个块跳到下一个块,或者从块的末端跳到静音。有几种方法可以消除它,最常见的方法是将边界从任意位置移动到最近的“零交叉”,这样就不再有跳跃或不连续。或者,由于您的块彼此重叠,您可以做一些事情来找到块的值彼此交叉的地方,最好是朝着相同的方向。
答案 1 :(得分:0)
我知道这样做的唯一方法是直接处理每帧级别的数据。你必须“打开”声音来获取字节并直接进行计算。大多数内置的Java控件都具有受缓冲区大小阻碍的粒度,即每个声音数据缓冲区只能处理一次音量变化。
即使您在每帧级别工作,Java也缺乏实时保证可能会遇到问题。但它们是可以克服的。
我制作了一个“剪辑切片器”,例如,使用相当于剪辑作为源声音。它采用样本的随机切片并将它们串在一起。只需16帧重叠插值即可保持声音流畅。使用1/10秒的16帧重叠片段可以很好地制作4秒钟录制的无尽流媒体。
我做了一个Theremin,它为音量和音高提供鼠标移动侦听器位置。我让它工作得非常顺利,有大约30或40帧延迟。诀窍是为鼠标动作监听器输出加上时间戳,并根据对该数据的计算进行控制,因为事件没有到达或实时平滑处理,造成拉链或其他不连续性。
另一件需要考虑的事情是,数据范围无法很好地映射到分贝。因此,低端的小体积差异比高端的相同音量间隔更不连续(并且易于发出咔嗒声)。我通过将音频数据映射到分贝音量,并根据幅度映射为音量变化量供电来解决这个问题。我希望其中一些想法有用!