From 1953e5686c08a04544999d2112e7df279039c73e Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Fri, 22 Nov 2002 04:23:31 +0000 Subject: [PATCH] genericized music playing, made transitioning from any music type to any other clean and good. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1983 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../threerings/media/sound/MidiPlayer.java | 168 +++++++ .../com/threerings/media/sound/ModPlayer.java | 63 +-- .../{MP3Manager.java => sound/Mp3Player.java} | 44 +- .../threerings/media/sound/MusicPlayer.java | 72 +++ .../threerings/media/sound/SoundManager.java | 449 +++++------------- 5 files changed, 415 insertions(+), 381 deletions(-) create mode 100644 src/java/com/threerings/media/sound/MidiPlayer.java rename src/java/com/threerings/media/{MP3Manager.java => sound/Mp3Player.java} (78%) create mode 100644 src/java/com/threerings/media/sound/MusicPlayer.java diff --git a/src/java/com/threerings/media/sound/MidiPlayer.java b/src/java/com/threerings/media/sound/MidiPlayer.java new file mode 100644 index 000000000..900f03f20 --- /dev/null +++ b/src/java/com/threerings/media/sound/MidiPlayer.java @@ -0,0 +1,168 @@ +// +// $Id: MidiPlayer.java,v 1.1 2002/11/22 04:23:31 ray Exp $ + +package com.threerings.media; + +import java.io.BufferedInputStream; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Synthesizer; + +/** + * Does something extraordinary. + */ +public class MidiPlayer extends MusicPlayer + implements MetaEventListener +{ + // documentation inherited + public void init () + { + try { + Sequencer seq = MidiSystem.getSequencer(); + seq.open(); + if (seq instanceof Synthesizer) { + _channels = ((Synthesizer) seq).getChannels(); + //updateMusicVolume(); + } + _sequencer = seq; + + } catch (MidiUnavailableException mue) { + Log.warning("Midi unavailable! [e=" + mue + "]."); + } + } + + // documentation inherited + public void shutdown () + { + _sequencer.close(); + } + + // documentation inherited + public void start (String set, String path) + throws Exception + { + _sequencer.setSequence( + new BufferedInputStream(_rmgr.getResource(set, path))); + _sequencer.start(); + _sequencer.addMetaEventListener(this); + } + + // documentation inherited + public void stop () + { + _sequencer.removeMetaEventListener(this); + _sequencer.stop(); + } + + // documentation inherited + public void setVolume (float volume) + { + if (_channels != null) { + int setting = (int) (volume * 127.0); + for (int ii=0; ii < _channels.length; ii++) { + _channels[ii].controlChange(VOLUME_CONTROL, setting); + } + } + } + + // documentation inherited from interface MetaEventListener + public void meta (MetaMessage msg) + { + if (msg.getType() == END_OF_TRACK) { + _musicListener.musicStopped(); + } + } + +// STUFF FROM ANOTHER TIME +// /** +// * Get a list of alternate midi devices. +// */ +// public MidiDevice.Info[] getAlternateMidiDevices () +// { +// ArrayList infos = new ArrayList(); +// CollectionUtil.addAll(infos, MidiSystem.getMidiDeviceInfo()); +// +// // remove the synth/seqs, leaving only hardware midi thingies +// for (Iterator iter=infos.iterator(); iter.hasNext(); ) { +// try { +// MidiDevice dev = MidiSystem.getMidiDevice( +// (MidiDevice.Info) iter.next()); +// if ((dev instanceof Sequencer) || +// (dev instanceof Synthesizer)) { +// iter.remove(); +// } +// } catch (MidiUnavailableException mue) { +// iter.remove(); +// } +// } +// +// return (MidiDevice.Info[]) infos.toArray( +// new MidiDevice.Info[infos.size()]); +// } +// +// /** +// * Attempt to use the alternate midi device for output. +// * Return true if we're using it. +// */ +// public boolean useAlternateDevice (MidiDevice.Info devinfo) +// { +// Log.info("Trying alternate device: " + devinfo); +// try { +// MidiDevice dev = MidiSystem.getMidiDevice(devinfo); +// Receiver rec = dev.getReceiver(); +// if (rec == null) { +// Log.info("Got no device!"); +// return false; +// } +// _stoppingSong = true; +// _sequencer.stop(); +// _sequencer.close(); +// +// Receiver old = _sequencer.getTransmitter().getReceiver(); +// Log.info("Old receiver: " + old); +// if (old != null) { +// old.close(); +// } +// _sequencer.open(); +// +// // THIS DOESN'T WORK. +// // See bug #4347135, specifically notes on the bottom. +// _sequencer.getTransmitter().setReceiver(rec); +// playTopSong(); +// +// // possibly shut down an old receiver +// if (_receiver != null) { +// _receiver.close(); +// } +// // set the new receiver +// _receiver = rec; +// +// return true; +// +// } catch (MidiUnavailableException mue) { +// Log.warning("Use of alternate device failed [e=" + mue + +// ", device=" + devinfo + "]."); +// return false; +// } +// } + + /** This is apparently the midi code for end of track. Wack. */ + protected static final int END_OF_TRACK = 47; + + /** The midi control for volume is 7. Ooooooo. */ + protected static final int VOLUME_CONTROL = 7; + + /** The sequencer. */ + protected Sequencer _sequencer; + + /** The channels in the sequencer, which we'll use to fuxor volumes. */ + protected MidiChannel[] _channels; +} diff --git a/src/java/com/threerings/media/sound/ModPlayer.java b/src/java/com/threerings/media/sound/ModPlayer.java index c01b46822..91c0f9721 100644 --- a/src/java/com/threerings/media/sound/ModPlayer.java +++ b/src/java/com/threerings/media/sound/ModPlayer.java @@ -1,5 +1,5 @@ // -// $Id: ModPlayer.java,v 1.2 2002/11/20 23:06:33 ray Exp $ +// $Id: ModPlayer.java,v 1.3 2002/11/22 04:23:31 ray Exp $ package com.threerings.media; @@ -20,36 +20,32 @@ import com.threerings.resource.ResourceManager; /** * Does something extraordinary. */ -public class ModPlayer +public class ModPlayer extends MusicPlayer { - public ModPlayer (ResourceManager rmgr, SoundManager smgr) + // documentation inherited + public void init () { - _rmgr = rmgr; - _smgr = smgr; - try { _device = new NaryaSoundDevice(); + _device.start(); } catch (OutputDeviceException ode) { Log.warning("Unable to allocate sound channel for mod playing " + "[e=" + ode + "]."); } } - public void stop () + // documentation inherited + public void shutdown () { - _player = null; + _device.stop(); } + // documentation inherited public void start (String set, String path) + throws Exception { - Module module = null; - try { - module = ModuleLoader.read( - new DataInputStream(_rmgr.getResource(set, path))); - } catch (IOException ioe) { - Log.warning("error loading oh shit oh shit: [e=" + ioe + "]."); - return; - } + Module module = ModuleLoader.read( + new DataInputStream(_rmgr.getResource(set, path))); final MicroMod mod = new MicroMod( module, _device, new LinearResampler()); @@ -57,9 +53,7 @@ public class ModPlayer _player = new Thread("narya mod player") { public void run () { - _device.start(); - while ((_player == Thread.currentThread()) && - (mod.getSequenceLoopCount() == 0)) { + while (mod.getSequenceLoopCount() == 0) { mod.doRealTimePlayback(); try { @@ -67,9 +61,14 @@ public class ModPlayer } catch (InterruptedException ie) { // WFCares } + + if (_player != Thread.currentThread()) { + // we were stopped! + return; + } } - _device.stop(); - _smgr.songStopEvent(); + _device.drain(); + _musicListener.musicStopped(); } }; @@ -77,10 +76,13 @@ public class ModPlayer _player.start(); } - /** - * Set the volume of the midiplayer. - * @param vol 0f - 1f (inclusive). - */ + // documentation inherited + public void stop () + { + _player = null; + } + + // documentation inherited public void setVolume (float vol) { _device.setVolume(vol); @@ -105,11 +107,16 @@ public class ModPlayer { SoundManager.adjustVolume(sourceDataLine, vol); } + + /** + * Access the drain method of the line. + */ + public void drain () + { + sourceDataLine.drain(); + } } protected Thread _player; protected NaryaSoundDevice _device; - - protected ResourceManager _rmgr; - protected SoundManager _smgr; } diff --git a/src/java/com/threerings/media/MP3Manager.java b/src/java/com/threerings/media/sound/Mp3Player.java similarity index 78% rename from src/java/com/threerings/media/MP3Manager.java rename to src/java/com/threerings/media/sound/Mp3Player.java index fee9c592f..2c4db0d22 100644 --- a/src/java/com/threerings/media/MP3Manager.java +++ b/src/java/com/threerings/media/sound/Mp3Player.java @@ -1,5 +1,5 @@ // -// $Id: MP3Manager.java,v 1.2 2002/11/20 04:03:09 ray Exp $ +// $Id: Mp3Player.java,v 1.1 2002/11/22 04:23:31 ray Exp $ package com.threerings.media; @@ -24,21 +24,24 @@ import com.threerings.resource.ResourceManager; /** * Does something extraordinary. */ -public class MP3Manager +public class Mp3Player extends MusicPlayer { - public MP3Manager (ResourceManager rmgr, SoundManager smgr) + // documentation inherited + public void init () { - _rmgr = rmgr; - _smgr = smgr; } - public void stop () + // documentation inherited + public void shutdown () { - _player = null; } + // documentation inherited public void start (final String set, final String path) + throws Exception { + // TODO: some stuff needs to come out of here and into init/shutdown + // but we'll deal with all that later, d00d. _player = new Thread("narya mp3 relay") { public void run () { AudioInputStream inStream = null; @@ -79,7 +82,7 @@ public class MP3Manager byte[] data = new byte[BUFFER_SIZE]; int count = 0; - while (_player == Thread.currentThread()) { + while (count >= 0) { try { count = inStream.read(data, 0, data.length); } catch (IOException ioe) { @@ -88,13 +91,15 @@ public class MP3Manager } if (count >= 0) { line.write(data, 0, count); - } else { - break; + } + if (_player != Thread.currentThread()) { + return; } } + line.drain(); line.close(); - _smgr.songStopEvent(); + _musicListener.musicStopped(); } }; @@ -103,10 +108,19 @@ public class MP3Manager _player.start(); } + // documentation inherited + public void stop () + { + _player = null; + } + + // documentation inherited + public void setVolume (float volume) + { + // TODO + } + protected Thread _player; - protected ResourceManager _rmgr; - protected SoundManager _smgr; - - protected static final int BUFFER_SIZE = 128000; + protected static final int BUFFER_SIZE = 8192; } diff --git a/src/java/com/threerings/media/sound/MusicPlayer.java b/src/java/com/threerings/media/sound/MusicPlayer.java new file mode 100644 index 000000000..81f0a9cd8 --- /dev/null +++ b/src/java/com/threerings/media/sound/MusicPlayer.java @@ -0,0 +1,72 @@ +// +// $Id: MusicPlayer.java,v 1.1 2002/11/22 04:23:31 ray Exp $ + +package com.threerings.media; + +import com.threerings.resource.ResourceManager; + +/** + * Does something extraordinary. + */ +public abstract class MusicPlayer +{ + /** + */ + public interface MusicEventListener + { + /** + * A callback that all players should use when the song they are + * playing has finished playing (completely). + */ + public void musicStopped(); + } + + /** + */ + public final void init ( + ResourceManager rmgr, MusicEventListener musicListener) + { + _rmgr = rmgr; + _musicListener = musicListener; + + init(); + } + + /** + * Do your init here. + */ + public void init () + { + } + + /** + * Shutdown and free all resources. + */ + public void shutdown () + { + } + + /** + * Start playing the specified song. + */ + public abstract void start (String set, String path) + throws Exception; + + /** + * Stop playing the specified song. + */ + public abstract void stop (); + + /** + * Set the volume. + * + * @param volume 0f - 1f, inclusive. + */ + public abstract void setVolume (float volume); + + /** The place we load data from. */ + protected ResourceManager _rmgr; + + /** Tell this guy about it when a song stops. */ + protected MusicEventListener _musicListener; +} diff --git a/src/java/com/threerings/media/sound/SoundManager.java b/src/java/com/threerings/media/sound/SoundManager.java index 3dd59d2c7..07b35860a 100644 --- a/src/java/com/threerings/media/sound/SoundManager.java +++ b/src/java/com/threerings/media/sound/SoundManager.java @@ -1,5 +1,5 @@ // -// $Id: SoundManager.java,v 1.23 2002/11/20 23:06:33 ray Exp $ +// $Id: SoundManager.java,v 1.24 2002/11/22 04:23:31 ray Exp $ package com.threerings.media; @@ -16,17 +16,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; -import javax.sound.midi.InvalidMidiDataException; -import javax.sound.midi.MetaEventListener; -import javax.sound.midi.MetaMessage; -import javax.sound.midi.MidiChannel; -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.Receiver; -import javax.sound.midi.Sequencer; -import javax.sound.midi.Synthesizer; - import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; @@ -64,7 +53,7 @@ import com.threerings.media.Log; // -- CLEANUP is NEEDED (lots of references to Sequences, when we're now // playing mods and mp3s as well. ) public class SoundManager - implements MetaEventListener + implements MusicPlayer.MusicEventListener { /** * Create instances of this for your application to differentiate @@ -109,7 +98,7 @@ public class SoundManager public void run () { Object command = null; SoundKey key = null; - MidiInfo midiInfo = null; + MusicInfo musicInfo = null; while (amRunning()) { try { @@ -126,7 +115,7 @@ public class SoundManager key = (SoundKey) _queue.get(); } else if (PLAYMUSIC == command) { - midiInfo = (MidiInfo) _queue.get(); + musicInfo = (MusicInfo) _queue.get(); } } @@ -135,10 +124,10 @@ public class SoundManager playSound(key); } else if (PLAYMUSIC == command) { - playSequence(midiInfo); + playMusic(musicInfo); } else if (STOPMUSIC == command) { - stopSequence(key); + stopMusic(key); } else if (LOCK == command) { _clipCache.lock(key); @@ -159,7 +148,7 @@ public class SoundManager } else if (DIE == command) { _resourceFreer.stop(); flushResources(true); - shutdownMidi(); + shutdownMusic(); } } catch (Exception e) { Log.warning("Captured exception in SoundManager loop."); @@ -320,7 +309,7 @@ public class SoundManager { synchronized (_queue) { _queue.append(PLAYMUSIC); - _queue.append(new MidiInfo(set, path, numloops)); + _queue.append(new MusicInfo(set, path, numloops)); } } @@ -336,78 +325,6 @@ public class SoundManager } } - /** - * Get a list of alternate midi devices. - */ - public MidiDevice.Info[] getAlternateMidiDevices () - { - ArrayList infos = new ArrayList(); - CollectionUtil.addAll(infos, MidiSystem.getMidiDeviceInfo()); - - // remove the synth/seqs, leaving only hardware midi thingies - for (Iterator iter=infos.iterator(); iter.hasNext(); ) { - try { - MidiDevice dev = MidiSystem.getMidiDevice( - (MidiDevice.Info) iter.next()); - if ((dev instanceof Sequencer) || - (dev instanceof Synthesizer)) { - iter.remove(); - } - } catch (MidiUnavailableException mue) { - iter.remove(); - } - } - - return (MidiDevice.Info[]) infos.toArray( - new MidiDevice.Info[infos.size()]); - } - - /** - * Attempt to use the alternate midi device for output. - * Return true if we're using it. - */ - public boolean useAlternateDevice (MidiDevice.Info devinfo) - { - Log.info("Trying alternate device: " + devinfo); - try { - MidiDevice dev = MidiSystem.getMidiDevice(devinfo); - Receiver rec = dev.getReceiver(); - if (rec == null) { - Log.info("Got no device!"); - return false; - } - _stoppingSong = true; - _sequencer.stop(); - _sequencer.close(); - - Receiver old = _sequencer.getTransmitter().getReceiver(); - Log.info("Old receiver: " + old); - if (old != null) { - old.close(); - } - _sequencer.open(); - - // THIS DOESN'T WORK. - // See bug #4347135, specifically notes on the bottom. - _sequencer.getTransmitter().setReceiver(rec); - playTopSong(); - - // possibly shut down an old receiver - if (_receiver != null) { - _receiver.close(); - } - // set the new receiver - _receiver = rec; - - return true; - - } catch (MidiUnavailableException mue) { - Log.warning("Use of alternate device failed [e=" + mue + - ", device=" + devinfo + "]."); - return false; - } - } - /** * On the SoundManager thread, * plays the sound file with the given pathname. @@ -468,88 +385,107 @@ public class SoundManager } /** - * Play a sequence from the specified path. + * Play a song from the specified path. */ - protected void playSequence (MidiInfo info) + protected void playMusic (MusicInfo info) { - if (_sequencer == null) { - initMidi(); + Log.info("Playing: " + info); + // stop whatever's currently playing + if (_musicPlayer != null) { + _musicPlayer.stop(); + handleMusicStopped(); } - stopCurrentSong(false); - _midiStack.addFirst(info); - playTopSong(); + // add the new song + _musicStack.addFirst(info); + + // and play it + playTopMusic(); } /** * Start the specified sequence. */ - protected void playTopSong () + protected void playTopMusic () { - if (_midiStack.isEmpty()) { + if (_musicStack.isEmpty()) { return; } - MidiInfo info = (MidiInfo) _midiStack.getFirst(); + MusicInfo info = (MusicInfo) _musicStack.getFirst(); + Class playerClass = getMusicPlayerClass(info.path); - // start the new one - try { - if (info.path.endsWith(".mp3")) { - _mp3player.start(info.set, info.path); - - } else if (info.path.endsWith(".mod")) { - _modplayer.start(info.set, info.path); - - } else { - _sequencer.setSequence(getMidiData(info)); - if (info.msPosition != -1) { - // TODO: this doesn't work correctly - _sequencer.setTickPosition(info.tickPosition); - _sequencer.setMicrosecondPosition(info.msPosition); - info.msPosition = -1; - } - _sequencer.start(); - //updateMusicVolume(); - //Log.info("Now playing : " + info.path); + // shutdown the old player if we're switching music types + if (! playerClass.isInstance(_musicPlayer)) { + if (_musicPlayer != null) { + _musicPlayer.shutdown(); } - } catch (InvalidMidiDataException imda) { - Log.warning("Invalid midi data, not playing [path=" + - info.path + "]."); + // set up the new player + try { + _musicPlayer = (MusicPlayer) playerClass.newInstance(); + } catch (Exception e) { + Log.warning("Unable to instantiate music player [class=" + + playerClass + "]."); - } catch (IOException ioe) { - Log.warning("ioe=" + ioe); + // scrap it, try again with the next song + _musicPlayer = null; + _musicStack.removeFirst(); + playTopMusic(); + return; + } + + _musicPlayer.init(_rmgr, this); + _musicPlayer.setVolume(_musicVol); + } + + // play! + try { + _musicPlayer.start(info.set, info.path); + } catch (Exception e) { + Log.warning("Error playing music, skipping [e=" + e + + ", set=" + info.set + ", path=" + info.path + "]."); + _musicStack.removeFirst(); + playTopMusic(); + return; + } + } + + /** + * Get the appropriate music player for the specified music file. + */ + protected static Class getMusicPlayerClass (String path) + { + path = path.toLowerCase(); + + if (path.endsWith(".mid") || path.endsWith(".rmf")) { + return MidiPlayer.class; + + } else if (path.endsWith(".mod")) { + return ModPlayer.class; + + } else if (path.endsWith(".mp3")) { + return Mp3Player.class; + + } else { + return null; } } /** * Stop whatever song is currently playing and deal with the - * MidiInfo associated with it. + * MusicInfo associated with it. */ - protected void stopCurrentSong (boolean wasStopped) + protected void handleMusicStopped () { - if (_midiStack.isEmpty()) { + if (_musicStack.isEmpty()) { return; } // see what was playing - MidiInfo current = (MidiInfo) _midiStack.getFirst(); - - // stop the existing song - if (!wasStopped) { - // TODO: fade? - _stoppingSong = true; - if (current.path.endsWith(".mp3")) { - _mp3player.stop(); - - } else if (current.path.endsWith(".mod")) { - _modplayer.stop(); - - } else { - _sequencer.stop(); - } - } + MusicInfo current = (MusicInfo) _musicStack.getFirst(); + // see how many times the song was to loop and act accordingly switch (current.loops) { default: current.loops--; @@ -557,15 +493,7 @@ public class SoundManager case 1: // sorry charlie - _midiStack.removeFirst(); - break; - - case -1: - // save info... - // TODO: this doesn't seem to work, and is out-n-out broken - // if we use the tickPos - current.msPosition = _sequencer.getMicrosecondPosition(); - current.tickPosition = _sequencer.getTickPosition(); + _musicStack.removeFirst(); break; } } @@ -573,34 +501,27 @@ public class SoundManager /** * Stop the sequence at the specified path. */ - protected void stopSequence (SoundKey key) + protected void stopMusic (SoundKey key) { - if (! _midiStack.isEmpty()) { - MidiInfo current = (MidiInfo) _midiStack.getFirst(); + Log.info("Stopping: " + key); + if (! _musicStack.isEmpty()) { + MusicInfo current = (MusicInfo) _musicStack.getFirst(); // if we're currently playing this song.. if (key.equals(current)) { + Log.info("is top song!"); // stop it - _stoppingSong = true; - if (key.path.endsWith(".mp3")) { - _mp3player.stop(); - - } else if (key.path.endsWith(".mod")) { - _modplayer.stop(); - - } else { - _sequencer.stop(); - } + _musicPlayer.stop(); // remove it from the stack - _midiStack.removeFirst(); + _musicStack.removeFirst(); // start playing the next.. - playTopSong(); + playTopMusic(); } else { // we aren't currently playing this song. Simply remove. - for (Iterator iter=_midiStack.iterator(); iter.hasNext(); ) { + for (Iterator iter=_musicStack.iterator(); iter.hasNext(); ) { if (key.equals(iter.next())) { iter.remove(); return; @@ -614,119 +535,28 @@ public class SoundManager "[key=" + key + "]."); } - /** - * Initialize the midi system. - */ - protected void initMidi () - { - _mp3player = new MP3Manager(_rmgr, this); - _modplayer = new ModPlayer(_rmgr, this); - _modplayer.setVolume(_musicVol); - - try { - Sequencer seq = MidiSystem.getSequencer(); -// Sequencer seq = getTritonusSequencer(); - seq.open(); - if (seq instanceof Synthesizer) { - _midiChannels = ((Synthesizer) seq).getChannels(); - //updateMusicVolume(); - } - _sequencer = seq; - _sequencer.addMetaEventListener(this); - - Log.info("Seq class: " + _sequencer.getClass()); - -// _sequencer.getTransmitter().setReceiver(new Receiver() { -// public void close () -// { -// } -// -// public void send (javax.sound.midi.MidiMessage msg, long stamp) -// { -// Log.info("msg : " + msg); -// } -// }); - - } catch (MidiUnavailableException mue) { - Log.warning("Midi unavailable. Can't play music."); - return; - } - } - - protected Sequencer getTritonusSequencer () - throws MidiUnavailableException - { - MidiDevice.Info[] info = MidiSystem.getMidiDeviceInfo(); - for (int ii=0; ii < info.length; ii++) { - if (info[ii].toString().indexOf("Tritonus") != -1) { - MidiDevice dev = MidiSystem.getMidiDevice(info[ii]); - if (dev instanceof Sequencer) { - return (Sequencer) dev; - } - } - } - - Log.info("ACK SPUTTER!"); - return MidiSystem.getSequencer(); - } - - /** - * Stop playing and shutdown the midi system. - */ - protected void shutdownMidi () - { - _sequencer.removeMetaEventListener(this); - stopCurrentSong(false); - _sequencer.close(); - if (_receiver != null) { - _receiver.close(); - } - _sequencer = null; - _midiChannels = null; - _midiStack.clear(); - } - /** * Attempt to modify the music volume for any playing tracks. */ protected void updateMusicVolume () { - if (_modplayer != null) { - _modplayer.setVolume(_musicVol); - } - - if (_midiChannels == null) { - Log.warning("Cannot modify music volume!"); - - } else { - int setting = (int) (_musicVol * 127.0); - for (int ii=0; ii < _midiChannels.length; ii++) { - _midiChannels[ii].controlChange(MIDI_VOLUME_CONTROL, setting); - } + if (_musicPlayer != null) { + _musicPlayer.setVolume(_musicVol); } } - // documentation inherited from interface MetaEventListener - public void meta (MetaMessage msg) + // documentation inherited from interface MusicPlayer.MusicEventListener + public void musicStopped () { -// Log.info("meta message: " + msg.getType() + ", msg=" + -// new String(msg.getData())); - - if (msg.getType() == MIDI_END_OF_TRACK) { - songStopEvent(); - } + handleMusicStopped(); + playTopMusic(); } - /** - * Submitted by external players like the MP3Manager. - */ - public void songStopEvent () + protected void shutdownMusic () { - if (_stoppingSong) { - _stoppingSong = false; - } else { - stopCurrentSong(true); - playTopSong(); + if (_musicPlayer != null) { + _musicPlayer.stop(); + _musicPlayer.shutdown(); } } @@ -764,7 +594,8 @@ public class SoundManager } else { // set it up and put it in the cache AudioInputStream stream = AudioSystem.getAudioInputStream( - getResource(key)); + new ByteArrayInputStream(StreamUtils.streamAsBytes( + _rmgr.getResource(key.set, key.path), BUFFER_SIZE))); DataLine.Info dinfo = new DataLine.Info( Clip.class, stream.getFormat()); info = new ClipInfo(dinfo, stream); @@ -774,37 +605,6 @@ public class SoundManager return info; } - /** - * Get the midi data for the specified path. - */ - protected InputStream getMidiData (MidiInfo info) - throws IOException - { - InputStream stream = (InputStream) _midiCache.get(info); - if (stream != null) { - // reset the stream for the new user - stream.reset(); - - } else { - stream = getResource(info); - _midiCache.put(info, stream); - } - - return stream; - } - - - /** - * Get the data specified by the path from the resource bundle. - * No caching is done. - */ - protected InputStream getResource (SoundKey key) - throws IOException - { - return new ByteArrayInputStream(StreamUtils.streamAsBytes( - _rmgr.getResource(key.set, key.path), BUFFER_SIZE)); - } - // /** // * Adjust the volume of this clip. // */ @@ -1042,7 +842,8 @@ public class SoundManager { if (o instanceof SoundKey) { SoundKey that = (SoundKey) o; - return (this.path == that.path) && (this.set == that.set); + return this.path.equals(that.path) && + this.set.equals(that.set); } return false; } @@ -1067,18 +868,14 @@ public class SoundManager } /** - * A class that tracks the information about our playing midi files. + * A class that tracks the information about our playing music files. */ - protected static class MidiInfo extends SoundKey + protected static class MusicInfo extends SoundKey { /** How many times to loop, or -1 for forever. */ public int loops; - /** The position of big loopers, or -1 if none. */ - public long tickPosition = -1; - public long msPosition = -1; - - public MidiInfo (String set, String path, int loops) + public MusicInfo (String set, String path, int loops) { super(set, path); this.loops = loops; @@ -1106,10 +903,6 @@ public class SoundManager /** The queue of sound clips to be played. */ protected Queue _queue = new Queue(); - - /** So that we ignore the stopped meta event when we stop a song - * ourselves. */ - protected boolean _stoppingSong = false; /** Volume levels for both sound clips and music. */ protected float _clipVol = 1f, _musicVol = 1f; @@ -1117,28 +910,14 @@ public class SoundManager /** The cache of recent audio clips . */ protected LockableLRUHashMap _clipCache = new LockableLRUHashMap(10); - /** The cache of recent midi sequences. */ - protected LRUHashMap _midiCache = new LRUHashMap(4); - /** The clips that are currently active. */ protected ArrayList _activeClips = new ArrayList(); - /** The sequencer that plays midi music. */ - protected Sequencer _sequencer; - - protected MP3Manager _mp3player; - - protected ModPlayer _modplayer; - - /** The receiver used to send midi from the sequencer to an alternate - * midi device. */ - protected Receiver _receiver; - - /** The channels in the sequencer, which we'll use to fuxor volumes. */ - protected MidiChannel[] _midiChannels; - /** The stack of songs that we're playing. */ - protected LinkedList _midiStack = new LinkedList(); + protected LinkedList _musicStack = new LinkedList(); + + /** The current music player, if any. */ + protected MusicPlayer _musicPlayer; /** A set of soundTypes for which sound is enabled. */ protected HashSet _disabledTypes = new HashSet(); @@ -1153,12 +932,6 @@ public class SoundManager protected Object FLUSH = new Object(); protected Object DIE = new Object(); - /** This is apparently the midi code for end of track. Wack. */ - protected static final int MIDI_END_OF_TRACK = 47; - - /** The midi control for volume is 7. Ooooooo. */ - protected static final int MIDI_VOLUME_CONTROL = 7; - /** The queue size at which we start to ignore requests to play sounds. */ protected static final int MAX_QUEUE_SIZE = 100;