/*
* This file is part of jSpaceWar.
*
* jSpaceWar is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* jSpaceWar is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with jSpaceWar. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mlarktar.spacewar;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
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.sound.sampled.DataLine.Info;
/**
* @author malar
*
* This class is responsible for playing sounds. It will be given to Ship objects
* so they can generate sound events.
*
* The old API is used here.
*/
public class SoundEvents implements MetaEventListener {
public static final String MISILE = "Misile";
public static final String LASER = "Laser";
public static final String HYPER = "Hyper";
public static final String AMB_DEF = "Ambient";
public static final String AMB_FIN = "Panic";
public static final String AMB_SUM = "Summary";
public static final String BOUNCE = "Bounce";
public static final String DETONATE = "Detonate";
public static final String TENK = "Tenk";
public static final String AMB_ABT = "About";
private Map soundEvents;
private Object looping;
private Sequencer sequencer;
public SoundEvents() {
soundEvents = new HashMap();
try {
sequencer = MidiSystem.getSequencer();
sequencer.addMetaEventListener(this);
sequencer.open();
} catch (MidiUnavailableException e) {
sequencer = null;
}
}
/** Plays the event loaded by loadClip() if available
* @see loadClip()
*/
public void playEvent(String event) {
if (soundEvents.containsKey(event)) {
Object sound = soundEvents.get(event);
if (sound instanceof Clip) {
Clip clip = (Clip) sound;
clip.setFramePosition(0);
clip.start();
} else if (sequencer != null && sound instanceof Sequence) {
Sequence sequence = (Sequence) sound;
try {
sequencer.setSequence(sequence);
sequencer.start();
} catch (InvalidMidiDataException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
}
public void loopEvent(String event) {
if (soundEvents.containsKey(event)) {
Object sound = soundEvents.get(event);
if (sound instanceof Clip) {
Clip clip = (Clip) sound;
clip.setFramePosition(0);
clip.loop(Clip.LOOP_CONTINUOUSLY);
clip.start();
looping = clip;
} else if (sequencer != null && sound instanceof Sequence) {
playEvent(event);
looping = sound;
}
}
}
public void stopLooping() {
if (looping != null) {
if (looping instanceof Clip) {
Clip clip = (Clip) looping;
clip.stop();
} else if (sequencer != null && looping instanceof Sequence) {
sequencer.stop();
}
looping = null;
}
}
/** Loads a clip on a diferent thread */
public void loadClip(URL clipURL, String destination) {
try {
loadClip(clipURL.openStream(), destination);
} catch (IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
}
public void loadClip(InputStream clipStream, String destination) {
Object currentSound = null;
try {
// is it sound file like .wav
currentSound = AudioSystem.getAudioInputStream(clipStream);
} catch (UnsupportedAudioFileException e) {
// is it a sequenced file like .mid
try {
currentSound = MidiSystem.getSequence(clipStream);
} catch (InvalidMidiDataException em) {
// file type not supported!
} catch (IOException em) {
System.err.println(e.getMessage());
e.printStackTrace();
}
} catch (IOException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
if (currentSound != null) {
if (currentSound instanceof AudioInputStream) {
try {
Clip clip = (Clip) AudioSystem.getLine(new Info(Clip.class, ((AudioInputStream) currentSound).getFormat()));
clip.open((AudioInputStream) currentSound);
soundEvents.put(destination, clip);
} catch (LineUnavailableException e1) {
// This will happen if the underlying platform does not support sound
// System.err.println(e1.getMessage());
// e1.printStackTrace();
} catch (IOException e1) {
System.err.println(e1.getMessage());
e1.printStackTrace();
}
} else if (currentSound instanceof Sequence) { // Sequence
soundEvents.put(destination, currentSound);
}
}
}
/* receives midi message 47 (Sequence ended) and if looping is on then
* restarts the sequence. Only if the looping request is on a midi.
* @see javax.sound.midi.MetaEventListener#meta(javax.sound.midi.MetaMessage)
*/
public void meta(MetaMessage meta) {
// 47 = Sequence Ended. See midi doc
if (meta.getType() == 47) {
if (looping == sequencer.getSequence()) {
sequencer.start();
}
}
}
public boolean isLooping() {
return (looping != null);
}
}