我有一个播放音频文件的声音类。但是,某些ogg文件在播放时不起作用。我不确定这是由于文件格式还是文件大小引起的。
文件较小似乎是问题所在,因为可以正常工作的文件大于或等于6.7 kb,而不能工作的文件小于或等于6 kb。
但是,我尝试在具有Audacity功能的oggs之一的末尾添加生成的音调,将文件增加到7.5 kb,但仍然无法正常工作。
这是我用来播放文件的Sound类:
import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED;
import static javax.sound.sampled.AudioSystem.getAudioInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine.Info;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
/**
* The {@code Sound} class plays audio from a wav, ogg, or mp3 file
* with wav working the best in a new thread
* <p>
* Here are some examples of how the {@code Sound} object can be initialized:
* <blockquote><pre>
* Sound soundOne = new Sound("pathToFile/music.wav", true);
* Sound soundTwo = new Sound(new File("pathToFile/music.wav"), true);
* Sound soundThree = new Sound(ClassName.class.getResource(pathToFile/music.wav), true);
* </pre></blockquote>
* <p>
* The class {@code Sound} includes methods for playing audio, stopping audio, changing
* the volume, getting the duration if a wav, get whether the audio is stopped, get
* whether the audio is finished, and changing the input file
*
*/
public class Sound {
/**
* Whether or not the music should be playing in a loop
*/
private boolean loopable;
/**
* Whether or not a URL was given
*/
private boolean isUrl;
/**
* The String name of the file
*/
private String fileName;
/**
* The URL location of the file
*/
private URL fileUrl;
/**
* The volume at which the sound plays at
*/
private double volume = 1.0;
/**
* The duration of the audio file in milliseconds
*/
private double durationInMilliseconds;
private ArrayList<PlayingSound> playingSounds = new ArrayList<>();
/**
* Initializes a newly created {@code Sound} object given a String file name
* @param fileName Path of the file to be played
* @param loopable Whether or not the audio should loop
* @throws UnsupportedAudioFileException Thrown if the file is not supported
* @throws IOException Thrown if there is a problem with the given file
*/
public Sound(String fileName, boolean loopable) throws UnsupportedAudioFileException, IOException {
isUrl = false;
this.fileName = fileName;
this.loopable = loopable;
if(fileName.endsWith(".wav")) {
final File file = new File(fileName);
AudioInputStream stream = AudioSystem.getAudioInputStream(file);
AudioFormat format = stream.getFormat();
long frames = stream.getFrameLength();
durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
}
}
/**
* Initializes a newly created {@code Sound} object given a File object
* @param inputFile File to be played
* @param loopable Whether or not the audio should loop
* @throws UnsupportedAudioFileException Thrown if the file is not supported
* @throws IOException Thrown if there is a problem with the given file
*/
public Sound(File inputFile, boolean loopable) throws UnsupportedAudioFileException, IOException {
isUrl = false;
this.fileName = inputFile.toString();
this.loopable = loopable;
if(fileName.endsWith(".wav")) {
AudioInputStream stream = AudioSystem.getAudioInputStream(inputFile);
AudioFormat format = stream.getFormat();
long frames = stream.getFrameLength();
durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
}
}
/**
* Initializes a newly created {@code Sound} object given a URL object
* @param url URL to audio file
* @param loopable Whether or not the audio should loop
* @throws UnsupportedAudioFileException Thrown if the file is not supported
* @throws IOException Thrown if there is a problem with the given file
*/
public Sound(URL url, boolean loopable) throws UnsupportedAudioFileException, IOException {
isUrl = true;
fileUrl = url;
String urlString = url.toString();
fileName = urlString.substring(Math.max(urlString.lastIndexOf('\\'), urlString.lastIndexOf('/')) + 1);
this.loopable = loopable;
if(fileUrl.getFile().endsWith(".wav")) {
AudioInputStream stream = AudioSystem.getAudioInputStream(fileUrl);
AudioFormat format = stream.getFormat();
long frames = stream.getFrameLength();
durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
}
}
/**
* Plays the audio from the given source
*/
public final void play() {
playingSounds.add(new PlayingSound());
}
/**
* Stops the audio from playing
*/
public final void stop() {
for(PlayingSound ps : playingSounds)
ps.stop();
}
/**
* Changes the volume of the audio
* @param volume Volume to change to
*/
public final void changeVolume(double volume) {
if(volume > 1 || volume < 0)
throw new IllegalArgumentException("Error: Volume must be between 0 and 1");
this.volume = volume;
}
/**
* The AudioFormat to specify the convention to represent the data
* @param inFormat The format of the audio file
* @return The necessary format information from the inFormat
*/
private AudioFormat getOutFormat(AudioFormat inFormat) {
final int ch = inFormat.getChannels();
final float rate = inFormat.getSampleRate();
return new AudioFormat(PCM_SIGNED, rate, 16, ch, ch * 2, rate, false);
}
/**
* Gives duration in milliseconds if .wav file
* @return Duration in milliseconds if .wav file
* @throws Exception Thrown if file is not .wav
*/
public double getDuration() throws Exception {
if(!isUrl && fileName.endsWith(".wav") || isUrl && fileUrl.getFile().endsWith(".wav"))
return durationInMilliseconds;
throw new Exception("Error: Length can only be determined for .wav files");
}
/**
* Returns whether or not the audio is playing
* @return Whether or not the audio is playing
*/
public final boolean isStopped() {
for(PlayingSound ps : playingSounds)
if(!ps.isStopped())
return false;
return true;
}
/**
* Returns whether or not the audio has finished playing (has exited loop)
* @return Whether or not the audio has finished playing (has exited loop)
*/
public final boolean isFinished() {
for(PlayingSound ps : playingSounds)
if(!ps.isFinished())
return false;
return true;
}
/**
* Changes the input location for the audio
* @param url The URL to replace the audio source
* @throws UnsupportedAudioFileException Thrown if the file is not supported
* @throws IOException Thrown if there is a problem with the given file
*/
public final void changeInput(URL url) throws UnsupportedAudioFileException, IOException {
isUrl = true;
fileUrl = url;
if(fileUrl.getFile().endsWith(".wav")) {
AudioInputStream stream = AudioSystem.getAudioInputStream(fileUrl);
AudioFormat format = stream.getFormat();
long frames = stream.getFrameLength();
durationInMilliseconds = 1000 * ((double) frames/format.getFrameRate());
}
}
private void removeInternalSound(PlayingSound ps) {
playingSounds.remove(ps);
}
/**
* Returns the volume the sound is currently set to
* @return The volume of the audio
*/
public final double getVolume() {
return volume;
}
@Override
public String toString() {
return String.format("String[name: %s, loopable: %b]", fileName, loopable);
}
private class PlayingSound {
private boolean stop = false;
private boolean finished = false;
private Thread playingSound;
PlayingSound() {
playingSound = new Thread(() -> {
do {
try {
AudioInputStream in;
if(!isUrl)
in = getAudioInputStream(new File(fileName));
else
in = getAudioInputStream(fileUrl);
final AudioFormat outFormat = getOutFormat(in.getFormat());
final Info info = new Info(SourceDataLine.class, outFormat);
try(final SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info)) {
if(line != null) {
line.open(outFormat);
line.start();
AudioInputStream inputMystream = AudioSystem.getAudioInputStream(outFormat, in);
stream(inputMystream, line);
line.drain();
line.stop();
}
}
}
catch(UnsupportedAudioFileException | LineUnavailableException | IOException e) {
throw new IllegalStateException(e);
}
} while(loopable && !stop);
finished = true;
removeInternalSound(this);
});
playingSound.start();
}
/**
* Streams the audio to the mixer
* @param in Input stream to audio file
* @param line Where the audio data can be written to
* @throws IOException Thrown if given file has any problems
*/
private void stream(AudioInputStream in, SourceDataLine line) throws IOException {
byte[] buffer = new byte[4];
for(int n = 0; n != -1 && !stop; n = in.read(buffer, 0, buffer.length)) {
byte[] bufferTemp = new byte[buffer.length];
for(int i = 0; i < bufferTemp.length; i += 2) {
short audioSample = (short) ((short) ((buffer[i + 1] & 0xff) << 8) | (buffer[i] & 0xff));
audioSample = (short) (audioSample * volume);
bufferTemp[i] = (byte) audioSample;
bufferTemp[i + 1] = (byte) (audioSample >> 8);
}
buffer = bufferTemp;
line.write(buffer, 0, n);
}
}
void stop() {
stop = true;
}
boolean isStopped() {
return stop;
}
boolean isFinished() {
return finished;
}
}
}
如果将pathToFile替换为文件的路径,则该类可用于测试上述Sound类:
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException, UnsupportedAudioFileException, InterruptedException {
Sound test = new Sound("pathToFile", false);
test.play();
Thread.sleep(1000);
}
}
这是三个可运行的ogg文件:
文件a:
https://dl.dropboxusercontent.com/s/hwgor2xk0ief7ui/workingOne.ogg
文件b:
https://dl.dropboxusercontent.com/s/4n14lxpvmw0ezpd/workingTwo.ogg
文件c:
https://dl.dropboxusercontent.com/s/749zrcglz1jpfow/workingThree.ogg
以下是三个失败的ogg文件:
文件d:
https://dl.dropboxusercontent.com/s/bwsu4ouwu06rfao/failedFile.ogg
文件d加上额外的生成色调,以使大小超出上述工作文件的大小:
https://dl.dropboxusercontent.com/s/t7q4wmh4ljqvz3a/failedFile2.ogg
文件e:
https://dl.dropboxusercontent.com/s/tddn22crdkvwawl/click.ogg
可能需要一些库才能使ogg文件与给定类一起使用。如果没有文件可用,请使用给定程序(可能使用IDE)编译给定zip中的库:
包含的(java jar)库是JLayer 1.0.1,Jogg 0.0.7,Jorbis 0.0.17-1,MP3 SPI 1.9.5,Tritonus-share 0.3.7.4和Ogg Vorbis SPI 1.0.3。 / p>
https://dl.dropboxusercontent.com/s/tqrj5w4vs32a3h8/lib.zip
更新:
我在文件d中添加了很多我之前在文件d中添加的音调(价值30秒),以查看它是否会改变任何东西,并且奏效。
因此,我决定开始剪切音频,直到音频无法播放为止。
奇怪的是,我剪切的长度小于文件d的长度,并且一直有效,直到剪切到一定程度为止。
我们称文件d的短版本为文件f,而文件d的短版本为文件g,而不是文件g。
此外,如果我在执行此操作的软件Audacity中将导出质量设置从10/10更改为5/10,则无法播放。我们称这个文件为h。
以下是每个上述文件:
文件f:
https://dl.dropboxusercontent.com/s/ore4bfgb0va2gw7/fileF.ogg
文件g:
https://dl.dropboxusercontent.com/s/zq000zhlup9hiu1/fileG.ogg
文件h:
https://dl.dropboxusercontent.com/s/4ojj7gv9x92z9mi/fileH.ogg