📄 soundscheduler.java
字号:
/* * $RCSfile: SoundScheduler.java,v $ * * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Use is subject to license terms. * * $Revision: 1.10 $ * $Date: 2007/04/12 17:34:06 $ * $State: Exp $ */package javax.media.j3d;import javax.vecmath.*;import java.lang.Math;import java.util.Vector;import java.util.ArrayList;import java.net.URL;import java.io.InputStream;import java.util.Enumeration;import java.util.Arrays;import java.awt.*;import java.awt.event.*;/** * This structure parallels the RenderBin structure and * is used for sounds */class SoundScheduler extends J3dStructure { /** * The View that owns this SoundScheduler */ View view = null; /** * This boolean tells the thread to suspend itself. * This is true ONLY when everythings ready to render using run loop */ boolean ready = false; /** * The ViewPlatform that is associated with this SoundScheduler */ ViewPlatformRetained viewPlatform = null; /** * The GraphicContext3D that we are currently unning in. */ GraphicsContext3D graphicsCtx = null; /** * Maintain what reference to the last AuralAttributes found active * was so that only if there was a change do we need to reset these * parameters in the AudioDevice3D. */ AuralAttributesRetained lastAA = null; /** * Since AuralAttribute gain scale factor is multipled with sound's * initialGain scale factor, any change in AuralAttrib gain scale * factor should force an update of all active sounds' gains * Also, change in AuralAttributes should force a sound update * even if no other sound field changes occurred. */ boolean resetAA = true; /** * Audio Device */ AudioDevice audioDevice = null; AudioDevice3D audioDevice3D = null; AudioDevice3DL2 audioDevice3DL2 = null; int totalChannels = 0; /** * Array of SoundScapeRetained nodes that intersect the viewPlatform * This list is a subset of the soundscapes array, and is used when * selecting the closest Soundscape. * Maintained as an expandable array. */ SoundscapeRetained[] intersectedSoundscapes = new SoundscapeRetained[32]; /** * Array of Bounds nodes for the corresponding intersectedSoundscapes * array. This array is used when selecting the closest Soundscape. * This list is used when selecting the closest Soundscape. * Maintained as an expandable array. */ Bounds[] intersectedRegions = new Bounds[32]; /** * Reference to last processed region within run(). * Maintained to avoid re-transforming this bounds. */ Bounds region = null; /** * An array of prioritized sounds currently playing "live" sounds. * This prioritized sound list is NO longer re-create instead sounds * are insert, shuffled or removed as messages are processed. */ // XXXX: (Enhancement) should have a seperate list for // background sound and a list for positional sounds ArrayList prioritizedSounds = new ArrayList(); /** * Current number of scene graph sound nodes in the universe */ int nRetainedSounds = -1; // none calculated yet /** * Current number of immediate mode sound nodes in the universe */ int nImmedSounds = -1; // none calculated yet /** * Current active (selected) attribute node in the sceneGraph */ AuralAttributesRetained aaRetained = null; // variables for processing transform messages boolean transformMsg = false; UpdateTargets targets = null; /** * Current active (selected) attribute node in the sceneGraph */ AuralAttributesRetained aaImmed = null; // Dirty flags for fields and parameters that are unique to the // Sound Scheduler or the Audio Device // Any listener (body) and/or view transform changes processed in // CanvasViewCache force one of these flags to be set. static final int EAR_POSITIONS_CHANGED = 0x0001; static final int EYE_POSITIONS_CHANGED = 0x0002; static final int IMAGE_PLATE_TO_VWORLD_CHANGED = 0x0004; static final int HEAD_TO_VWORLD_CHANGED = 0x0008; static final int LISTENER_CHANGED = 0x000F;// all of the above private int listenerUpdated = LISTENER_CHANGED; /** * Temporary flag that's denotes that a positional sound was processed * in the current loop of renderChange(). */ private boolean positionalSoundUpdated = false; /** * Temporary flag that's denotes that some field auralAttribute was changed */ private boolean auralAttribsChanged = true; // force processing 1st x private boolean stallThread = false; int lastEventReceived = WindowEvent.WINDOW_CLOSED; /** * Constructs a new SoundScheduler */ SoundScheduler(VirtualUniverse u, View v) { super(u, J3dThread.SOUND_SCHEDULER); // Assertion check view & universe if (v == null) { System.err.println("WARNING: SoundScheduler constructed with null view"); } if (u == null) { System.err.println("WARNING: SoundScheduler constructed with null universe"); } universe = u; view = v; reset(); } // NOTE: processMessage only called with updatethread.active true void processMessages(long referenceTime) { J3dMessage[] messages = getMessages(referenceTime); int nMsg = getNumMessage(); J3dMessage m; int nSounds; if (nMsg > 0) { for (int i=0; i < nMsg; i++) { m = messages[i]; switch (m.type) { case J3dMessage.INSERT_NODES: insertNodes(m); break; case J3dMessage.REMOVE_NODES: removeNodes(m); break; case J3dMessage.SOUND_ATTRIB_CHANGED: changeNodeAttrib(m); break; case J3dMessage.SOUND_STATE_CHANGED: changeNodeState(m); break; case J3dMessage.BOUNDINGLEAF_CHANGED: processBoundingLeafChanged(m); break; case J3dMessage.SOUNDSCAPE_CHANGED: SoundscapeRetained ss = (SoundscapeRetained)m.args[0]; if (universe.soundStructure.isSoundscapeScopedToView(ss, view)) { auralAttribsChanged = true; changeNodeAttrib(m); } break; case J3dMessage.AURALATTRIBUTES_CHANGED: auralAttribsChanged = true; changeNodeAttrib(m); break; case J3dMessage.MEDIA_CONTAINER_CHANGED: changeNodeAttrib(m); break; case J3dMessage.TRANSFORM_CHANGED: transformMsg = true; auralAttribsChanged = true; break; case J3dMessage.RENDER_IMMEDIATE: processImmediateNodes(m.args, referenceTime); break; case J3dMessage.VIEWSPECIFICGROUP_CHANGED: processViewSpecificGroupChanged(m); break; case J3dMessage.UPDATE_VIEW: if (debugFlag) debugPrint(".processMessage() UPDATE_VIEW"); // NOTE: can only rely on seeing UPDATE_VIEW when canvas [re]Created // AND when view deactivated... // NOTE: // temp work-around // calling prioritizeSounds() wipes out old atom fields // QUESTION: prioritizedSound is NEVER empty - why if size is 0 can // .isEmpty return anything but TRUE??? // if (prioritizedSounds.isEmpty()) { nSounds = prioritizeSounds(); } break; case J3dMessage.SWITCH_CHANGED: if (debugFlag) debugPrint(".processMessage() " + "SWITCH_CHANGED ignored"); break; } // switch m.decRefcount(); } // for if (transformMsg) { targets = universe.transformStructure.getTargetList(); updateTransformChange(targets, referenceTime); transformMsg = false; targets = null; } Arrays.fill(messages, 0, nMsg, null); } // Call renderChanges within try/catch so errors won't kill // the SoundScheduler. try { renderChanges(); } catch (RuntimeException e) { System.err.println("Exception occurred " + "during Sound rendering:"); e.printStackTrace(); } catch (Error e) { // Issue 264 - catch Error System.err.println("Error occurred " + "during Sound rendering:"); e.printStackTrace(); } // what if the user/app makes no change to scenegraph? // must still re-render after retest for sound complete // calculate which sound will finished first and set a // wait time to this shortest time so that scheduler is // re-entered to process sound complete. long waitTime = shortestTimeToFinish(); if (waitTime == 0L) { // come right back if (debugFlag) debugPrint(".processMessage calls sendRunMessage " + "for immediate processing"); VirtualUniverse.mc.sendRunMessage(universe, J3dThread.SOUND_SCHEDULER); } else if (waitTime > 0L) { // Use TimerThread to send message with sounds complete. // This uses waitForElapse time to sleep for at least the duration // returned by shortestTimeToFinish method. if (debugFlag) debugPrint(".processMessage calls sendRunMessage " + "with wait time = " + waitTime ); // QUESTION (ISSUE): even when this is set to a large time // processMessage is reentered immediately. // Why is timer thread not waiting?? VirtualUniverse.mc.sendRunMessage(waitTime, view, J3dThread.SOUND_SCHEDULER); } } void insertNodes(J3dMessage m) { Object[] nodes = (Object[])m.args[0]; ArrayList viewScopedNodes = (ArrayList)m.args[3]; ArrayList scopedNodesViewList = (ArrayList)m.args[4]; Object node; for (int i=0; i<nodes.length; i++) { node = (Object) nodes[i]; if (node instanceof SoundRetained) { nRetainedSounds++; // insert sound node into sound scheduler's prioritized list addSound((SoundRetained) node); } else if (node instanceof SoundscapeRetained) { auralAttribsChanged = true; } else if (node instanceof AuralAttributesRetained) { auralAttribsChanged = true; } else if (node instanceof ViewPlatformRetained) { // XXXX: don't support multiple viewPlatforms per scheduler /* // useful for resetting VP ?? addViewPlatform((ViewPlatformRetained) node); */ if (debugFlag) { debugPrint(".insertNodes() viewPlatformRetained not supported yet"); } } } // Handle ViewScoped Nodes if (viewScopedNodes != null) { int size = viewScopedNodes.size(); int vlsize; for (int i = 0; i < size; i++) { node = (NodeRetained)viewScopedNodes.get(i); ArrayList vl = (ArrayList) scopedNodesViewList.get(i); // If the node object is scoped to this view, then .. if (vl.contains(view)) { if (node instanceof SoundRetained) { nRetainedSounds++; // insert sound node into sound scheduler's prioritized list addSound((SoundRetained) node); } else if (node instanceof SoundscapeRetained) { auralAttribsChanged = true; } } } } } /** * Add sound to sounds list. */ void addSound(SoundRetained sound) { if (sound == null) return; if (debugFlag) debugPrint(".addSound()"); synchronized (prioritizedSounds) { addPrioritizedSound(sound); } } // end addSound /** * Node removed from tree */ void removeNodes(J3dMessage m) { Object[] nodes = (Object[])m.args[0]; ArrayList viewScopedNodes = (ArrayList)m.args[3]; ArrayList scopedNodesViewList = (ArrayList)m.args[4]; Object node; for (int i=0; i<nodes.length; i++) { node = (Object) nodes[i]; if (node instanceof SoundRetained) { // sound is deactivated but NOT deleted // incase sound is reattached// QUESTION: what's the difference in messages between really deleting// a node and just deactivating it./*//// can't delete atom in case it's reactivitated// nRetainedSounds--; deleteSound((SoundRetained) node);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -