package oop13.space.utilities;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JOptionPane;
/**
* Class used to manage and reproduce the sound effect of the game.
*
* @author Manuel Bottazzi
*/
public class AudioPlayer {
private static final String ALIEN_KILLED_PATH = "/sounds/alien_killed.wav";
private static final String BACKGROUND_PATH = "/sounds/invaders_background.wav";
private static final String MOTHERSHIP_PATH = "/sounds/mothership.wav";
private static final String SHIP_KILLED_PATH = "/sounds/ship_hitted.wav";
private static final String SHOT_PATH = "/sounds/shoot.wav";
/** The String to put in parameter of this class' methods in order to have
* the sound of a killed alien.
*/
public static final String ALIEN_KILLED_SOUND = "KilledAlien";
/** The String to put in parameter of this class' methods in order to have
* the background sound from alien movement.
*/
public static final String BACKGROUND_SOUND = "Background";
/** The String to put in parameter of this class' methods in order to have
* the sound of the MotherShip.
*/
public static final String MOTHERSHIP_SOUND = "Mothership";
/** The String to put in parameter of this class' methods in order to have
* the sound of the hit Ship.
*/
public static final String SHIP_HITTED_SOUND = "killedShip";
/** The String to put in parameter of this class' methods in order to have
* the sound of a shot.
*/
public static final String SHOT_SOUND = "Shot";
private static AudioPlayer AUDIOPLAYER = null;
private Map <String, Clip> audioSet = new HashMap<>();
/**
* Creates a new AudioPlayer.
*
* Store in a Map a Clip Object for each sound in the application.
*/
private AudioPlayer() {
audioSet.put(ALIEN_KILLED_SOUND, this.loadClip(ALIEN_KILLED_PATH));
audioSet.put(BACKGROUND_SOUND, this.loadClip(BACKGROUND_PATH));
audioSet.put(MOTHERSHIP_SOUND, this.loadClip(MOTHERSHIP_PATH));
audioSet.put(SHIP_HITTED_SOUND, this.loadClip(SHIP_KILLED_PATH));
audioSet.put(SHOT_SOUND, this.loadClip(SHOT_PATH));
}
/**
* Creates a Clip Object for a sound.
* Generates an AudioStream on the given path, loaded into a new Clip Object, returned to the caller.
*
* @param path - the path of the audio file to be loaded
* @return the Clip object related to that audio file.
*/
private Clip loadClip(String path) {
AudioInputStream audio;
Clip cl = null;
URL url = this.getClass().getResource(path);
try {
audio = AudioSystem.getAudioInputStream(url);
cl = AudioSystem.getClip();
cl.open(audio);
audio.close();
} catch (UnsupportedAudioFileException e) {
JOptionPane.showMessageDialog(null, GameStrings.AUDIO_FORMAT_ERROR, GameStrings.ERROR, JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, GameStrings.IO_ERROR, GameStrings.ERROR, JOptionPane.ERROR_MESSAGE);
} catch (LineUnavailableException e) {
JOptionPane.showMessageDialog(null, GameStrings.LINE_UNAVAILABLE_ERROR, GameStrings.ERROR, JOptionPane.ERROR_MESSAGE);
}
return cl;
}
/**
* Returns the current Singleton instance of the AudioPlayer.
* If it's the first call this create a new instance.
*
* @return the current Singleton instance of the AudioPlayer.
*/
public static AudioPlayer getAudioPlayer() {
if (AUDIOPLAYER == null) {
AUDIOPLAYER = new AudioPlayer();
}
return AUDIOPLAYER;
}
private Clip getSound(String soundName) {
return this.audioSet.get(soundName);
}
/**
* Reproduces the relative audio file continuously.
*
* @param soundName - the String relative to the clip in the Map
*/
public void playLoop(String soundName) {
Clip cl = this.getSound(soundName);
cl.loop(Clip.LOOP_CONTINUOUSLY);
}
/**
* Reproduces the relative audio file one time.
*
* @param soundName - the String relative to the clip in the Map
*/
public void playOnce(String soundName) {
Clip cl = this.getSound(soundName);
cl.setFramePosition(0);
cl.start();
}
/**
* Stops the reproduction of the relative audio file.
*
* @param soundName - the String relative to the clip in the Map
*/
public void stop(String soundName) {
Clip cl = this.getSound(soundName);
cl.stop();
}
/**
* Stops the reproduction of all the audio file.
*/
public void stopAll() {
for (Clip cl : this.audioSet.values()) {
cl.stop();
}
}
/**
* Stops the reproduction of all the audio file and close the relative clip.
*/
public void closePlayer() {
for (Clip cl : this.audioSet.values()) {
cl.stop();
cl.close();
}
}
}