Behold, Nenya, Ring of Water and repository for our media and animation related
goodies, both Java 2D and LWJGL/JME 3D. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@1 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
//
|
||||
// $Id: MidiPlayer.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.sound.midi.MetaEventListener;
|
||||
import javax.sound.midi.MetaMessage;
|
||||
import javax.sound.midi.MidiChannel;
|
||||
import javax.sound.midi.MidiSystem;
|
||||
import javax.sound.midi.Sequencer;
|
||||
import javax.sound.midi.Synthesizer;
|
||||
|
||||
/**
|
||||
* Plays midi/rmf sounds using Java's sequencer, which is susceptible
|
||||
* to the accuracy of System.currentTimeMillis() and so currently sounds
|
||||
* like "ass" under Windows.
|
||||
*/
|
||||
public class MidiPlayer extends MusicPlayer
|
||||
implements MetaEventListener
|
||||
{
|
||||
// documentation inherited
|
||||
public void init ()
|
||||
throws Exception
|
||||
{
|
||||
_sequencer = MidiSystem.getSequencer();
|
||||
_sequencer.open();
|
||||
if (_sequencer instanceof Synthesizer) {
|
||||
_channels = ((Synthesizer) _sequencer).getChannels();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void shutdown ()
|
||||
{
|
||||
_sequencer.close();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void start (InputStream stream)
|
||||
throws Exception
|
||||
{
|
||||
_sequencer.setSequence(new BufferedInputStream(stream));
|
||||
_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;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// $Id: ModPlayer.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import micromod.MicroMod;
|
||||
import micromod.Module;
|
||||
import micromod.ModuleLoader;
|
||||
import micromod.output.JavaSoundOutputDevice;
|
||||
import micromod.output.OutputDeviceException;
|
||||
import micromod.output.converters.SS16LEAudioFormatConverter;
|
||||
import micromod.resamplers.LinearResampler;
|
||||
|
||||
/**
|
||||
* A player that plays .mod format music.
|
||||
*/
|
||||
public class ModPlayer extends MusicPlayer
|
||||
{
|
||||
// documentation inherited
|
||||
public void init ()
|
||||
throws Exception
|
||||
{
|
||||
_device = new NaryaSoundDevice();
|
||||
_device.start();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void shutdown ()
|
||||
{
|
||||
_device.stop();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void start (InputStream stream)
|
||||
throws Exception
|
||||
{
|
||||
Module module = ModuleLoader.read(new DataInputStream(stream));
|
||||
|
||||
final MicroMod mod = new MicroMod(
|
||||
module, _device, new LinearResampler());
|
||||
|
||||
_player = new Thread("narya mod player") {
|
||||
public void run () {
|
||||
|
||||
while (mod.getSequenceLoopCount() == 0) {
|
||||
|
||||
mod.doRealTimePlayback();
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException ie) {
|
||||
// WFCares
|
||||
}
|
||||
|
||||
if (_player != Thread.currentThread()) {
|
||||
// we were stopped!
|
||||
return;
|
||||
}
|
||||
}
|
||||
_device.drain();
|
||||
_musicListener.musicStopped();
|
||||
}
|
||||
};
|
||||
|
||||
_player.setDaemon(true);
|
||||
_player.start();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void stop ()
|
||||
{
|
||||
_player = null;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void setVolume (float vol)
|
||||
{
|
||||
_device.setVolume(vol);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that allows us to access the dataline so we can adjust
|
||||
* the volume.
|
||||
*/
|
||||
protected static class NaryaSoundDevice extends JavaSoundOutputDevice
|
||||
{
|
||||
public NaryaSoundDevice ()
|
||||
throws OutputDeviceException
|
||||
{
|
||||
super(new SS16LEAudioFormatConverter(), 44100, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the volume of the line that we're sending our mod data to.
|
||||
*/
|
||||
public void setVolume (float vol)
|
||||
{
|
||||
SoundManager.adjustVolume(sourceDataLine, vol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the drain method of the line.
|
||||
*/
|
||||
public void drain ()
|
||||
{
|
||||
sourceDataLine.drain();
|
||||
}
|
||||
}
|
||||
|
||||
/** The thread that does the work. */
|
||||
protected Thread _player;
|
||||
|
||||
/** The sound output device. */
|
||||
protected NaryaSoundDevice _device;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// $Id: Mp3Player.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
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;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* Plays mp3 files. Depends on three external jar files that aren't even
|
||||
* imported here:
|
||||
* tritonus_share.jar
|
||||
* tritonus_mp3.jar
|
||||
* javalayer.jar
|
||||
*/
|
||||
public class Mp3Player extends MusicPlayer
|
||||
{
|
||||
// documentation inherited
|
||||
public void init ()
|
||||
{
|
||||
// TODO: some stuff needs to move here, like setting up the line
|
||||
// but we don't yet know the audio format, so I need to figure that
|
||||
// out (the format might always be known..).
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void shutdown ()
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void start (final InputStream stream)
|
||||
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;
|
||||
try {
|
||||
inStream = AudioSystem.getAudioInputStream(
|
||||
new BufferedInputStream(stream, BUFFER_SIZE));
|
||||
} catch (Exception e) {
|
||||
Log.warning("MP3 fuckola. [e=" + e + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
AudioFormat sourceFormat = inStream.getFormat();
|
||||
AudioFormat.Encoding targetEnc =
|
||||
AudioFormat.Encoding.PCM_SIGNED;
|
||||
|
||||
inStream = AudioSystem.getAudioInputStream(
|
||||
targetEnc, inStream);
|
||||
AudioFormat format = inStream.getFormat();
|
||||
|
||||
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 (count >= 0) {
|
||||
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);
|
||||
}
|
||||
if (_player != Thread.currentThread()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_line.drain();
|
||||
_line.close();
|
||||
_musicListener.musicStopped();
|
||||
}
|
||||
};
|
||||
|
||||
_player.setDaemon(true);
|
||||
//_player.setPriority(_player.getPriority() + 1);
|
||||
_player.start();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void stop ()
|
||||
{
|
||||
_player = null;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void setVolume (float volume)
|
||||
{
|
||||
// TODO : line won't be null when we initialize it in the right place
|
||||
if (_line != null) {
|
||||
SoundManager.adjustVolume(_line, volume);
|
||||
}
|
||||
}
|
||||
|
||||
/** The thread that transfers data to the line. */
|
||||
protected Thread _player;
|
||||
|
||||
/** The line that we play through. */
|
||||
protected SourceDataLine _line;
|
||||
|
||||
/** The size of our buffer. */
|
||||
protected static final int BUFFER_SIZE = 8192;
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
//
|
||||
// $Id: SoundManager.java 3290 2004-12-29 21:56:58Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import com.samskivert.util.Config;
|
||||
import com.samskivert.util.RandomUtil;
|
||||
import com.samskivert.util.RunQueue;
|
||||
|
||||
import com.threerings.media.Log;
|
||||
|
||||
/**
|
||||
* Manages the playing of audio files.
|
||||
*/
|
||||
// TODO:
|
||||
// - fade music out when stopped?
|
||||
// - be able to pause music
|
||||
public class MusicManager
|
||||
{
|
||||
/**
|
||||
* Constructs a music manager.
|
||||
*
|
||||
* @param smgr The soundManager we work with.
|
||||
* @param runQueue the client event run queue.
|
||||
*
|
||||
*/
|
||||
public MusicManager (SoundManager smgr, RunQueue runQueue)
|
||||
{
|
||||
_smgr = smgr;
|
||||
_runQueue = runQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut the damn thing off.
|
||||
*/
|
||||
public void shutdown ()
|
||||
{
|
||||
_musicStack.clear();
|
||||
stopMusicPlayer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string summarizing our volume settings and disabled sound
|
||||
* types.
|
||||
*/
|
||||
public String summarizeState ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("musicVol=").append(_musicVol);
|
||||
return buf.append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the volume for music.
|
||||
*
|
||||
* @param vol a volume parameter between 0f and 1f, inclusive.
|
||||
*/
|
||||
public void setMusicVolume (float vol)
|
||||
{
|
||||
float oldvol = _musicVol;
|
||||
_musicVol = Math.max(0f, Math.min(1f, vol));
|
||||
if (_musicPlayer != null) {
|
||||
_musicPlayer.setVolume(_musicVol);
|
||||
}
|
||||
|
||||
if ((oldvol == 0f) && (_musicVol != 0f)) {
|
||||
playTopMusic();
|
||||
} else if ((oldvol != 0f) && (_musicVol == 0f)) {
|
||||
stopMusicPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the music volume.
|
||||
*/
|
||||
public float getMusicVolume ()
|
||||
{
|
||||
return _musicVol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start playing the specified music repeatedly.
|
||||
*/
|
||||
public void pushMusic (String pkgPath, String key)
|
||||
{
|
||||
pushMusic(pkgPath, key, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start playing music for the specified number of loops. If no other
|
||||
* music is pushed, the specified music will play for the number of loops
|
||||
* specified, and will then be popped off the stack.
|
||||
*/
|
||||
public void pushMusic (String pkgPath, String key, int numloops)
|
||||
{
|
||||
MusicKey mkey = new MusicKey(pkgPath, key, numloops);
|
||||
|
||||
// stop any existing playing music
|
||||
if (_musicPlayer != null) {
|
||||
_musicPlayer.stop();
|
||||
handleMusicStopped();
|
||||
}
|
||||
|
||||
// add the new song
|
||||
_musicStack.addFirst(mkey);
|
||||
|
||||
// and play it
|
||||
playTopMusic();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified music from the playlist. If it is currently
|
||||
* playing, it will be stopped and the previous song will be started.
|
||||
*/
|
||||
public void removeMusic (String pkgPath, String key)
|
||||
{
|
||||
MusicKey mkey = new MusicKey(pkgPath, key, -1);
|
||||
|
||||
if (!_musicStack.isEmpty()) {
|
||||
MusicKey current = (MusicKey) _musicStack.getFirst();
|
||||
|
||||
// if we're currently playing this song..
|
||||
if (mkey.equals(current)) {
|
||||
// stop it
|
||||
if (_musicPlayer != null) {
|
||||
_musicPlayer.stop();
|
||||
}
|
||||
|
||||
// remove it from the stack
|
||||
_musicStack.removeFirst();
|
||||
// start playing the next..
|
||||
playTopMusic();
|
||||
return;
|
||||
|
||||
} else {
|
||||
// we aren't currently playing this song. Simply remove.
|
||||
for (Iterator iter=_musicStack.iterator(); iter.hasNext(); ) {
|
||||
if (key.equals(iter.next())) {
|
||||
iter.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Log.debug("Sequence stopped that wasn't in the stack anymore " +
|
||||
"[key=" + mkey + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the specified sequence.
|
||||
*/
|
||||
protected void playTopMusic ()
|
||||
{
|
||||
if (_musicStack.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the volume is off, we don't actually want to play anything
|
||||
// but we want to at least decrement any loopers by one
|
||||
// and keep them on the top of the queue
|
||||
if (_musicVol == 0f) {
|
||||
handleMusicStopped();
|
||||
return;
|
||||
}
|
||||
|
||||
MusicKey info = (MusicKey) _musicStack.getFirst();
|
||||
|
||||
Config c = _smgr.getConfig(info);
|
||||
String[] names = c.getValue(info.key, (String[])null);
|
||||
if ((names == null) || (names.length == 0)) {
|
||||
Log.warning("No such music [key=" + info + "].");
|
||||
_musicStack.removeFirst();
|
||||
playTopMusic();
|
||||
return;
|
||||
}
|
||||
String music = names[RandomUtil.getInt(names.length)];
|
||||
|
||||
Class playerClass = getMusicPlayerClass(music);
|
||||
|
||||
// if we don't have a player for this song, play the next song
|
||||
if (playerClass == null) {
|
||||
_musicStack.removeFirst();
|
||||
playTopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
// shutdown the old player if we're switching music types
|
||||
if (! playerClass.isInstance(_musicPlayer)) {
|
||||
if (_musicPlayer != null) {
|
||||
_musicPlayer.shutdown();
|
||||
}
|
||||
|
||||
// set up the new player
|
||||
try {
|
||||
_musicPlayer = (MusicPlayer) playerClass.newInstance();
|
||||
_musicPlayer.init(_playerListener);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.warning("Unable to instantiate music player [class=" +
|
||||
playerClass + ", e=" + e + "].");
|
||||
|
||||
// scrap it, try again with the next song
|
||||
_musicPlayer = null;
|
||||
_musicStack.removeFirst();
|
||||
playTopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
_musicPlayer.setVolume(_musicVol);
|
||||
}
|
||||
|
||||
// play!
|
||||
String bundle = c.getValue("bundle", (String)null);
|
||||
try {
|
||||
// TODO: buffer for the music player?
|
||||
_musicPlayer.start(_smgr._rmgr.getResource(bundle, music));
|
||||
} catch (Exception e) {
|
||||
Log.warning("Error playing music, skipping [e=" + e +
|
||||
", bundle=" + bundle + ", music=" + music + "].");
|
||||
_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 if (path.endsWith(".ogg")) {
|
||||
// return OggPlayer.class;
|
||||
|
||||
// } else {
|
||||
return null;
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop whatever song is currently playing and deal with the
|
||||
* MusicKey associated with it.
|
||||
*/
|
||||
protected void handleMusicStopped ()
|
||||
{
|
||||
if (_musicStack.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// see what was playing
|
||||
MusicKey current = (MusicKey) _musicStack.getFirst();
|
||||
|
||||
// see how many times the song was to loop and act accordingly
|
||||
switch (current.loops) {
|
||||
default:
|
||||
current.loops--;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// sorry charlie
|
||||
_musicStack.removeFirst();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the current music player.
|
||||
*/
|
||||
protected void stopMusicPlayer ()
|
||||
{
|
||||
if (_musicPlayer != null) {
|
||||
_musicPlayer.stop();
|
||||
_musicPlayer.shutdown();
|
||||
_musicPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that tracks the information about our playing music files.
|
||||
*/
|
||||
protected static class MusicKey extends SoundManager.SoundKey
|
||||
{
|
||||
/** How many times to loop, or -1 for forever. */
|
||||
public int loops;
|
||||
|
||||
public MusicKey (String set, String path, int loops)
|
||||
{
|
||||
super((byte) -1, set, path);
|
||||
this.loops = loops;
|
||||
}
|
||||
}
|
||||
|
||||
/** The sound manager we work with. */
|
||||
protected SoundManager _smgr;
|
||||
|
||||
/** The client event run queue. */
|
||||
protected RunQueue _runQueue;
|
||||
|
||||
/** Volume level for music. */
|
||||
protected float _musicVol = 1f;
|
||||
|
||||
/** The stack of songs that we're playing. */
|
||||
protected LinkedList _musicStack = new LinkedList();
|
||||
|
||||
/** The current music player, if any. */
|
||||
protected MusicPlayer _musicPlayer;
|
||||
|
||||
/** Event listener for receiving information about a song ending. */
|
||||
protected MusicPlayer.MusicEventListener _playerListener =
|
||||
new MusicPlayer.MusicEventListener() {
|
||||
public void musicStopped () {
|
||||
_runQueue.postRunnable(new Runnable() {
|
||||
public void run() {
|
||||
handleMusicStopped();
|
||||
playTopMusic();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// $Id: MusicPlayer.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Abstract music player.
|
||||
*/
|
||||
public abstract class MusicPlayer
|
||||
{
|
||||
/**
|
||||
* A watcher interested in music events.
|
||||
*/
|
||||
public interface MusicEventListener
|
||||
{
|
||||
/**
|
||||
* A callback that all players should use when the song they are
|
||||
* playing has finished playing (completely).
|
||||
*/
|
||||
public void musicStopped();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the music player.
|
||||
*/
|
||||
public final void init (MusicEventListener musicListener)
|
||||
throws Exception
|
||||
{
|
||||
_musicListener = musicListener;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do your init here.
|
||||
*/
|
||||
public void init ()
|
||||
throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown and free all resources.
|
||||
*/
|
||||
public void shutdown ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Start playing song data from the specified stream.
|
||||
*/
|
||||
public abstract void start (InputStream stream)
|
||||
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);
|
||||
|
||||
/** Tell this guy about it when a song stops. */
|
||||
protected MusicEventListener _musicListener;
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
//
|
||||
// $Id: OggPlayer.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
||||
import com.jcraft.jorbis.*;
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
/**
|
||||
* Plays Ogg Vorbis streams.
|
||||
*
|
||||
* Hacked together from NASTY code from JOrbis.
|
||||
*/
|
||||
// TODO- this would need to be greatly cleaned up if we were serious about
|
||||
// using it.
|
||||
public class OggPlayer extends MusicPlayer
|
||||
{
|
||||
// documentation inherited
|
||||
public void start (final InputStream stream)
|
||||
{
|
||||
_player = new Thread("narya ogg player") {
|
||||
public void run () {
|
||||
playStream(stream);
|
||||
}
|
||||
};
|
||||
_player.setDaemon(true);
|
||||
_player.start();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void stop ()
|
||||
{
|
||||
_player = null;
|
||||
}
|
||||
|
||||
static final int BUFSIZE=4096*2;
|
||||
static int convsize=BUFSIZE*2;
|
||||
static byte[] convbuffer=new byte[convsize];
|
||||
|
||||
SyncState oy;
|
||||
StreamState os;
|
||||
Page og;
|
||||
Packet op;
|
||||
Info vi;
|
||||
Comment vc;
|
||||
DspState vd;
|
||||
Block vb;
|
||||
|
||||
byte[] buffer=null;
|
||||
int bytes=0;
|
||||
|
||||
int format;
|
||||
int rate=0;
|
||||
int channels=0;
|
||||
SourceDataLine outputLine=null;
|
||||
|
||||
int frameSizeInBytes;
|
||||
int bufferLengthInBytes;
|
||||
|
||||
void init_jorbis(){
|
||||
oy=new SyncState();
|
||||
os=new StreamState();
|
||||
og=new Page();
|
||||
op=new Packet();
|
||||
|
||||
vi=new Info();
|
||||
vc=new Comment();
|
||||
vd=new DspState();
|
||||
vb=new Block(vd);
|
||||
|
||||
buffer=null;
|
||||
bytes=0;
|
||||
|
||||
oy.init();
|
||||
}
|
||||
|
||||
SourceDataLine getOutputLine(int channels, int rate){
|
||||
if(outputLine!=null || this.rate!=rate || this.channels!=channels){
|
||||
if(outputLine!=null){
|
||||
outputLine.drain();
|
||||
outputLine.stop();
|
||||
outputLine.close();
|
||||
}
|
||||
init_audio(channels, rate);
|
||||
outputLine.start();
|
||||
}
|
||||
return outputLine;
|
||||
}
|
||||
|
||||
void init_audio(int channels, int rate){
|
||||
try {
|
||||
//ClassLoader originalClassLoader=null;
|
||||
//try{
|
||||
// originalClassLoader=Thread.currentThread().getContextClassLoader();
|
||||
// Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
|
||||
//}
|
||||
//catch(Exception ee){
|
||||
// System.out.println(ee);
|
||||
//}
|
||||
AudioFormat audioFormat =
|
||||
new AudioFormat((float)rate,
|
||||
16,
|
||||
channels,
|
||||
true, // PCM_Signed
|
||||
false // littleEndian
|
||||
);
|
||||
DataLine.Info info =
|
||||
new DataLine.Info(SourceDataLine.class,
|
||||
audioFormat,
|
||||
AudioSystem.NOT_SPECIFIED);
|
||||
if (!AudioSystem.isLineSupported(info)) {
|
||||
//System.out.println("Line " + info + " not supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
outputLine = (SourceDataLine) AudioSystem.getLine(info);
|
||||
//outputLine.addLineListener(this);
|
||||
outputLine.open(audioFormat);
|
||||
}
|
||||
catch (LineUnavailableException ex) {
|
||||
System.out.println("Unable to open the sourceDataLine: " + ex);
|
||||
return;
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
System.out.println("Illegal Argument: " + ex);
|
||||
return;
|
||||
}
|
||||
|
||||
frameSizeInBytes = audioFormat.getFrameSize();
|
||||
int bufferLengthInFrames = outputLine.getBufferSize()/frameSizeInBytes/2;
|
||||
bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
|
||||
|
||||
//buffer = new byte[bufferLengthInBytes];
|
||||
//if(originalClassLoader!=null)
|
||||
// Thread.currentThread().setContextClassLoader(originalClassLoader);
|
||||
|
||||
this.rate=rate;
|
||||
this.channels=channels;
|
||||
}
|
||||
catch(Exception ee){
|
||||
System.out.println(ee);
|
||||
}
|
||||
}
|
||||
|
||||
protected void playStream (InputStream stream)
|
||||
{
|
||||
init_jorbis();
|
||||
|
||||
loop:
|
||||
while (true) {
|
||||
int eos = 0;
|
||||
|
||||
int index = oy.buffer(BUFSIZE);
|
||||
buffer = oy.data;
|
||||
try {
|
||||
bytes = stream.read(buffer, index, BUFSIZE);
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
|
||||
if (oy.pageout(og) != 1) {
|
||||
if (bytes < BUFSIZE) {
|
||||
break;
|
||||
}
|
||||
System.err.println("Input does not appear to be an Ogg bitstream.");
|
||||
return;
|
||||
}
|
||||
|
||||
os.init(og.serialno());
|
||||
os.reset();
|
||||
|
||||
vi.init();
|
||||
vc.init();
|
||||
|
||||
if (os.pagein(og) < 0) {
|
||||
// error; stream version mismatch perhaps
|
||||
System.err.println("Error reading first page of Ogg bitstream data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (os.packetout(op) != 1) {
|
||||
// no page? must not be vorbis
|
||||
System.err.println("Error reading initial header packet.");
|
||||
break;
|
||||
// return;
|
||||
}
|
||||
|
||||
if (vi.synthesis_headerin(vc, op) < 0) {
|
||||
// error case; not a vorbis header
|
||||
System.err.println("This Ogg bitstream does not contain Vorbis audio data.");
|
||||
return;
|
||||
}
|
||||
|
||||
int i=0;
|
||||
|
||||
while (i < 2) {
|
||||
while (i < 2) {
|
||||
int result = oy.pageout(og);
|
||||
if (result==0) {
|
||||
break; // Need more data
|
||||
}
|
||||
if (result==1) {
|
||||
os.pagein(og);
|
||||
while (i < 2) {
|
||||
result = os.packetout(op);
|
||||
if (result == 0) {
|
||||
break;
|
||||
}
|
||||
if (result == -1) {
|
||||
System.err.println("Corrupt secondary header. Exiting.");
|
||||
//return;
|
||||
break loop;
|
||||
}
|
||||
vi.synthesis_headerin(vc, op);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = oy.buffer(BUFSIZE);
|
||||
buffer = oy.data;
|
||||
try {
|
||||
bytes = stream.read(buffer, index, BUFSIZE);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes == 0 && i < 2) {
|
||||
System.err.println("End of file before finding all Vorbis headers!");
|
||||
return;
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
}
|
||||
|
||||
convsize=BUFSIZE/vi.channels;
|
||||
|
||||
vd.synthesis_init(vi);
|
||||
vb.init(vd);
|
||||
|
||||
double[][][] _pcm=new double[1][][];
|
||||
float[][][] _pcmf=new float[1][][];
|
||||
int[] _index=new int[vi.channels];
|
||||
|
||||
getOutputLine(vi.channels, vi.rate);
|
||||
|
||||
while (eos == 0) {
|
||||
while (eos == 0) {
|
||||
|
||||
if (_player != Thread.currentThread()) {
|
||||
//System.err.println("bye.");
|
||||
try {
|
||||
//outputLine.drain();
|
||||
//outputLine.stop();
|
||||
//outputLine.close();
|
||||
stream.close();
|
||||
} catch(Exception ee) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int result = oy.pageout(og);
|
||||
if (result == 0) {
|
||||
break; // need more data
|
||||
}
|
||||
if (result == -1) { // missing or corrupt data at this page position
|
||||
// System.err.println("Corrupt or missing data in bitstream; continuing...");
|
||||
|
||||
} else {
|
||||
os.pagein(og);
|
||||
while (true) {
|
||||
result = os.packetout(op);
|
||||
if (result == 0) break; // need more data
|
||||
if (result == -1) { // missing or corrupt data at this page position
|
||||
// no reason to complain; already complained above
|
||||
} else {
|
||||
// we have a packet. Decode it
|
||||
int samples;
|
||||
if (vb.synthesis(op) == 0) { // test for success!
|
||||
vd.synthesis_blockin(vb);
|
||||
}
|
||||
while ((samples =
|
||||
vd.synthesis_pcmout(_pcmf, _index)) > 0) {
|
||||
|
||||
double[][] pcm = _pcm[0];
|
||||
float[][] pcmf = _pcmf[0];
|
||||
boolean clipflag = false;
|
||||
int bout = Math.min(samples, convsize);
|
||||
|
||||
// convert doubles to 16 bit signed ints (host order) and
|
||||
// interleave
|
||||
for (i = 0; i < vi.channels; i++) {
|
||||
int ptr = i*2;
|
||||
//int ptr=i;
|
||||
int mono = _index[i];
|
||||
for (int j = 0; j < bout; j++) {
|
||||
int val = (int)
|
||||
(pcmf[i][mono+j] * 32767.);
|
||||
if (val > 32767){
|
||||
val = 32767;
|
||||
clipflag = true;
|
||||
|
||||
} else if (val < -32768) {
|
||||
val = -32768;
|
||||
clipflag = true;
|
||||
}
|
||||
if (val < 0) {
|
||||
val = val | 0x8000;
|
||||
}
|
||||
convbuffer[ptr] = (byte)(val);
|
||||
convbuffer[ptr+1] = (byte)(val>>>8);
|
||||
ptr += 2 * (vi.channels);
|
||||
}
|
||||
}
|
||||
outputLine.write(convbuffer, 0,
|
||||
2 * vi.channels * bout);
|
||||
vd.synthesis_read(bout);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (og.eos() != 0) {
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eos==0) {
|
||||
index = oy.buffer(BUFSIZE);
|
||||
buffer = oy.data;
|
||||
try {
|
||||
bytes = stream.read(buffer,index,BUFSIZE);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
if (bytes == -1) {
|
||||
break;
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
if (bytes==0) {
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os.clear();
|
||||
vb.clear();
|
||||
vd.clear();
|
||||
vi.clear();
|
||||
}
|
||||
|
||||
oy.clear();
|
||||
|
||||
//System.err.println("Done.");
|
||||
|
||||
try {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void setVolume (float volume)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
protected Thread _player;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// $Id: SoundCodes.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
import com.threerings.media.sound.SoundManager.SoundType;
|
||||
|
||||
/**
|
||||
* A basic set of sound types.
|
||||
*/
|
||||
public interface SoundCodes
|
||||
{
|
||||
/**
|
||||
* Alert sounds are the type of sounds a player would hear when
|
||||
* getting a puzzle challenge.
|
||||
*/
|
||||
public static final SoundType ALERT = new SoundType("alert");
|
||||
|
||||
/**
|
||||
* Feedback sounds are the type of sounds a player would here when
|
||||
* clicking on buttons or performing an action.
|
||||
*/
|
||||
public static final SoundType FEEDBACK = new SoundType("feedback");
|
||||
|
||||
/**
|
||||
* Ambient sounds are birds chirping, waves lapping, boats creaking.
|
||||
*/
|
||||
public static final SoundType AMBIENT = new SoundType("ambient");
|
||||
|
||||
/**
|
||||
* Game alert sounds are used to indicate that it's a player's turn.
|
||||
*/
|
||||
public static final SoundType GAME_ALERT = new SoundType("game_alert");
|
||||
|
||||
/**
|
||||
* General game sound effects.
|
||||
*/
|
||||
public static final SoundType GAME_FX =new SoundType("game_fx");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// $Id: Sounds.java 4191 2006-06-13 22:42:20Z ray $
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.media.sound;
|
||||
|
||||
/**
|
||||
* A base class for sound repository classes. These would extend this
|
||||
* class and define keys for the various sounds that are mapped in the
|
||||
* properties file associated with that sound repository.
|
||||
*/
|
||||
public class Sounds
|
||||
{
|
||||
/** The name of the sound repository configuration file. */
|
||||
public static final String PROP_NAME = "sounds";
|
||||
|
||||
/**
|
||||
* Return the package path prefix of the supplied class.
|
||||
*
|
||||
* Generates the key for the sound repository configuration file in
|
||||
* the package associated with the class. For example, if a the class
|
||||
* <code>com.threerings.happy.fun.GameSounds</code> were supplied to
|
||||
* this method, it would return
|
||||
* <code>com/threerings/happy/fun/sounds/</code> which would reference
|
||||
* a <code>sounds.properties</code> file in the
|
||||
* <code>com.threerings.happy.fun</code> package.
|
||||
*/
|
||||
protected static String getPackagePath (Class clazz)
|
||||
{
|
||||
return clazz.getPackage().getName().replace('.', '/') + "/";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user