package org.ripple.power.sound;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import org.ripple.power.collection.ArrayByte;
import org.ripple.power.ui.UIRes;
public class LMidiSound implements MetaEventListener, Sound {
private static final int MIDI_EOT_MESSAGE = 47;
private static final int GAIN_CONTROLLER = 7;
private int volume;
private Sequencer sequencer;
private static boolean available;
private static boolean volumeSupported;
private static final int UNINITIALIZED = 0;
private static final int INITIALIZING = 1;
private static final int INITIALIZED = 2;
private static int rendererStatus = UNINITIALIZED;
private ArrayByte bytes;
public LMidiSound() {
if (rendererStatus == UNINITIALIZED) {
rendererStatus = INITIALIZING;
Thread thread = new Thread() {
public final void run() {
try {
Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
volumeSupported = (sequencer instanceof Synthesizer);
sequencer.close();
available = true;
} catch (Throwable e) {
available = false;
}
rendererStatus = INITIALIZED;
}
};
thread.setDaemon(true);
thread.start();
}
}
public LMidiSound(String fileName) throws IOException {
bytes = new ArrayByte(UIRes.getStream(fileName), ArrayByte.BIG_ENDIAN);
if (rendererStatus == UNINITIALIZED) {
rendererStatus = INITIALIZING;
Thread thread = new Thread() {
public final void run() {
try {
Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
volumeSupported = (sequencer instanceof Synthesizer);
sequencer.close();
available = true;
} catch (Throwable e) {
available = false;
}
rendererStatus = INITIALIZED;
}
};
thread.setDaemon(true);
thread.start();
}
}
public boolean isAvailable() {
if (rendererStatus != INITIALIZED) {
int i = 0;
while (rendererStatus != INITIALIZED && i++ < 50) {
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
}
}
if (rendererStatus != INITIALIZED) {
rendererStatus = INITIALIZED;
available = false;
}
}
return available;
}
public void playSound(String fileName) {
try {
playSound(UIRes.getStream(fileName));
} catch (IOException e) {
e.printStackTrace();
}
}
public void playSound() {
playSound(new ByteArrayInputStream(bytes.getData()));
}
public void playSound(InputStream in) {
try {
System.setProperty("javax.sound.midi.Sequencer",
"com.sun.media.sound.RealTimeSequencerProvider");
if (this.sequencer == null) {
this.sequencer = MidiSystem.getSequencer();
if (!this.sequencer.isOpen()) {
this.sequencer.open();
}
}
Sequence seq = MidiSystem.getSequence(in);
this.sequencer.setSequence(seq);
this.sequencer.start();
this.sequencer.addMetaEventListener(this);
if (this.volume != 1) {
this.setSoundVolume(this.volume);
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected void replaySound(URL audiofile) {
this.sequencer.start();
this.sequencer.addMetaEventListener(this);
}
public void stopSound() {
this.sequencer.stop();
this.sequencer.setMicrosecondPosition(0);
this.sequencer.removeMetaEventListener(this);
}
public void meta(MetaMessage msg) {
if (msg.getType() == MIDI_EOT_MESSAGE) {
this.sequencer.setMicrosecondPosition(0);
this.sequencer.removeMetaEventListener(this);
}
}
public void setSoundVolume(int volume) {
if (this.sequencer == null) {
return;
}
if (volumeSupported) {
MidiChannel[] channels = ((Synthesizer) this.sequencer)
.getChannels();
for (int i = 0; i < channels.length; i++) {
channels[i].controlChange(GAIN_CONTROLLER, volume);
}
}
}
public boolean isVolumeSupported() {
return volumeSupported;
}
}