简体   繁体   English

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

[英]Java - Adjust playback speed of a WAV file

I'm likely dense but I cannot seem to find a solution to my issue 我可能很忙,但似乎找不到解决方案

( NOTE: I CAN find lots of people reporting this issue, seems like it happened as a result of newer Java (possible 1.5?). Perhaps SAMPLE_RATE is no longer supported? I am unable to find any solution) . 注意:我可以找到很多人报告此问题,似乎是由于Java更新引起的(可能是1.5?)。也许不再支持SAMPLE_RATE?我找不到任何解决方案 。)

I'm trying to adjust the SAMPLE_RATE to speed up/slow down song. 我正在尝试调整SAMPLE_RATE以加快/降低歌曲速度。 I can successfully play a .wav file without issue, so I looked into FloatControl which worked for adjusting volume: 我可以成功播放.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);
    }

But when trying to translate this principle to SAMPLE_RATE, I get an error very early on at this stage: 但是,当尝试将此原理转换为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);
}

Everything I've found online seems to be related to taking input from a mic or some external line and doesn't seem to translate to using an audio file, so I'm unsure what I'm missing. 我在网上找到的所有内容似乎都与从麦克风或某些外部线路上获取输入有关,似乎并没有转化为使用音频文件,因此我不确定自己缺少什么。 Any help would be appreciated! 任何帮助,将不胜感激! Thanks! 谢谢!

Here we have a method that changes the speed - by doubling the sample rate. 在这里,我们有一种改变速度的方法-通过使采样率加倍。 Basically the steps are as follows: 基本上,步骤如下:

  • open the audio stream of the file 打开文件的音频流
  • get the format 获取格式
  • create a new format with the sample rate changed 更改采样率以创建新格式
  • open a data line with that format 打开具有该格式的数据行
  • read from the file/audio stream and play onto the line 从文件/音频流中读取并播放

The concepts here are SourceDataLine, AudioFormat and AudioInputStream. 这里的概念是SourceDataLine,AudioFormat和AudioInputStream。 If you look at the javax.sound tutorial you will find them, or even the pages of the classes. 如果您查看javax.sound教程,将会发现它们,甚至是类的页面。 You can now create your own method (like adjust(factor)) that just gets the new format and all else stay the same. 现在,您可以创建自己的方法(如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(); }
  }

It is also possible to vary the speed by using linear interpolation when progressing through the audio data. 处理音频数据时,还可以通过使用线性插值来更改速度。

Audio values are laid out in an array and the cursor normally goes from value to value. 音频值排列在数组中,并且光标通常在值之间移动。 But you can set things up to progress an arbitrary amount, for example 1.5 frames, and create a weighted value where needed. 但是您可以设置进度以增加任意数量,例如1.5帧,并在需要时创建加权值。

Suppose data is as follows: 假设数据如下:

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

Your playback data (for 1.5 rate) would be 您的播放数据(1.5速率)将是

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

I know there have been posts that more fully explain this algorithm before on Stack Overflow. 我知道在Stack Overflow之前,有一些帖子可以更全面地解释该算法。 Forgive me for not tracking them down. 原谅我没有追踪他们。

I use this method to allow real-time speed changes in .wav playback in the following open-source library: AudioCue . 我使用这种方法在以下开源库AudioCue中允许实时更改.wav播放速度。 Feel free to check out the code and make use of the ideas in it. 随时检查代码并利用其中的思想。

Following is the method that creates a stereo pair of audio values from a spot that lies in between two audio frames (data is signed floats, ranging from -1 to 1). 以下是从位于两个音频帧之间的点创建立体声音频值对的方法(数据为带符号的浮点,范围为-1至1)。 It's from an inner class AudioCuePlayer in AudioCue.java . 它来自AudioCuePlayer中的内部类AudioCue.java Probably not the easiest to read. 可能不是最容易阅读的。 The sound data being read is in the array cue , and idx is the current "play head" location that is progressing through this array. 正在读取的声音数据在数组cue ,而idx是在此数组中进行的当前“播放头”位置。 'intIndex' is the audio frame, and 'flatIndex' is the actual location of the frame in the array. “ intIndex”是音频帧,而“ flatIndex”是帧在数组中的实际位置。 I use frames to track the playhead's location and calculate the interpolation weights, and then use the flatIndex for getting the corresponding values from the array. 我使用帧跟踪播放头的位置并计算插值权重,然后使用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;
}

I'd be happy to clarify if there are questions. 我很乐意澄清是否有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM