Java-调整WAV文件的播放速度

时间:2018-09-29 21:01:36

标签: java audio javasound pcm audio-processing

我可能很稠密,但似乎无法找到解决问题的方法

注意::我可以找到很多人报告此问题,似乎是由于Java更新(可能是1.5?)导致的。也许不再支持SAMPLE_RATE?无法找到任何解决方案)

我正在尝试调整SAMPLE_RATE以加快/减慢歌曲速度。我可以顺利播放.wav文件,所以我研究了可用于调节音量的FloatControl:

public void adjustVolume(String audioType, float gain) {
        FloatControl gainControl = null;

        gainControl = (FloatControl) clipSFX.getControl(FloatControl.Type.MASTER_GAIN);
                if(gain > MAX_VOLUME)
                    gain = MAX_VOLUME;
                if(gain < MIN_VOLUME)
                    gain = MIN_VOLUME;

            //set volume
            gainControl.setValue(gain);
    }

但是当尝试将此原理转换为SAMPLE_RATE时,我在此阶段很早就收到了一个错误:

    public void adjustVolume(String audioType, float gain) {
        FloatControl gainControl = null;

        gainControl = (FloatControl) clipSFX.getControl(FloatControl.Type.SAMPLE_RATE);
        //ERROR: Exception in thread "Thread-3" java.lang.IllegalArgumentException: Unsupported control type: Sample Rate

        //I haven't gotten this far yet since the above breaks, but in theory will then set value?
            gainControl.setValue(gain);
}

我在网上找到的所有内容似乎都与从麦克风或某些外部线路上获取输入有关,似乎并没有转化为使用音频文件,因此我不确定我所缺少的内容。任何帮助,将不胜感激!谢谢!

2 个答案:

答案 0 :(得分:2)

这里我们有一种改变速度的方法-通过使采样率加倍。基本上,步骤如下:

  • 打开文件的音频流
  • 获取格式
  • 更改采样率后创建新格式
  • 打开具有该格式的数据行
  • 从文件/音频流中读取并播放到行上

这里的概念是SourceDataLine,AudioFormat和AudioInputStream。如果您查看javax.sound教程,将会发现它们,甚至是类的页面。现在,您可以创建自己的方法(如Adjust(factor)),该方法只会获取新格式,而其他所有格式都保持不变。

  public void play() {
    try {
      File fileIn = new File(" ....);
      AudioInputStream audioInputStream=AudioSystem.getAudioInputStream(fileIn);
      AudioFormat formatIn=audioInputStream.getFormat();
      AudioFormat format=new AudioFormat(formatIn.getSampleRate()*2, formatIn.getSampleSizeInBits(), formatIn.getChannels(), true, formatIn.isBigEndian());
          System.out.println(formatIn.toString());
          System.out.println(format.toString());
      byte[] data=new byte[1024];
      DataLine.Info dinfo=new DataLine.Info(SourceDataLine.class, format);
      SourceDataLine line=(SourceDataLine)AudioSystem.getLine(dinfo);
      if(line!=null) {
        line.open(format);
        line.start();
        while(true) {
          int k=audioInputStream.read(data, 0, data.length);
          if(k<0) break;
          line.write(data, 0, k);
        }
        line.stop();
        line.close();
      }
    }
    catch(Exception ex) { ex.printStackTrace(); }
  }

答案 1 :(得分:1)

在处理音频数据时,还可以通过使用线性插值来改变速度。

音频值排列在一个数组中,并且光标通常在值之间移动。但是,您可以设置进度以增加任意量,例如1.5帧,并在需要时创建加权值。

假设数据如下:

  1. 0.5
  2. 0.8
  3. 0.2
  4. -0.1
  5. -0.5
  6. -0.7

您的播放数据(用于1.5速率)应为

  1. 0.5
  2. (0.8 + 0.2)/ 2
  3. -0.1
  4. (-0.5 + -0.7)/ 2

我知道在Stack Overflow之前,有一些帖子可以更全面地解释该算法。原谅我没有追踪他们。

我使用此方法在以下开放源代码库AudioCue中允许实时更改.wav播放速度。随时检查代码并利用其中的思想。

跟随是一种从位于两个音频帧之间的点创建立体声音频值对的方法(数据为带符号的浮点,范围从-1到1)。它来自AudioCuePlayer中的内部类AudioCue.java。可能不是最容易阅读的。所读取的声音数据位于数组cue中,而idx是通过该数组进行的当前“播放头”位置。 “ intIndex”是音频帧,而“ flatIndex”是帧在数组中的实际位置。我使用帧跟踪播放头的位置并计算插值权重,然后使用flatIndex从数组中获取相应的值。

private float[] readFractionalFrame(float[] audioVals, float idx)
{
    final int intIndex = (int) idx;
    final int flatIndex = intIndex * 2;

    audioVals[0] = cue[flatIndex + 2] * (idx - intIndex) 
            + cue[flatIndex] * ((intIndex + 1) - idx);

    audioVals[1] = cue[flatIndex + 3] * (idx - intIndex) 
            + cue[flatIndex + 1] * ((intIndex + 1) - idx);

    return audioVals;
}

如果有问题我很乐意澄清。