使用 Java Sound API 跳转到音频文件中的位置

发布于 2024-11-30 11:06:24 字数 1575 浏览 1 评论 0 原文

我正在使用 AudioInputStream 将字节提供给 SourceDataLine 播放 PCM 文件。我想让用户能够移动滑块以跳转到文件中的某个点。

我遇到的问题:

了解我考虑使用 的 内存映射文件 将字节提供给行,这样我就可以跳到任何我想要的地方,但如果不需要的话,我不想增加函数的复杂性。有没有一个好的方法可以做到我所缺少的?任何人都可以解释 getLongFramePosition() 实际上是什么意思?是通过扬声器的帧数(似乎不是)?

I'm using a AudioInputStream to feed bytes to a SourceDataLine to play a PCM file. I want to give the user the ability to move a slider to jump to some point in the file.

Issues I'm having:

  • markSupported() returns false on my AudioInputStream. So I
    cannot use my initial approach to call reset() then skip() (which
    I already thought was kind of ugly...)
  • I would really prefer not to tear down the InputStream and create a new one just to jump to a position prior to my current mark.
  • SourceLineData.getLongFramePosition() does not seem to be very reliable... I know it has a buffer, but even if account for the bytes left in the buffer, i do not understand the behavior

I have considered using a Memory-Mapped File to feed bytes to the line that way I can jump wherever I want, but I don't want to add complexity to the function if I don't have to. Is there a good way to do this that I'm missing? also can anyone explain what the frame number returned by getLongFramePosition() actually means? is it number of frames passed through speakers (does not appear to be)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

幸福还没到 2024-12-07 11:06:24

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

允世 2024-12-07 11:06:24

我能想到的最简洁的方法是使用 FileChannel 将字节读取到 SourceDataLine 中,这样根据用户移动滑块,我可以确定字节位置文件(确保调整或舍入它以与帧对齐),然后在 FileChannel 中设置该位置,然后继续播放。当发生这种情况时,我刷新了线路,以防止播放剩余的字节。

The cleanest way I could come up with was to use a FileChannel to read the bytes into the SourceDataLine 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 the FileChannel and then continue playback. I flushed the line when this happened to keep from playing remaining bytes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文