diff options
| author | Fuwn <[email protected]> | 2026-02-12 22:33:32 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-12 22:33:32 -0800 |
| commit | c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9 (patch) | |
| tree | df9f48bf128a6c0186a8e91857d6ff30fe0e9f18 /NET/worlds/scape/Sound.java | |
| download | worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.tar.xz worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.zip | |
Initial commit
Diffstat (limited to 'NET/worlds/scape/Sound.java')
| -rw-r--r-- | NET/worlds/scape/Sound.java | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/NET/worlds/scape/Sound.java b/NET/worlds/scape/Sound.java new file mode 100644 index 0000000..aa9d5a3 --- /dev/null +++ b/NET/worlds/scape/Sound.java @@ -0,0 +1,623 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.IniFile; +import NET.worlds.network.CacheFile; +import NET.worlds.network.URL; +import java.io.IOException; +import java.util.Vector; + +public class Sound extends Action implements BGLoaded, StateContext { + static int debugLevel = IniFile.gamma().getIniInt("sounddebug", 0); + private String cachedName; + private URL soundURL; + protected CacheFile cachedFile = null; + protected float soundVolume = 1.0F; + protected float stopDistance = 1000.0F; + private int repeat = 1; + private boolean continuous = false; + private boolean attenuateOn = true; + private boolean panningOn = true; + protected SuperRoot activeSeq; + SoundPlayer player; + AudibilityFilter aFilter = null; + private int maxHopcount = 1; + private boolean doorMovementFlag = false; + private static boolean soundOn = true; + boolean playAfterLoading = true; + protected int state = 0; + protected static final int SYNC = 1; + protected static final int ASYNC = 2; + protected int backgroundState = 1; + private static SoundCallback closer; + static Vector cachedEntries; + private static Vector pendingEntries; + private boolean mainRan; + private boolean opened; + private static Object classCookie = new Object(); + + static { + debugOut(1, "SOUND DEBUGGING LEVEL = " + debugLevel); + } + + private static void debugOut(int n, String s) { + if (debugLevel > n) { + System.out.println(s); + } + } + + public Sound(URL soundURL) { + Transform.countClass(this, 1); + debugOut(9, "Sound " + soundURL); + this.setURL(soundURL); + } + + public Sound() { + Transform.countClass(this, 1); + debugOut(9, "Sound "); + this.setURL(null); + } + + public final void setURL(URL url) { + if (this.activeSeq != null) { + this.closePlayer(); + } + + this.soundURL = url; + } + + public final URL getURL() { + return this.soundURL; + } + + public final void setSoundVolume(float vol) { + this.soundVolume = vol; + } + + public final float getSoundVolume() { + return this.soundVolume; + } + + public final void setStopDistance(float i) { + this.stopDistance = i; + } + + public final float getStopDistance() { + return this.stopDistance; + } + + public final void setRepeat(int i) { + this.repeat = i; + } + + public final int getRepeat() { + return this.repeat; + } + + public final void setContinuous(boolean c) { + this.continuous = c; + } + + public final boolean isContinuous() { + return this.continuous; + } + + public final void setAttenuate(boolean b) { + this.attenuateOn = b; + } + + public final boolean getAttenuate() { + return this.attenuateOn; + } + + public final void setPanning(boolean b) { + this.panningOn = b; + } + + public final boolean getPanning() { + return this.panningOn; + } + + public final int getState() { + return this.player.getState(); + } + + public final int getHopcount() { + return this.maxHopcount; + } + + public final void setHopcount(int i) { + this.maxHopcount = i; + if (this.aFilter != null) { + this.aFilter.setHopcount(this.maxHopcount); + } + } + + public boolean getDoorMovementFlag() { + return this.doorMovementFlag; + } + + public void setDoorMovementFlag(boolean b) { + this.doorMovementFlag = b; + if (this.aFilter != null) { + this.startAudibilityFilter(); + } + } + + private void startAudibilityFilter() { + debugOut(9, "startAudibilityFilter " + this.getURL()); + WObject owner = (WObject)this.getOwner(); + if (owner != null) { + if (this.doorMovementFlag) { + this.aFilter = new DoorBasedFilter(this, owner, this.maxHopcount, this.stopDistance); + } else { + this.aFilter = new AudibilityFilter(this, owner, this.maxHopcount); + } + + this.aFilter.moveEmitter(); + } + } + + public static void turnSoundOn() { + soundOn = true; + } + + public static void turnSoundOff() { + soundOn = false; + } + + public void setPlayAfterLoading(boolean b) { + this.playAfterLoading = b; + } + + protected boolean isRealAudio(URL s) { + return s.endsWith(".ram") || s.endsWith(".ra") || s.endsWith(".rm"); + } + + @Override + public void changeState(int s) { + debugOut(9, "changeState to " + s); + this.state = s; + } + + protected Object doState(Object obj) { + return SoundState.instance().doState(this, obj); + } + + private boolean isBackgroundProcessing() { + if (this.state != 0) { + debugOut(9, "backgroundProcessing " + this.state); + } + + return this.state != 0; + } + + private void startSound() { + this.backgroundState = 1; + if (this.aFilter == null) { + this.startAudibilityFilter(); + } + + if (this.aFilter != null) { + this.aFilter.setEmitterOn(true); + } + + if (this.state == 0) { + this.state = 1; + } + + this.doState(this.soundURL); + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteName) { + this.backgroundState = 2; + return this.doState(URL.make(localName)); + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + this.backgroundState = 1; + this.doState(obj); + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + WObject owner = (WObject)this.getOwner(); + return owner == null ? null : owner.getRoom(); + } + + protected void ensureClosure() { + if (closer == null) { + closer = new SoundCallback(); + Main.register(closer); + } + + if (cachedEntries == null) { + cachedEntries = new Vector(); + } + + cachedEntries.addElement(this.cachedFile); + } + + protected void unlockCache() { + if (this.cachedFile != null) { + debugOut(6, "unlocking " + this.soundURL); + this.cachedFile.finalize(); + + assert cachedEntries != null; + + assert cachedEntries.indexOf(this.cachedFile, 0) >= 0; + + cachedEntries.removeElement(this.cachedFile); + this.cachedFile = null; + } + } + + synchronized boolean openPlayer(URL url) { + assert this.player == null; + + this.cachedName = url.unalias(); + debugOut(4, "openPlayer on:: " + this.cachedName); + if (url.endsWith(".wav")) { + this.player = new WavSoundPlayer(this); + } else if (url.endsWith(".mid")) { + this.player = new MCISoundPlayer(this); + } else { + this.player = new WMPSoundPlayer(this); + } + + if (Main.isMainThread()) { + this.openInMainThread(); + } else { + this.mainRan = false; + Main.register(new MainCallback() { + @Override + public void mainCallback() { + Sound.this.openInMainThread(); + Main.unregister(this); + } + }); + + while (!this.mainRan) { + try { + this.wait(); + } catch (InterruptedException var3) { + } + } + } + + return this.opened; + } + + public synchronized void openInMainThread() { + this.opened = this.player.open(this.soundVolume, this.stopDistance, this.attenuateOn, this.panningOn); + if (!this.opened) { + this.closePlayer(); + } + + this.mainRan = true; + this.notify(); + } + + void closePlayer() { + if (this.player != null) { + this.player.stop(); + this.unlockCache(); + if (SoundResource.instance().syncUnlock()) { + this.player.close(); + } + + this.player = null; + } + + debugOut(2, " closePlayer"); + } + + @Override + public Persister trigger(Event e, Persister seqID) { + debugOut(9, "trigger in: seqID " + seqID + " activeSeq " + this.activeSeq); + if (this.isBackgroundProcessing()) { + return this.activeSeq; + } else { + if (seqID == null) { + if (this.soundURL == null || this.getOwner() == null) { + return null; + } + + if (this.activeSeq != null) { + this.closePlayer(); + } + + this.activeSeq = this; + Persister var3 = this.activeSeq; + debugOut(6, "triggering new sound " + var3); + this.startSound(); + } else if (seqID != this.activeSeq) { + this.unlockCache(); + if (!this.isContinuous()) { + this.aFilter.setEmitterOn(false); + } + + return null; + } + + if (this.player != null && this.player.getState() != 0 && !this.isContinuous()) { + this.aFilter.setEmitterOn(false); + } + + if ((this.isBackgroundProcessing() || this.updateSound() && this.player.getState() == 0) && this.getOwner() != null) { + return this.activeSeq; + } else { + this.activeSeq = null; + this.closePlayer(); + return null; + } + } + } + + boolean updateSound() { + debugOut(9, "Sound::updateSound:: in"); + if (this.player == null) { + debugOut(6, "update returning false because player is null"); + return false; + } else if (!SoundResource.instance().isOK()) { + debugOut(2, "update registering not OK"); + return false; + } else if (!this.aFilter.isAudible()) { + debugOut(4, "update stopping sound because isAudible false"); + return false; + } else { + Point3Temp pilot = Point3Temp.make(); + Point3Temp up = Point3Temp.make(); + Point3Temp forward = Point3Temp.make(); + Point3Temp obj = Point3Temp.make(); + this.aFilter.getListenerPosition(pilot, up, forward); + this.aFilter.getEmitterPosition(obj); + if (!this.player.position(pilot, obj, forward, up)) { + debugOut(6, "update returning false because position false"); + return false; + } else { + float vol = -1.0F; + if (soundOn) { + vol = this.aFilter.getEmitterVolume(); + } + + if (!this.player.setVolume(vol * this.soundVolume)) { + debugOut(6, "update returning false because volume false"); + return false; + } else { + return true; + } + } + } + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + this.startAudibilityFilter(); + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + Object ret = null; + switch (index - offset) { + case 0: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Sound File URL").allowSetNull(), "asf;wav;mid;ram;ra;rm;mp3"); + } else if (mode == 1) { + ret = this.soundURL; + } else if (mode == 2) { + this.soundURL = (URL)value; + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Max Volume")); + } else if (mode == 1) { + ret = new Float(this.soundVolume); + } else if (mode == 2) { + this.soundVolume = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Stop Distance")); + } else if (mode == 1) { + ret = new Float(this.stopDistance); + } else if (mode == 2) { + this.stopDistance = (Float)value; + } + break; + case 3: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Times to Repeat")); + } else if (mode == 1) { + ret = new Integer(this.repeat); + } else if (mode == 2) { + this.repeat = (Integer)value; + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Attenuate With Distance"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.attenuateOn); + } else if (mode == 2) { + this.attenuateOn = (Boolean)value; + } + break; + case 5: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Do panning"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.panningOn); + } else if (mode == 2) { + this.panningOn = (Boolean)value; + } + break; + case 6: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Room hops till sound dies")); + } else if (mode == 1) { + ret = new Integer(this.maxHopcount); + } else if (mode == 2) { + this.setHopcount((Integer)value); + } + break; + case 7: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Door based audibility"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getDoorMovementFlag()); + } else if (mode == 2) { + this.setDoorMovementFlag((Boolean)value); + } + break; + case 8: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Play after loading"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.playAfterLoading); + } else if (mode == 2) { + this.setPlayAfterLoading((Boolean)value); + } + break; + case 9: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Loop Infinite"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.continuous); + } else if (mode == 2) { + this.setContinuous((Boolean)value); + } + break; + default: + ret = super.properties(index, offset + 10, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(7, classCookie); + s.saveBoolean(this.playAfterLoading); + s.saveBoolean(this.doorMovementFlag); + s.saveBoolean(this.panningOn); + s.saveBoolean(this.attenuateOn); + s.saveInt(this.maxHopcount); + super.saveState(s); + URL.save(s, this.soundURL); + s.saveFloat(this.soundVolume); + s.saveFloat(this.stopDistance); + s.saveInt(this.repeat); + s.saveBoolean(this.continuous); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + this.setURL(URL.restore(r)); + break; + case 1: + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 2: + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 3: + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 4: + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 5: + this.setPlayAfterLoading(r.restoreBoolean()); + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 6: + this.setPlayAfterLoading(r.restoreBoolean()); + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 7: + this.setPlayAfterLoading(r.restoreBoolean()); + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + this.setContinuous(r.restoreBoolean()); + break; + default: + throw new TooNewException(); + } + + if (vers < 6 && this.continuous) { + this.setContinuous(false); + } + } +} |