有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

音频Java调整WAV文件的播放速度

我可能很笨,但我似乎找不到解决问题的办法

注意:我可以找到很多人报告这个问题,似乎这是新Java(可能是1.5?)的结果。也许不再支持抽样率?我找不到任何解决办法)

我正在尝试调整采样率以加快/减慢歌曲。我可以成功地玩一个游戏。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);
    }

但在尝试将这一原理转化为采样率时,我在这个阶段很早就遇到了一个错误:

    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) 个答案

  1. # 1 楼答案

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

    • 打开文件的音频流
    • 获取格式
    • 在更改采样率的情况下创建新格式
    • 用该格式打开数据行
    • 从文件/音频流中读取并在线播放

    这里的概念是SourceDataLine、AudioFormat和AudioInputStream。看看javax。声音教程你会找到它们,甚至是课程的页面。现在,您可以创建自己的方法(比如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(); }
      }
    
  2. # 2 楼答案

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

    音频值以数组形式排列,光标通常从一个值移动到另一个值。但您可以设置进度为任意数量,例如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

    我知道在堆栈溢出之前,有一些帖子更全面地解释了这种算法。原谅我没有追踪到他们

    我使用这种方法来允许实时的速度变化。wav在以下开源库中播放:AudioCue。请随意查看代码并利用其中的想法

    以下是从位于两个音频帧之间的点(数据是有符号的浮动,范围从-1到1)创建一对立体声音频值的方法。它来自AudioCue.java中的一个内部类AudioCuePlayer。可能不是最容易读的。正在读取的声音数据在数组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;
    }
    

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