Added support for looping sounds.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3371 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -89,6 +89,31 @@ public class SoundManager
|
|||||||
protected String _strname;
|
protected String _strname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A control for sounds.
|
||||||
|
*/
|
||||||
|
public static interface Frob
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Stop playing or looping the sound.
|
||||||
|
* At present, the granularity of this command is limited to the
|
||||||
|
* buffer size of the line spooler, or about 8k of data. Thus,
|
||||||
|
* if playing an 11khz sample, it could take 8/11ths of a second
|
||||||
|
* for the sound to actually stop playing.
|
||||||
|
*/
|
||||||
|
public void stop ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the volume of the sound.
|
||||||
|
*/
|
||||||
|
public void setVolume (float vol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the volume of this sound.
|
||||||
|
*/
|
||||||
|
public float getVolume ();
|
||||||
|
}
|
||||||
|
|
||||||
/** The default sound type. */
|
/** The default sound type. */
|
||||||
public static final SoundType DEFAULT = new SoundType("default");
|
public static final SoundType DEFAULT = new SoundType("default");
|
||||||
|
|
||||||
@@ -239,7 +264,8 @@ public class SoundManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((_clipVol != 0f) && isEnabled(type)) {
|
if ((_clipVol != 0f) && isEnabled(type)) {
|
||||||
final SoundKey skey = new SoundKey(PLAY, pkgPath, key, delay);
|
final SoundKey skey = new SoundKey(PLAY, pkgPath, key, delay,
|
||||||
|
_clipVol);
|
||||||
if (delay > 0) {
|
if (delay > 0) {
|
||||||
new Interval() {
|
new Interval() {
|
||||||
public void expired () {
|
public void expired () {
|
||||||
@@ -252,6 +278,18 @@ public class SoundManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop the specified sound.
|
||||||
|
*/
|
||||||
|
public Frob loop (SoundType type, String pkgPath, String key)
|
||||||
|
{
|
||||||
|
SoundKey skey = new SoundKey(LOOP, pkgPath, key, 0, _clipVol);
|
||||||
|
addToPlayQueue(skey);
|
||||||
|
return skey; // it is a frob
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==== End of public methods ====
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the sound clip key to the queue to be played.
|
* Add the sound clip key to the queue to be played.
|
||||||
*/
|
*/
|
||||||
@@ -344,6 +382,7 @@ public class SoundManager
|
|||||||
{
|
{
|
||||||
switch (key.cmd) {
|
switch (key.cmd) {
|
||||||
case PLAY:
|
case PLAY:
|
||||||
|
case LOOP:
|
||||||
playSound(key);
|
playSound(key);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -378,6 +417,10 @@ public class SoundManager
|
|||||||
*/
|
*/
|
||||||
protected void playSound (SoundKey key)
|
protected void playSound (SoundKey key)
|
||||||
{
|
{
|
||||||
|
if (!key.running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
key.thread = Thread.currentThread();
|
||||||
SourceDataLine line = null;
|
SourceDataLine line = null;
|
||||||
try {
|
try {
|
||||||
// get the sound data from our LRU cache
|
// get the sound data from our LRU cache
|
||||||
@@ -390,6 +433,7 @@ public class SoundManager
|
|||||||
Log.info("Sound expired [key=" + key.key + "].");
|
Log.info("Sound expired [key=" + key.key + "].");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInputStream stream = AudioSystem.getAudioInputStream(
|
AudioInputStream stream = AudioSystem.getAudioInputStream(
|
||||||
@@ -400,27 +444,39 @@ public class SoundManager
|
|||||||
line = (SourceDataLine) AudioSystem.getLine(
|
line = (SourceDataLine) AudioSystem.getLine(
|
||||||
new DataLine.Info(SourceDataLine.class, format));
|
new DataLine.Info(SourceDataLine.class, format));
|
||||||
line.open(format, LINEBUF_SIZE);
|
line.open(format, LINEBUF_SIZE);
|
||||||
|
float setVolume = 1;
|
||||||
line.start();
|
line.start();
|
||||||
adjustVolume(line, _clipVol);
|
|
||||||
_soundSeemsToWork = true;
|
_soundSeemsToWork = true;
|
||||||
|
|
||||||
// play the sound
|
do {
|
||||||
byte[] buffer = new byte[LINEBUF_SIZE];
|
// play the sound
|
||||||
int count = 0;
|
byte[] buffer = new byte[LINEBUF_SIZE];
|
||||||
while (count != -1) {
|
int count = 0;
|
||||||
try {
|
while (key.running && count != -1) {
|
||||||
count = stream.read(buffer, 0, buffer.length);
|
float vol = key.volume;
|
||||||
} catch (IOException e) {
|
if (vol != setVolume) {
|
||||||
// this shouldn't ever ever happen because the stream
|
adjustVolume(line, vol);
|
||||||
// we're given is from a reliable source
|
setVolume = vol;
|
||||||
Log.warning("Error reading clip data! [e=" + e + "].");
|
}
|
||||||
return;
|
try {
|
||||||
|
count = stream.read(buffer, 0, buffer.length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// this shouldn't ever ever happen because the stream
|
||||||
|
// we're given is from a reliable source
|
||||||
|
Log.warning("Error reading clip data! [e=" + e + "].");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count >= 0) {
|
||||||
|
line.write(buffer, 0, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count >= 0) {
|
// if we're going to loop, reset the stream to the beginning
|
||||||
line.write(buffer, 0, count);
|
if (key.cmd == LOOP) {
|
||||||
|
stream.reset();
|
||||||
}
|
}
|
||||||
}
|
} while (key.cmd == LOOP && key.running);
|
||||||
|
|
||||||
// sleep the drain time. We never trust line.drain() because
|
// sleep the drain time. We never trust line.drain() because
|
||||||
// it is buggy and locks up on natively multithreaded systems
|
// it is buggy and locks up on natively multithreaded systems
|
||||||
@@ -468,6 +524,7 @@ public class SoundManager
|
|||||||
if (line != null) {
|
if (line != null) {
|
||||||
line.close();
|
line.close();
|
||||||
}
|
}
|
||||||
|
key.thread = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,6 +753,7 @@ public class SoundManager
|
|||||||
* A key for tracking sounds.
|
* A key for tracking sounds.
|
||||||
*/
|
*/
|
||||||
protected static class SoundKey
|
protected static class SoundKey
|
||||||
|
implements Frob
|
||||||
{
|
{
|
||||||
public byte cmd;
|
public byte cmd;
|
||||||
|
|
||||||
@@ -705,6 +763,14 @@ public class SoundManager
|
|||||||
|
|
||||||
public long stamp;
|
public long stamp;
|
||||||
|
|
||||||
|
/** Should we still be running? */
|
||||||
|
public volatile boolean running = true;
|
||||||
|
|
||||||
|
public volatile float volume;
|
||||||
|
|
||||||
|
/** The player thread, if it's playing us. */
|
||||||
|
public Thread thread;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a SoundKey that just contains the specified command.
|
* Create a SoundKey that just contains the specified command.
|
||||||
* DIE.
|
* DIE.
|
||||||
@@ -727,11 +793,36 @@ public class SoundManager
|
|||||||
/**
|
/**
|
||||||
* Constructor for a sound effect soundkey.
|
* Constructor for a sound effect soundkey.
|
||||||
*/
|
*/
|
||||||
public SoundKey (byte cmd, String pkgPath, String key, int delay)
|
public SoundKey (byte cmd, String pkgPath, String key, int delay,
|
||||||
|
float volume)
|
||||||
{
|
{
|
||||||
this(cmd, pkgPath, key);
|
this(cmd, pkgPath, key);
|
||||||
|
|
||||||
stamp = System.currentTimeMillis() + delay;
|
stamp = System.currentTimeMillis() + delay;
|
||||||
|
this.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Frob
|
||||||
|
public void stop ()
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
Thread t = thread;
|
||||||
|
if (t != null) {
|
||||||
|
// doesn't actually ever seem to do much
|
||||||
|
t.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Frob
|
||||||
|
public void setVolume (float vol)
|
||||||
|
{
|
||||||
|
volume = Math.max(0f, Math.min(1f, vol));
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Frob
|
||||||
|
public float getVolume ()
|
||||||
|
{
|
||||||
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -804,6 +895,7 @@ public class SoundManager
|
|||||||
protected static final byte LOCK = 1;
|
protected static final byte LOCK = 1;
|
||||||
protected static final byte UNLOCK = 2;
|
protected static final byte UNLOCK = 2;
|
||||||
protected static final byte DIE = 3;
|
protected static final byte DIE = 3;
|
||||||
|
protected static final byte LOOP = 4;
|
||||||
|
|
||||||
/** A pref that specifies a directory for us to get test sounds from. */
|
/** A pref that specifies a directory for us to get test sounds from. */
|
||||||
protected static RuntimeAdjust.FileAdjust _testDir =
|
protected static RuntimeAdjust.FileAdjust _testDir =
|
||||||
|
|||||||
Reference in New Issue
Block a user