1

因此,我试图让 Java 在这方面以一定的速度播放声音,我尝试为 SourceDataLine 获得一个用于采样率的控件:

`package com.pap.sound;

import javax.sound.sampled.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.BitSet;

public class Player implements Playable {
private AudioFormat format;
private SourceDataLine sourceDataLine;
private DataLine.Info info;
private final URL soundUrl;
private final boolean[] stopped;
private float playRate;
private boolean playRateChanged;


public Player(URL soundUrl) throws LineUnavailableException,     MalformedURLException {
    this.format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100, 16, 2 , 4, 44100,false);
    this.info = new DataLine.Info(SourceDataLine.class, format);
    this.sourceDataLine =  (SourceDataLine) AudioSystem.getLine(info);
    this.soundUrl = soundUrl;
    this.stopped = new boolean[1];
    this.stopped[0] = false;
    this.playRate = 1;
    this.playRateChanged = false;
}
@Override
public boolean play() throws LineUnavailableException {
    sourceDataLine.open();
    Thread playerThread = new Thread(){

        @Override
        public void run() {
            int numberOfBitesRead = 0;
            AudioInputStream auis = null;
            try {
                auis = AudioSystem.getAudioInputStream(soundUrl);
            } catch (UnsupportedAudioFileException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] bytes = new byte[4];
            sourceDataLine.start();
            try {
                auis.mark(auis.available());

            while(!stopped[0]) {

                numberOfBitesRead = auis.read(bytes);
                if(numberOfBitesRead == -1) {
                    auis.reset();
                }

                sourceDataLine.write(bytes, 0, bytes.length);
                FloatControl fc = (FloatControl)     sourceDataLine.getControl(FloatControl.Type.SAMPLE_RATE);
                if(playRateChanged) {
                    fc.setValue((int)(44200*playRate));
                    playRateChanged = false;
                }
            }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    };

    playerThread.start();

    return false;
}

@Override
public boolean stop() {
    this.stopped[0] = true;
    this.sourceDataLine.stop();
    this.sourceDataLine.close();
    return false;
}

@Override
public boolean setPlayRate(float playRate) {
    this.playRate = playRate;
    this.playRateChanged = true;
    return false;
}

}`

但在运行时我得到:

Exception in thread "Thread-1" java.lang.IllegalArgumentException: Unsupported control type: Sample Rate
    at com.sun.media.sound.AbstractLine.getControl(AbstractLine.java:150)
    at com.pap.sound.Player$1.run(Player.java:67)

大家有遇到过这样的事情吗?我试图为此找到答案,但找不到答案。我正在使用 Java 8。 在此处输入图像描述 感谢您的帮助。

4

1 回答 1

0

In the end I came up with a solution. Because the old FloatControl.Type.SAMPLE_RATE is not available anymore in Java 8 I chosed to increase the sample reate by simply ommiting some of the bytes when I play the sound the solution looks as follows:

This is the inferface:

package com.pap.sound;

import javax.sound.sampled.LineUnavailableException;


public interface Playable {
public boolean play() throws LineUnavailableException;
public boolean stop();
public boolean setPlayRate(float playRate);
}

This is the player class:

package com.pap.sound;

import com.sun.media.sound.AudioFloatFormatConverter;
import com.sun.media.sound.JavaSoundAudioClip;
import com.sun.media.sound.SoftMixingDataLine;

import javax.sound.sampled.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;


public class Player implements Playable {
 private AudioFormat format;
 private SourceDataLine sourceDataLine;
 private DataLine.Info info;
 private final URL soundUrl;
 private final boolean[] stopped;
 private float playRate;
 private boolean playRateChanged;
 private int bytesWritten;
 private int bytesIgnorred;


public Player(URL soundUrl) throws LineUnavailableException, MalformedURLException {
    this.format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100, 16, 2 , 4, 44100,false);
    this.info = new DataLine.Info(SourceDataLine.class, format);
    this.sourceDataLine =  (SourceDataLine) AudioSystem.getLine(info);
    TargetDataLine tdl = AudioSystem.getTargetDataLine(format);

    this.soundUrl = soundUrl;
    this.stopped = new boolean[1];
    this.stopped[0] = false;
    this.playRate = 1;
    this.playRateChanged = false;
    this.bytesWritten =0;
    this.bytesIgnorred = 0;
}
@Override
public boolean play() throws LineUnavailableException {
    sourceDataLine.open();
    final Thread playerThread = new Thread(){

        @Override
        public void run() {
            int numberOfBitesRead = 0;
            AudioInputStream auis = null;
            try {
                auis = AudioSystem.getAudioInputStream(soundUrl);
            } catch (UnsupportedAudioFileException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] bytes = new byte[4];
            sourceDataLine.start();
            try {
                auis.mark(auis.available());

            while(!stopped[0]) {

                numberOfBitesRead = auis.read(bytes);
                if(numberOfBitesRead == -1) {
                    auis.reset();
                }
                if(bytesWritten < (10)) {
                    sourceDataLine.write(bytes, 0, bytes.length);
                    bytesWritten+=4;
                } else {
                    if(bytesIgnorred < ((int)(playRate*10-10))) {
                        bytesIgnorred+=4;
                    } else {
                        bytesWritten =0;
                        bytesIgnorred = 0;
                    }
                }
            }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    };

    playerThread.start();

    return false;
}

@Override
public boolean stop() {
    this.stopped[0] = true;
    this.sourceDataLine.stop();
    this.sourceDataLine.close();
    return false;
}

@Override
public boolean setPlayRate(float playRate) {
    this.playRate = playRate;
    this.playRateChanged = true;
    return false;
}

}

To test it I used the following code:

package com.pap.main;

import com.pap.sound.Player;
import javax.sound.sampled.LineUnavailableException;
import java.net.MalformedURLException;
import java.net.URL;


public class Main {
public static void main(String[] args) throws MalformedURLException, LineUnavailableException, InterruptedException {
    URL url = ClassLoader.getSystemClassLoader().getSystemResource("steam.wav");
    Player player = new Player(url);
    player.play();
    Thread.sleep(2000);
    for(int i=0;i<60;i++) {
        player.setPlayRate(1f+(float)(i)*0.1f);
        System.out.println(1f+(float)(i)*0.1f + "x");
        Thread.sleep(1000);
    }
    player.stop();
}

}

于 2015-09-23T20:13:41.453 回答