From 7da8317928a000c5c708ccc7acd777bb117c1b36 Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Wed, 20 Nov 2002 01:33:34 +0000 Subject: [PATCH] mp3 playing capabilities. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1964 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- src/java/com/threerings/media/MP3Manager.java | 110 ++++++++++++++++++ .../threerings/media/sound/SoundManager.java | 100 ++++++++++++---- 2 files changed, 188 insertions(+), 22 deletions(-) create mode 100644 src/java/com/threerings/media/MP3Manager.java diff --git a/src/java/com/threerings/media/MP3Manager.java b/src/java/com/threerings/media/MP3Manager.java new file mode 100644 index 000000000..9ff997e5c --- /dev/null +++ b/src/java/com/threerings/media/MP3Manager.java @@ -0,0 +1,110 @@ +// +// $Id: MP3Manager.java,v 1.1 2002/11/20 01:33:34 ray Exp $ + +package com.threerings.media; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine.Info; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; + +import org.apache.commons.io.StreamUtils; + +import com.threerings.resource.ResourceManager; + +/** + * Does something extraordinary. + */ +public class MP3Manager +{ + public MP3Manager (ResourceManager rmgr, SoundManager smgr) + { + _rmgr = rmgr; + _smgr = smgr; + } + + public void stop () + { + _player = null; + } + + public void start (final String path) + { + _player = new Thread("narya mp3 relay") { + public void run () { + AudioInputStream inStream = null; + try { + inStream = AudioSystem.getAudioInputStream( +// new ByteArrayInputStream(StreamUtils.streamAsBytes( +// _rmgr.getResource(path), 8192))); + new BufferedInputStream(_rmgr.getResource(path), 4096)); + } catch (Exception e) { + Log.warning("MP3 fuckola [path=" + path + + ", e=" + e + "]."); + return; + } + + AudioFormat sourceFormat = inStream.getFormat(); + AudioFormat.Encoding targetEnc = + AudioFormat.Encoding.PCM_SIGNED; + + inStream = AudioSystem.getAudioInputStream( + targetEnc, inStream); + AudioFormat format = inStream.getFormat(); + + SourceDataLine line = null; + DataLine.Info info = new DataLine.Info( + SourceDataLine.class, format); + + try { + line = (SourceDataLine) AudioSystem.getLine(info); + line.open(format); + } catch (LineUnavailableException lue) { + Log.warning("MP3 line unavailable: " + lue); + return; + } + + line.start(); + + byte[] data = new byte[BUFFER_SIZE]; + int count = 0; + while (_player == Thread.currentThread()) { + try { + count = inStream.read(data, 0, data.length); + } catch (IOException ioe) { + Log.warning("Error reading MP3: " + ioe); + break; + } + if (count >= 0) { + line.write(data, 0, count); + } else { + break; + } + } + + line.close(); + _smgr.songStopEvent(); + } + }; + + _player.setDaemon(true); + _player.setPriority(_player.getPriority() + 1); + _player.start(); + } + + protected Thread _player; + + protected ResourceManager _rmgr; + protected SoundManager _smgr; + + protected static final int BUFFER_SIZE = 128000; +} diff --git a/src/java/com/threerings/media/sound/SoundManager.java b/src/java/com/threerings/media/sound/SoundManager.java index 278c4fe44..eda40e5aa 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.19 2002/11/19 21:17:35 ray Exp $ +// $Id: SoundManager.java,v 1.20 2002/11/20 01:33:34 ray Exp $ package com.threerings.media; @@ -103,7 +103,7 @@ public class SoundManager // create a thread to plays sounds and load sound // data from the resource manager - _player = new Thread() { + _player = new Thread("narya SoundManager") { public void run () { Object command = null; String path = null; @@ -493,16 +493,20 @@ public class SoundManager // start the new one try { - _sequencer.setSequence(getMidiData(info.path)); - if (info.msPosition != -1) { - // TODO: this doesn't work correctly - _sequencer.setTickPosition(info.tickPosition); - _sequencer.setMicrosecondPosition(info.msPosition); - info.msPosition = -1; + if (info.path.endsWith(".mp3")) { + _mp3player.start(info.path); + } else { + _sequencer.setSequence(getMidiData(info.path)); + 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); } - _sequencer.start(); - //updateMusicVolume(); - //Log.info("Now playing : " + info.path); } catch (InvalidMidiDataException imda) { Log.warning("Invalid midi data, not playing [path=" + @@ -523,16 +527,20 @@ public class SoundManager return; } + // see what was playing + MidiInfo current = (MidiInfo) _midiStack.getFirst(); + // stop the existing song if (!wasStopped) { // TODO: fade? _stoppingSong = true; - _sequencer.stop(); + if (current.path.endsWith(".mp3")) { + _mp3player.stop(); + } else { + _sequencer.stop(); + } } - // see what was playing - MidiInfo current = (MidiInfo) _midiStack.getFirst(); - switch (current.loops) { default: current.loops--; @@ -563,9 +571,15 @@ public class SoundManager // if we're currently playing this song.. if (path.equals(current.path)) { + // stop it _stoppingSong = true; - _sequencer.stop(); + if (path.endsWith(".mp3")) { + _mp3player.stop(); + } else { + _sequencer.stop(); + } + // remove it from the stack _midiStack.removeFirst(); // start playing the next.. @@ -592,8 +606,11 @@ public class SoundManager */ protected void initMidi () { + _mp3player = new MP3Manager(_rmgr, this); + try { Sequencer seq = MidiSystem.getSequencer(); +// Sequencer seq = getTritonusSequencer(); seq.open(); if (seq instanceof Synthesizer) { _midiChannels = ((Synthesizer) seq).getChannels(); @@ -602,12 +619,42 @@ public class SoundManager _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. */ @@ -647,13 +694,20 @@ public class SoundManager // new String(msg.getData())); if (msg.getType() == MIDI_END_OF_TRACK) { + songStopEvent(); + } + } - if (_stoppingSong) { - _stoppingSong = false; - } else { - stopCurrentSong(true); - playTopSong(); - } + /** + * Submitted by external players like the MP3Manager. + */ + public void songStopEvent () + { + if (_stoppingSong) { + _stoppingSong = false; + } else { + stopCurrentSong(true); + playTopSong(); } } @@ -1018,6 +1072,8 @@ public class SoundManager /** The sequencer that plays midi music. */ protected Sequencer _sequencer; + protected MP3Manager _mp3player; + /** The receiver used to send midi from the sequencer to an alternate * midi device. */ protected Receiver _receiver;