Allows multiple instance of the same clip to be played simultaneously.
This might fix some issues with some sounds not being played sometimes. Also might require more memory since more clips are created.
This commit is contained in:
parent
ad5277882e
commit
fbce0391a8
|
@ -79,7 +79,7 @@ public enum HitSound implements SoundController.SoundComponent {
|
|||
private String filename;
|
||||
|
||||
/** The Clip associated with the hit sound. */
|
||||
private HashMap<SampleSet, Clip> clips;
|
||||
private HashMap<SampleSet, MultiClip> clips;
|
||||
|
||||
/** Total number of hit sounds. */
|
||||
public static final int SIZE = values().length;
|
||||
|
@ -90,7 +90,7 @@ public enum HitSound implements SoundController.SoundComponent {
|
|||
*/
|
||||
HitSound(String filename) {
|
||||
this.filename = filename;
|
||||
this.clips = new HashMap<SampleSet, Clip>();
|
||||
this.clips = new HashMap<SampleSet, MultiClip>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,7 +100,7 @@ public enum HitSound implements SoundController.SoundComponent {
|
|||
public String getFileName() { return filename; }
|
||||
|
||||
@Override
|
||||
public Clip getClip() {
|
||||
public MultiClip getClip() {
|
||||
return (currentSampleSet != null) ? clips.get(currentSampleSet) : null;
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ public enum HitSound implements SoundController.SoundComponent {
|
|||
* @param s the sample set
|
||||
* @param clip the Clip
|
||||
*/
|
||||
public void setClip(SampleSet s, Clip clip) {
|
||||
public void setClip(SampleSet s, MultiClip clip) {
|
||||
clips.put(s, clip);
|
||||
}
|
||||
|
||||
|
|
95
src/itdelatrisu/opsu/audio/MultiClip.java
Normal file
95
src/itdelatrisu/opsu/audio/MultiClip.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
package itdelatrisu.opsu.audio;
|
||||
|
||||
import itdelatrisu.opsu.ErrorHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.FloatControl;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
|
||||
//http://stackoverflow.com/questions/1854616/in-java-how-can-i-play-the-same-audio-clip-multiple-times-simultaneously
|
||||
public class MultiClip {
|
||||
/** A list of clips used for this audio sample */
|
||||
LinkedList<Clip> clips = new LinkedList<Clip>();
|
||||
|
||||
/** The format of this audio sample */
|
||||
AudioFormat format;
|
||||
|
||||
/** The data for this audio sample */
|
||||
byte[] buffer;
|
||||
|
||||
/** The name given to this clip */
|
||||
String name;
|
||||
|
||||
/** Constructor
|
||||
* @param name
|
||||
* @throws LineUnavailableException */
|
||||
public MultiClip(String name, AudioInputStream audioIn) throws IOException, LineUnavailableException {
|
||||
this.name = name;
|
||||
if(audioIn != null){
|
||||
buffer = new byte[audioIn.available()];
|
||||
int readed= 0;
|
||||
while(readed < buffer.length) {
|
||||
int read = audioIn.read(buffer, readed, buffer.length-readed);
|
||||
if(read < 0 )
|
||||
break;
|
||||
readed += read;
|
||||
}
|
||||
format = audioIn.getFormat();
|
||||
} else {
|
||||
System.out.println("Null multiclip");
|
||||
}
|
||||
getClip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the clip
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the clip with the specified volume.
|
||||
* @param volume the volume the play at
|
||||
* @throws IOException
|
||||
* @throws LineUnavailableException
|
||||
*/
|
||||
public void start(float volume) throws LineUnavailableException, IOException {
|
||||
Clip clip = getClip();
|
||||
|
||||
// PulseAudio does not support Master Gain
|
||||
if (clip.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
|
||||
// set volume
|
||||
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
|
||||
float dB = (float) (Math.log(volume) / Math.log(10.0) * 20.0);
|
||||
gainControl.setValue(dB);
|
||||
}
|
||||
|
||||
clip.setFramePosition(0);
|
||||
clip.start();
|
||||
}
|
||||
/**
|
||||
* Returns a Clip that is not playing from the list
|
||||
* if one is not available a new one is created
|
||||
* @return the Clip
|
||||
*/
|
||||
private Clip getClip() throws LineUnavailableException, IOException{
|
||||
for(Clip c : clips){
|
||||
if(!c.isRunning()){
|
||||
return c;
|
||||
}
|
||||
}
|
||||
Clip t = AudioSystem.getClip();
|
||||
if (format != null)
|
||||
t.open(format, buffer, 0, buffer.length);
|
||||
clips.add(t);
|
||||
return t;
|
||||
}
|
||||
}
|
|
@ -33,7 +33,6 @@ import javax.sound.sampled.AudioInputStream;
|
|||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.Clip;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.FloatControl;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
|
@ -50,7 +49,7 @@ public class SoundController {
|
|||
* Returns the Clip associated with the sound component.
|
||||
* @return the Clip
|
||||
*/
|
||||
public Clip getClip();
|
||||
public MultiClip getClip();
|
||||
}
|
||||
|
||||
/** Sample volume multiplier, from timing points [0, 1]. */
|
||||
|
@ -71,7 +70,7 @@ public class SoundController {
|
|||
* @param isMP3 true if MP3, false if WAV
|
||||
* @return the loaded and opened clip
|
||||
*/
|
||||
private static Clip loadClip(String ref, boolean isMP3) {
|
||||
private static MultiClip loadClip(String ref, boolean isMP3) {
|
||||
try {
|
||||
URL url = ResourceLoader.getResource(ref);
|
||||
|
||||
|
@ -79,7 +78,7 @@ public class SoundController {
|
|||
InputStream in = url.openStream();
|
||||
if (in.available() == 0) {
|
||||
in.close();
|
||||
return AudioSystem.getClip();
|
||||
return new MultiClip(ref, null);
|
||||
}
|
||||
in.close();
|
||||
|
||||
|
@ -88,6 +87,9 @@ public class SoundController {
|
|||
// GNU/Linux workaround
|
||||
// Clip clip = AudioSystem.getClip();
|
||||
AudioFormat format = audioIn.getFormat();
|
||||
|
||||
//TODO Is this really needed? since the code below will find out the format isn't supported
|
||||
// and will pretty much do the same thing I think. -fluddokt
|
||||
if (isMP3) {
|
||||
AudioFormat decodedFormat = new AudioFormat(
|
||||
AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16,
|
||||
|
@ -97,12 +99,10 @@ public class SoundController {
|
|||
audioIn = decodedAudioIn;
|
||||
}
|
||||
DataLine.Info info = new DataLine.Info(Clip.class, format);
|
||||
if (AudioSystem.isLineSupported(info)) {
|
||||
Clip clip = (Clip) AudioSystem.getLine(info);
|
||||
clip.open(audioIn);
|
||||
return clip;
|
||||
} else {
|
||||
// try to find closest matching line
|
||||
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;
|
||||
|
@ -149,11 +149,10 @@ public class SoundController {
|
|||
break;
|
||||
}
|
||||
if (bestIndex >= 0) {
|
||||
clip.open(AudioSystem.getAudioInputStream(formats[bestIndex], audioIn));
|
||||
return new MultiClip(ref, AudioSystem.getAudioInputStream(formats[bestIndex], audioIn));
|
||||
} else
|
||||
// still couldn't find anything, try the default clip format
|
||||
clip.open(AudioSystem.getAudioInputStream(clip.getFormat(), audioIn));
|
||||
return clip;
|
||||
return new MultiClip(ref, AudioSystem.getAudioInputStream(clip.getFormat(), audioIn));
|
||||
}
|
||||
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException | RuntimeException e) {
|
||||
ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e, true);
|
||||
|
@ -231,28 +230,16 @@ public class SoundController {
|
|||
* @param clip the Clip to play
|
||||
* @param volume the volume [0, 1]
|
||||
*/
|
||||
private static void playClip(Clip clip, float volume) {
|
||||
private static void playClip(MultiClip clip, float volume) {
|
||||
if (clip == null) // clip failed to load properly
|
||||
return;
|
||||
|
||||
if (volume > 0f) {
|
||||
// stop clip if running
|
||||
if (clip.isRunning()) {
|
||||
clip.stop();
|
||||
clip.flush();
|
||||
try {
|
||||
clip.start(volume);
|
||||
} catch (LineUnavailableException | IOException e) {
|
||||
ErrorHandler.error(String.format("Could not start a clip '%s'.", clip.getName()), e, true);
|
||||
}
|
||||
|
||||
// PulseAudio does not support Master Gain
|
||||
if (clip.isControlSupported(FloatControl.Type.MASTER_GAIN)) {
|
||||
// set volume
|
||||
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
|
||||
float dB = (float) (Math.log(volume) / Math.log(10.0) * 20.0);
|
||||
gainControl.setValue(dB);
|
||||
}
|
||||
|
||||
// play clip
|
||||
clip.setFramePosition(0);
|
||||
clip.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ public enum SoundEffect implements SoundController.SoundComponent {
|
|||
private String filename;
|
||||
|
||||
/** The Clip associated with the sound effect. */
|
||||
private Clip clip;
|
||||
private MultiClip clip;
|
||||
|
||||
/** Total number of sound effects. */
|
||||
public static final int SIZE = values().length;
|
||||
|
@ -67,11 +67,11 @@ public enum SoundEffect implements SoundController.SoundComponent {
|
|||
public String getFileName() { return filename; }
|
||||
|
||||
@Override
|
||||
public Clip getClip() { return clip; }
|
||||
public MultiClip getClip() { return clip; }
|
||||
|
||||
/**
|
||||
* Sets the Clip for the sound.
|
||||
* @param clip the clip
|
||||
*/
|
||||
public void setClip(Clip clip) { this.clip = clip; }
|
||||
public void setClip(MultiClip clip) { this.clip = clip; }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user