package NET.worlds.scape; import NET.worlds.core.IniFile; import NET.worlds.network.URL; import java.util.Vector; public class WavSoundPlayer extends SoundPlayer implements Runnable { float ang; float dist; float vol; private String playingSoundFile = ""; private URL url; private static Vector soundStack = new Vector(); private static Thread activeThread; int repeatsLeft; private static int playingThreads; private static int systemPaused; static boolean ignoreVolumeChanges = IniFile.gamma().getIniInt("ignoreVolumeChanges", 1) != 0; private static WavSoundTerminator terminator = new WavSoundTerminator(); private static float lastLeftVol; private static float lastRightVol; static { nativeInit(); } public WavSoundPlayer(Sound owner) { super(owner); } public static native void nativeInit(); @Override public boolean open(float volume, float stopDist, boolean atten, boolean pan) { return true; } @Override public void close() { this.stop(); } @Override public boolean position(Point3Temp cam, Point3Temp obj, Point3Temp out, Point3Temp up) { Point3Temp toObj = Point3Temp.make(obj).minus(cam); Point3Temp right = Point3Temp.make(out).cross(up); float y = toObj.dot(out); float x = toObj.dot(right); this.ang = (float)(Math.atan2(y, x) / Math.PI); this.dist = toObj.length(); return this.setVolume(this.vol); } @Override public boolean setVolume(float v) { this.vol = v; float leftFrac = 0.5F; if (this.owner != null && this.owner.getPanning()) { leftFrac = Math.abs(this.ang); if (this.ang < 0.0F) { v = this.vol * (float)(0.5 + Math.abs(0.5 + this.ang)); } } if (this.owner != null && this.owner.getAttenuate()) { float stopDist = this.owner.getStopDistance(); if (this.dist > stopDist) { this.volume(0.0F, 0.0F); return false; } v *= (stopDist - this.dist) / stopDist; } this.volume(v * leftFrac, v * (1.0F - leftFrac)); return true; } @Override public int getState() { return soundStack.contains(this) ? 0 : 1; } public void start(URL u) { this.url = u; this.start(1); } private static WavSoundPlayer getActive() { return !soundStack.isEmpty() ? (WavSoundPlayer)soundStack.lastElement() : null; } public static boolean isActive() { return !soundStack.isEmpty(); } private void play(int repeatCount, boolean reuseLoop) { this.playingSoundFile = this.url.unalias(); soundStack.removeElement(this); soundStack.addElement(this); this.repeatsLeft = repeatCount; if (this.repeatsLeft < 0) { if (!reuseLoop && systemPaused == 0) { this.nativePlay(true); } activeThread = null; } else { activeThread = new Thread(this); activeThread.start(); } } @Override public void start(int repeatCount) { synchronized (soundStack) { WavSoundPlayer active = getActive(); assert this.repeatsLeft == 0 && active != this; if (this.owner != null) { this.url = this.owner.getURL(); } boolean activeWasLoop = activeThread == null; boolean reuseLoop = active != null && activeWasLoop && repeatCount < 0 && active.playingSoundFile.equals(this.url.unalias()); if (active != null) { active.stop(reuseLoop); if (activeWasLoop) { soundStack.addElement(active); } } this.play(repeatCount, reuseLoop); } } @Override public void run() { synchronized (soundStack) { if (systemPaused > 0) { this.repeatsLeft = 0; return; } playingThreads++; } while (this.repeatsLeft > 0) { synchronized (soundStack) { if (activeThread != Thread.currentThread()) { break; } if (this.repeatsLeft > 0) { this.repeatsLeft--; } } this.nativePlay(false); } synchronized (soundStack) { if (activeThread == Thread.currentThread()) { assert getActive() == this; soundStack.removeElement(this); activeThread = null; WavSoundPlayer active = getActive(); if (active != null) { active.play(-1, false); } } playingThreads--; soundStack.notifyAll(); } } private void stop(boolean leaveLoopRunning) { if (getActive() == this) { boolean isLoop = activeThread == null; assert this.repeatsLeft < 0 && isLoop || !leaveLoopRunning; this.repeatsLeft = 0; if (!leaveLoopRunning && isLoop && systemPaused == 0) { this.nativeStop(); } activeThread = null; } soundStack.removeElement(this); } @Override public void stop() { synchronized (soundStack) { if (getActive() == this) { this.stop(false); WavSoundPlayer active = getActive(); if (active != null) { active.play(-1, false); } } else { soundStack.removeElement(this); } } } public static void pauseSystem() { pauseSystemExceptASF(); } public static void pauseSystemExceptASF() { synchronized (soundStack) { WavSoundPlayer active = getActive(); boolean isLoop = activeThread == null; if (active != null) { if (isLoop) { active.nativeStop(); } else { active.stop(false); } } systemPaused++; if (active != null) { active.play(-1, false); } while (playingThreads > 0) { try { soundStack.wait(); } catch (InterruptedException var4) { } } } } public static void resumeSystem() { resumeSystemExceptASF(); } public static void resumeSystemExceptASF() { synchronized (soundStack) { if (systemPaused > 0) { systemPaused = 0; WavSoundPlayer active = getActive(); if (active != null && activeThread == null) { active.play(-1, false); } } } } public void volume(float left, float right) { if (!ignoreVolumeChanges) { synchronized (soundStack) { if (getActive() == this && (lastLeftVol != left || lastRightVol != right)) { lastLeftVol = left; lastRightVol = right; this.nativeVolume(left, right); } } } } private native void nativePlay(boolean var1); private native void nativeVolume(float var1, float var2); private native void nativeStop(); }