Increase playback speed of sound file in java
Asked Answered
R

2

4

I'm looking for information on how I can increase the playback speed of a sound file using Java and it's sound API.

I'm currently using a clip and an AudioInputStream to play back the file, but I'll be glad to change that if it means I can increase the playback speed.

Rattlebrain answered 22/4, 2011 at 21:14 Comment(0)
E
5

I do this by using linear interpolation. As you step through your samples by some increment, use the fractional distance to create a value to stream.

For example if you land at 1.25 (between a sample with value 10 and sample of value 30), you would output a value of 15.

Extrusive answered 19/6, 2011 at 18:19 Comment(5)
+1 A lot more useful than the integral speed increase offered in my answer.Cynar
I changed things to make your answer correct. I was using a complicated system of dropping every certain number of frames, but since I had a variable speed, things were quite messy. Your answer is a better solution, but sadly one I won't be implementing. The frame shift caused by the earlier solution, meant I took a completely different approach to solving the problem.Rattlebrain
I'm sorry to ask, how can I apply linear interpolation to the clip.Brookner
Since writing this answer, I've published a library on github where you can see the code. The address is github.com/philfrei/AudioCue The code you will want to examine is in the class AudioCue and the method readFractionalFrames(). Or, working from the example in my answer, treat the value 10 as the contents of frame 1 and 30 as the contents of frame 2. If you had a straight line for the (X,Y) points would be (1, 10) and (2, 30). Now find the Y value where X = 1.25. This is the same process.Extrusive
Ah, but maybe you were asking about how to get the frame information from a Clip! If that is the case, I am sorry to say, the Java Clip does not allow you access to the PCM data. You will have to use SourceDataLine instead of Clip if you wish to get at the data points.Extrusive
C
2

A crude way to play back at an integral number (2,3,4..) of times the original speed, is to skip every so many samples of the original input stream. E.G. For double speed, skip one out of two, for triple speed, skip 2 out of 3.

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?");
    }
}

Example Input/Output

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> 
Cynar answered 23/4, 2011 at 5:42 Comment(7)
Any pointers as to which libraries/methods I could use to do this?Rattlebrain
This doesn't seem to work when using a byte stream that have been mixed (In my test that was after a concatenator, and then a Mixer). It only appears to work on byte stream obtained from sound files. I keep running into the error "could not get audio input stream from input stream"Rattlebrain
That comment was made too soon. I realized the issue was that I was trying to create an AudioInputStream using AudioSystem.getAudioInputStream instead of using the AudioInputStream constructor. Thanks a lot @Andrew ThompsonRattlebrain
@Varun Madiath: Glad you sorted it. :-)Cynar
@AndrewThompson Are there any ways I can playback at float numbers? (1.2, 1.5, 2.5)Brookner
Ah, thanks. Can I change some code in AcceleratePlayback to achieve the same result?Brookner
@Brookner I can't. What you can achieve is unknown to me.Cynar

© 2022 - 2024 — McMap. All rights reserved.