【问题标题】:Real-time java sound volume adjustment实时java音量调节
【发布时间】:2021-01-01 03:24:39
【问题描述】:

我使用 Java 的 SourceDataLine 播放声音,但每当我尝试调整音量(增益)时,动作和扬声器响应之间会有 0.2-0.5 秒的延迟。音频数据以 4k-16k 块写入(16 位单声道,22kHz ~ 44k/s)。

如何使音量调整更加实时?

write(byte[], int, int) 是否锁定了 FloatControl 的增益调整?

我是否需要恢复到同时调整声音缓冲区数据量的 DSP 方式或提交更小的块?

JDK7,不错的Windows PC

【问题讨论】:

  • 不是我一直在寻找的答案,但看来我必须回到 Java 游戏开发书籍才能找到 DSP 解决方案。

标签: java audio


【解决方案1】:

声音系统从 SourceDataLine 以几(百...)千字节为单位获取数据并缓冲它们。如果你改变它的参数,直到系统播放缓冲区为空并且从SDL中读取新数据后才会生效。

您需要做的是更改系统播放音量(即刻生效)周围的某个地方,而不是修改您提供给它的数据。

【讨论】:

  • 弄乱系统的主卷似乎不是一个好方法,因为我想我需要 JNI/JNA 来做到这一点。我个人讨厌那些这样做的应用程序。另外,我必须使用不同的音量设置同时播放音乐和其他声音。
  • 很遗憾,我无法为您提供更多帮助。这是我对 JavaSound 的唯一了解,它以许多意想不到的方式被破坏了.. :(
  • 谢谢,不幸的是,这个话题也超出了我的专业范围——这就是我问的原因。也许我应该再看看游戏声音的生成。
【解决方案2】:

您是否尝试在调用 SourceDataLine.open() 时使用自定义(较低)缓冲区大小?

SourceDataLine.open( AudioFormat format, int bufferSize )

这应该会减少延迟。不过,主播放音量解决方案可能仍然会更快。

【讨论】:

    【解决方案3】:

    如果您能以某种方式影响/创建您的 Mixer 为您的 Line 包含的 Line.Info 类,您可以更改其最小和最大缓冲区。然后,您可以将缓冲区设置为您提供给它的块的大小,然后您的延迟将减少到无(假设)

    【讨论】:

      【解决方案4】:

      Oracle tutorial on Java Sound 在其结尾部分提供了使用 Float.Control 的替代答案:“直接操作音频数据”。通过直接操纵数据,具有单帧粒度潜力的实时能力的可能性出现了。不幸的是,他们没有给出具体的例子。

      基本方法是首先访问各个 PCM 帧。 Clip 不会给它存储在内存中的数据提供任何挂钩。一种解决方案是在通过AudioInputStream 加载文件时将字节处理为 PCM。 PCM 值可以乘以音量因子以达到所需的音量。然后,PCM转换回字节后,就可以用SourceDataLine播放了。

      对于实时响应来说,这里的关键是音量因子的处理。在AudioCue 中,我使用了让播放代码公开一个公开的、松散耦合的“目标”卷的计划。在每帧的基础上,将当前音量与期望的音量进行比较,并逐渐向期望的方向移动。 (音量变化在 1024 帧内线性发生,对于 44100 fps 大约是 1/40 秒。)可以在第 883 行的公共setVolume 方法中观察到一个代码示例,在第 892 行初始化平滑的细节。在处理循环中应用体积因子的代码是区域 1301-1322(在方法 fillBuffer 注释行 //adjust volume if needed 之后的第二级 for-loop 中)。

      在第一次提出问题多年后,我添加了这个答案。我认为这是值得包含的,因为它提供了一个有用的替代方案,而在第一次提出问题时没有给出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-24
        • 1970-01-01
        • 2013-12-20
        • 2014-11-30
        • 2012-01-10
        • 1970-01-01
        • 2015-03-23
        • 2012-06-21
        相关资源
        最近更新 更多