【问题标题】:playing wav file in java - how do I extend or concatenate the sound played?在 java 中播放 wav 文件 - 如何扩展或连接播放的声音?
【发布时间】:2023-03-26 10:15:01
【问题描述】:

是否可以创建一个包含 wav 文件“循环”的临时文件?

或者是否可以操纵发送到流读取器/写入器的流?

基本上我想播放一些 wav 文件一段时间,如果该时间大于 wav 文件提供的时间长度,我想循环播放。

【问题讨论】:

    标签: java audio wav


    【解决方案1】:
         AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
         Clip clip = AudioSystem.getClip();
         clip.loop((int)(Math.ceil(timeRequested / audioIn.getFrameLength())));
    

    【讨论】:

    • 我有几个问题 - 如何将循环“附加”到我正在使用的现有 DataLine?剪辑怎么办? - 如何将其发送到 SourceDataLine?
    • 它将自动附加到您当前活动的DataLine,clip就像另一个播放器实例,您可以随时启动或停止它。您可以查询caps,看看可以有多少个同时播放,如果需要,您可以定义一个队列。但我不建议自己混合。
    • 我会试一试,但不确定它是否能像我的代码那样与数据线一起工作。谢谢
    【解决方案2】:

    我不确定我是否理解实施解决方案的确切限制,但似乎最简洁的方法是在您第一次播放文件时将音频数据存储在缓冲区中。然后,如果用户需要更多迭代(全部或部分),只需将您缓存的数据重写回 SourceDataLine 所需的次数。

    这是一个link 示例声音文件播放器 (PCM),它的代码应该很容易修改(或只是从中学习)。我还修改了一些(注意:未经测试)代码,这些代码仅显示了我上面描述的逻辑:(您可能还想修改我在下面的内容以符合仅写入大小为倍数的数据块的规则帧大小。)

    public void playSoundFile(SourceDataLine line, InputStream inputStream, AudioFormat format, long length, float times)
    {
        int index = 0;
        int size = length * format.getFrameSize();
        int currentSize = 0;
        byte[] buffer = new byte[size];
        AudioInputStream audioInputStream = new AudioInputStream(inputStream, format, length);
        while (index < size)
        {
            currentSize = audioInputStream.read(buffer, index, size - index);
            line.write(buffer, index, currentSize);
            index += currentSize;
        }
    
        float currentTimes = 1.0;
        while (currentTimes < times)
        {
            float timesLeft = times - currentTimes;
            int writeBlockSize = line.available();
            index = 0;
    
            if (timesLeft >= 1.0)
            {
                while (index < size)
                {
                    currentSize = ((size - index) < writeBlockSize) ? size - index : writeBlockSize;
                    line.write(buffer, index, currentSize);
                    index += currentSize;
                }
                currentTimes += 1.0;
            }
            else
            {
                int partialSize = (int)(timesLeft * ((float) size) + 0.5f);
                while (index < partialSize)
                {
                    currentSize = ((partialSize - index) < writeBlockSize) ? partialSize - index : writeBlockSize;
                    line.write(buffer, index, currentSize);
                    index += currentSize;
                }
                currentTimes += timesLeft;
            }
        }
    }
    

    希望有帮助!

    【讨论】:

    • 这是一种可能性,但这并不是我想要的——数据是异步发送到播放器的,调用线程不知道文件/声音有多长。
    • 您能否提供更多有关具体情况的信息?有几件事没有指定(例如谁知道文件/声音的长度以及应该播放多长时间?如果是播放器,那么播放器可以执行我上面描述的缓存方法。)跨度>
    【解决方案3】:

    我想我会使用音频输入流中的每秒帧数和帧大小信息来解决这个问题。其他有用的信息在 SourceDataLine 对象的 getMicrosecondPosition() 方法中,以确定到目前为止播放的时间/持续时间。

    这与音频输入流中的标记和重置方法一起可能会处理这一切。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-25
      • 1970-01-01
      • 2015-08-15
      相关资源
      最近更新 更多