使用 Java Sound API 跳转到音频文件中的位置
我正在使用 AudioInputStream
将字节提供给 SourceDataLine
播放 PCM 文件。我想让用户能够移动滑块以跳转到文件中的某个点。
我遇到的问题:
-
markSupported()
在我的 false href="http://download.oracle.com/javase/1,5.0/docs/api/javax/sound/sampled/AudioInputStream.html" rel="nofollow">AudioInputStream
。所以我 无法使用我最初的方法调用reset()
然后调用skip()
(其中 我已经认为这有点丑陋......) - 我真的不想拆除
InputStrea
m 并创建一个新的,只是为了跳转到当前标记之前的位置。 -
SourceLineData。 getLongFramePosition()
似乎不是很可靠...我知道它有一个缓冲区,但即使考虑到缓冲区中剩余的字节
,我也这样做不是 行为
了解我考虑使用 的 内存映射文件
将字节提供给行,这样我就可以跳到任何我想要的地方,但如果不需要的话,我不想增加函数的复杂性。有没有一个好的方法可以做到我所缺少的?任何人都可以解释 getLongFramePosition()
实际上是什么意思?是通过扬声器的帧数(似乎不是)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
BigClip 对您有用吗?
如果没有,这里有一些可行的方法。警告,这有点复杂。
http://hexara.com/VSL/VSL2.htm
使用此 Applet,您可以加载wav——我加载 wav 的时间超过 5 分钟,效果很好,但音频数据确实占用了大量 RAM。
加载 WAV 后,您可以将鼠标移动到任意点并通过按住鼠标并拖动来播放。显然,这不完全是您想要做的,因为您想从一个点开始播放,而不用担心拖动或拖动速度。但我将数据置于可播放状态所采取的路径应该仍然适合您。
如果您有可用的 AudioInputStream 和 AudioFileFormat,则可以设置一个内部数组并将数据直接读入其中。音频文件格式为您提供编码和帧长度,您可以使用它们来计算数组维度。
然后,创建一个 TargetDataLine,从您创建的数组中获取音频数据。 TDL 必须有一个变量来标记下一次读取的开始位置。您可以使用 JSlider 更改该变量的内容以指向您想要的任何框架。
如果您没有可用的 AudioInputStream,可以通过多种方法获得......但它更复杂,涉及 ByteArrayOutput 和 ByteArrayOutput 。输入流对象。可能没有必要去那里。 (我用它们在上面的Applet中读取客户端数据。)
至于您关于当前帧位置的问题,关键问题是JVM以块的形式处理音频数据,并且它往往会领先于突发的声音。我为这个问题苦苦思索了很久,最后想到了这个:
http://www.java-gaming.org/index.php/topic ,24605.0.html
Did the BigClip work for you?
If not, here's something that could work. Warning, it is a little convoluted.
http://hexara.com/VSL/VSL2.htm
With this Applet, you can load a wav -- I've loaded wavs longer than 5 minutes and it has worked fine, but audio data does take up a lot of RAM.
Once the WAV is loaded, you can mouse to any point and playback via holding the mouse down and dragging. Obviously, that's not exactly what YOU want to do, since you want to play back from a point, and not worry about dragging or dragging speed. But the path I take to get the data in a playable state should still work for you.
If you have a working AudioInputStream and AudioFileFormat, you can set up an internal array and read the data directly into it. The audio file format gives you the encoding and the length in frames which you can use to calculate your array dimension.
Then, make a TargetDataLine that gets its audio data from the array you made. A TDL has to have a variable that marks where the next read will start. You can use your JSlider to change the contents of that variable to point to whatever frame you want.
If you don't have a working AudioInputStream, there are ways to get one...but it is more convoluted, involving ByteArrayOutput & Input Stream objects. Probably no need to go there. (I use them to read client data in the above Applet.)
As to your question about the current Frame location, the key problem is that the JVM processes audio data in chunks, and it tends to run ahead of what is heard in bursts. I banged my head against this problem for a long while, then came up with this:
http://www.java-gaming.org/index.php/topic,24605.0.html
我能想到的最简洁的方法是使用 FileChannel 将字节读取到 SourceDataLine 中,这样根据用户移动滑块,我可以确定字节位置文件(确保调整或舍入它以与帧对齐),然后在
FileChannel
中设置该位置,然后继续播放。当发生这种情况时,我刷新了线路,以防止播放剩余的字节。The cleanest way I could come up with was to use a
FileChannel
to read the bytes into theSourceDataLine
this way based on the user moving a slider I could determine the byte position in the file (making sure to adjust or round it to line up with a frame) and then set that position in theFileChannel
and then continue playback. I flushed the line when this happened to keep from playing remaining bytes.