提高java中声音文件的播放速度

Posted

技术标签:

【中文标题】提高java中声音文件的播放速度【英文标题】:Increase playback speed of sound file in java 【发布时间】:2011-04-22 21:14:52 【问题描述】:

我正在寻找有关如何使用 Java 及其声音 API 提高声音文件播放速度的信息。

我目前正在使用剪辑和 AudioInputStream 来播放文件,但如果这意味着我可以提高播放速度,我会很高兴更改它。

【问题讨论】:

【参考方案1】:

我通过使用线性插值来做到这一点。当您逐步浏览样本时,请使用分数距离来创建要流式传输的值。

例如,如果您降落在 1.25(介于值为 10 的样本和值为 30 的样本之间),您将输出 15 的值。

【讨论】:

+1 比我的答案中提供的整体速度提升有用得多。 我更改了一些内容以使您的答案正确。我使用了一个复杂的系统,每隔一定数量的帧就丢帧,但由于我的速度是可变的,所以事情很混乱。您的答案是一个更好的解决方案,但遗憾的是我不会实施。早期解决方案引起的帧偏移意味着我采用了完全不同的方法来解决问题。 不好意思问一下,如何将linear interpolation申请到clip 自从写下这个答案后,我在 github 上发布了一个库,您可以在其中查看代码。地址是github.com/philfrei/AudioCue 您要检查的代码在AudioCue 类和readFractionalFrames() 方法中。或者,从我的答案中的示例开始,将值 10 视为第 1 帧的内容,将 30 视为第 2 帧的内容。如果 (X,Y) 点有一条直线,则为 (1, 10)和 (2, 30)。现在找到 X = 1.25 的 Y 值。这是相同的过程。 啊,但也许你问的是如何从剪辑中获取帧信息!如果是这种情况,我很遗憾地说,Java Clip 不允许您访问 PCM 数据。如果您希望获取数据点,则必须使用 SourceDataLine 而不是 Clip。【参考方案2】:

以原始速度的整数 (2,3,4..) 倍回放的粗略方法是跳过原始输入流的每这么多样本。例如。对于双倍速度,跳过二选一,三倍速,跳过三分之二。

AcceleratePlayback.java

import javax.swing.JOptionPane;
import javax.sound.sampled.*;
import java.net.URL;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.util.Date;

class AcceleratePlayback 

    public static void main(String[] args) throws Exception 
        int playBackSpeed = 1;
        if (args.length>0) 
            try 
                playBackSpeed = Integer.parseInt(args[0]);
             catch (Exception e) 
                e.printStackTrace();
                System.exit(1);
            
        
        int skip = playBackSpeed-1;
        System.out.println("Playback Rate: " + playBackSpeed);

        URL url = new URL("http://pscode.org/media/leftright.wav");
        System.out.println("URL: " + url);
        AudioInputStream ais = Audiosystem.getAudioInputStream(url);
        AudioFormat af = ais.getFormat();

        int frameSize = af.getFrameSize();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] b = new byte[2^16];
        int read = 1;
        while( read>-1 ) 
            read = ais.read(b);
            if (read>0) 
                baos.write(b, 0, read);
            
        
        System.out.println("End entire: \t" + new Date());

        byte[] b1 = baos.toByteArray();
        byte[] b2 = new byte[b1.length/playBackSpeed];
        for (int ii=0; ii<b2.length/frameSize; ii++) 
            for (int jj=0; jj<frameSize; jj++) 
                b2[(ii*frameSize)+jj] = b1[(ii*frameSize*playBackSpeed)+jj];
            
        
        System.out.println("End sub-sample: \t" + new Date());

        ByteArrayInputStream bais = new ByteArrayInputStream(b2);
        AudioInputStream aisAccelerated =
            new AudioInputStream(bais, af, b2.length);
        Clip clip = AudioSystem.getClip();
        clip.open(aisAccelerated);
        clip.loop(2*playBackSpeed);
        clip.start();

        JOptionPane.showMessageDialog(null, "Exit?");
    

示例输入/输出

prompt> java AcceleratePlayback
Playback Rate: 1
URL: http://pscode.org/media/leftright.wav
End entire:     Mon Apr 25 20:54:55 EST 2011
End sub-sample:         Mon Apr 25 20:54:55 EST 2011

prompt> java AcceleratePlayback 2
Playback Rate: 2
URL: http://pscode.org/media/leftright.wav
End entire:     Mon Apr 25 20:55:20 EST 2011
End sub-sample:         Mon Apr 25 20:55:20 EST 2011

prompt> java AcceleratePlayback 3
Playback Rate: 3
URL: http://pscode.org/media/leftright.wav
End entire:     Mon Apr 25 20:55:36 EST 2011
End sub-sample:         Mon Apr 25 20:55:36 EST 2011

prompt> 

【讨论】:

关于我可以使用哪些库/方法的任何指针? 这在使用混合的字节流时似乎不起作用(在我的测试中是在连接器之后,然后是混合器)。它似乎只适用于从声音文件获得的字节流。我一直遇到错误“无法从输入流中获取音频输入流” 该评论发表得太早了。我意识到问题是我试图使用 AudioSystem.getAudioInputStream 而不是使用 AudioInputStream 构造函数来创建 AudioInputStream。非常感谢@Andrew Thompson @Varun Madiath:很高兴你对它进行了排序。 :-) @AndrewThompson 有什么方法可以播放浮点数吗? (1.2, 1.5, 2.5)

以上是关于提高java中声音文件的播放速度的主要内容,如果未能解决你的问题,请参考以下文章

【c++】怎样才能使程序播放文件中的声音?

滚动视图滚动时如何播放取决于滚动视图滚动速度的声音?

如何逐渐加快 Android 中的声音播放速度?

PotPlayer使用总结

手机via浏览器有声音没视频

播放系统录制的声音