Better error handling for Clip loading. (fixes #59)

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-03-23 16:42:02 -04:00
parent 16ec6c5e23
commit 850a6c3882
2 changed files with 69 additions and 75 deletions

View File

@ -35,7 +35,6 @@ import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine; import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineListener; import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.newdawn.slick.SlickException; import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader; import org.newdawn.slick.util.ResourceLoader;
@ -89,7 +88,7 @@ public class SoundController {
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url); AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
return loadClip(ref, audioIn, isMP3); return loadClip(ref, audioIn, isMP3);
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException | RuntimeException e) { } catch (Exception e) {
ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e, true); ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e, true);
return null; return null;
} }
@ -102,77 +101,72 @@ public class SoundController {
* @param isMP3 true if MP3, false if WAV * @param isMP3 true if MP3, false if WAV
* @return the loaded and opened clip * @return the loaded and opened clip
*/ */
private static MultiClip loadClip(String ref, AudioInputStream audioIn, boolean isMP3) { private static MultiClip loadClip(String ref, AudioInputStream audioIn, boolean isMP3)
try { throws IOException, LineUnavailableException {
AudioFormat format = audioIn.getFormat(); AudioFormat format = audioIn.getFormat();
if (isMP3) { if (isMP3) {
AudioFormat decodedFormat = new AudioFormat( AudioFormat decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16,
format.getChannels(), format.getChannels() * 2, format.getSampleRate(), false); format.getChannels(), format.getChannels() * 2, format.getSampleRate(), false);
AudioInputStream decodedAudioIn = AudioSystem.getAudioInputStream(decodedFormat, audioIn); AudioInputStream decodedAudioIn = AudioSystem.getAudioInputStream(decodedFormat, audioIn);
format = decodedFormat; format = decodedFormat;
audioIn = decodedAudioIn; audioIn = decodedAudioIn;
}
DataLine.Info info = new DataLine.Info(Clip.class, format);
if (AudioSystem.isLineSupported(info)) {
return new MultiClip(ref, audioIn);
} else {
// try to find closest matching line
Clip clip = AudioSystem.getClip();
AudioFormat[] formats = ((DataLine.Info) clip.getLineInfo()).getFormats();
int bestIndex = -1;
float bestScore = 0;
float sampleRate = format.getSampleRate();
if (sampleRate < 0)
sampleRate = clip.getFormat().getSampleRate();
float oldSampleRate = sampleRate;
while (true) {
for (int i = 0; i < formats.length; i++) {
AudioFormat curFormat = formats[i];
AudioFormat newFormat = new AudioFormat(
sampleRate, curFormat.getSampleSizeInBits(),
curFormat.getChannels(), true, curFormat.isBigEndian());
formats[i] = newFormat;
DataLine.Info newLine = new DataLine.Info(Clip.class, newFormat);
if (AudioSystem.isLineSupported(newLine) &&
AudioSystem.isConversionSupported(newFormat, format)) {
float score = 1
+ (newFormat.getSampleRate() == sampleRate ? 5 : 0)
+ (newFormat.getSampleSizeInBits() == format.getSampleSizeInBits() ? 5 : 0)
+ (newFormat.getChannels() == format.getChannels() ? 5 : 0)
+ (newFormat.isBigEndian() == format.isBigEndian() ? 1 : 0)
+ newFormat.getSampleRate() / 11025
+ newFormat.getChannels()
+ newFormat.getSampleSizeInBits() / 8;
if (score > bestScore) {
bestIndex = i;
bestScore = score;
}
}
}
if (bestIndex < 0) {
if (oldSampleRate < 44100) {
if (sampleRate > 44100)
break;
sampleRate *= 2;
} else {
if (sampleRate < 44100)
break;
sampleRate /= 2;
}
} else
break;
}
if (bestIndex >= 0) {
return new MultiClip(ref, AudioSystem.getAudioInputStream(formats[bestIndex], audioIn));
} else
// still couldn't find anything, try the default clip format
return new MultiClip(ref, AudioSystem.getAudioInputStream(clip.getFormat(), audioIn));
}
} catch (IOException | LineUnavailableException | RuntimeException e) {
ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e, true);
} }
return null; DataLine.Info info = new DataLine.Info(Clip.class, format);
if (AudioSystem.isLineSupported(info))
return new MultiClip(ref, audioIn);
// try to find closest matching line
Clip clip = AudioSystem.getClip();
AudioFormat[] formats = ((DataLine.Info) clip.getLineInfo()).getFormats();
int bestIndex = -1;
float bestScore = 0;
float sampleRate = format.getSampleRate();
if (sampleRate < 0)
sampleRate = clip.getFormat().getSampleRate();
float oldSampleRate = sampleRate;
while (true) {
for (int i = 0; i < formats.length; i++) {
AudioFormat curFormat = formats[i];
AudioFormat newFormat = new AudioFormat(
sampleRate, curFormat.getSampleSizeInBits(),
curFormat.getChannels(), true, curFormat.isBigEndian());
formats[i] = newFormat;
DataLine.Info newLine = new DataLine.Info(Clip.class, newFormat);
if (AudioSystem.isLineSupported(newLine) &&
AudioSystem.isConversionSupported(newFormat, format)) {
float score = 1
+ (newFormat.getSampleRate() == sampleRate ? 5 : 0)
+ (newFormat.getSampleSizeInBits() == format.getSampleSizeInBits() ? 5 : 0)
+ (newFormat.getChannels() == format.getChannels() ? 5 : 0)
+ (newFormat.isBigEndian() == format.isBigEndian() ? 1 : 0)
+ newFormat.getSampleRate() / 11025
+ newFormat.getChannels()
+ newFormat.getSampleSizeInBits() / 8;
if (score > bestScore) {
bestIndex = i;
bestScore = score;
}
}
}
if (bestIndex < 0) {
if (oldSampleRate < 44100) {
if (sampleRate > 44100)
break;
sampleRate *= 2;
} else {
if (sampleRate < 44100)
break;
sampleRate /= 2;
}
} else
break;
}
if (bestIndex >= 0)
return new MultiClip(ref, AudioSystem.getAudioInputStream(formats[bestIndex], audioIn));
// still couldn't find anything, try the default clip format
return new MultiClip(ref, AudioSystem.getAudioInputStream(clip.getFormat(), audioIn));
} }
/** /**
@ -327,7 +321,7 @@ public class SoundController {
* @param isMP3 true if MP3, false if WAV * @param isMP3 true if MP3, false if WAV
* @param listener the line listener * @param listener the line listener
* @return the MultiClip being played * @return the MultiClip being played
* @throws SlickException if any error occurred (UnsupportedAudioFileException, IOException, RuntimeException) * @throws SlickException if any error occurred
*/ */
public static synchronized MultiClip playTrack(URL url, boolean isMP3, LineListener listener) throws SlickException { public static synchronized MultiClip playTrack(URL url, boolean isMP3, LineListener listener) throws SlickException {
stopTrack(); stopTrack();
@ -336,7 +330,7 @@ public class SoundController {
currentTrack = loadClip(url.getFile(), audioIn, isMP3); currentTrack = loadClip(url.getFile(), audioIn, isMP3);
playClip(currentTrack, Options.getMusicVolume() * Options.getMasterVolume(), listener); playClip(currentTrack, Options.getMusicVolume() * Options.getMasterVolume(), listener);
return currentTrack; return currentTrack;
} catch (UnsupportedAudioFileException | IOException | RuntimeException e) { } catch (Exception e) {
throw new SlickException(String.format("Failed to load clip '%s'.", url.getFile(), e)); throw new SlickException(String.format("Failed to load clip '%s'.", url.getFile(), e));
} }
} }

View File

@ -498,7 +498,7 @@ public class DownloadsMenu extends BasicGameState {
}); });
previewID = node.getID(); previewID = node.getID();
} catch (SlickException e) { } catch (SlickException e) {
UI.sendBarNotification("Failed to load track preview."); UI.sendBarNotification("Failed to load track preview. See log for details.");
Log.error(e); Log.error(e);
} }
} }