Пример #1
0
        internal bool INTERNAL_update()
        {
            // If we're not running, save some instructions...
            if (!INTERNAL_timer.IsRunning)
            {
                return(true);
            }

            // Play events when the timestamp has been hit.
            for (int i = 0; i < INTERNAL_eventList.Count; i += 1)
            {
                if (!INTERNAL_eventPlayed[i] &&
                    INTERNAL_timer.ElapsedMilliseconds > INTERNAL_eventList[i].Timestamp)
                {
                    uint type = INTERNAL_eventList[i].Type;
                    if (type == 1)
                    {
                        PlayWave((PlayWaveEvent)INTERNAL_eventList[i]);
                    }
                    else if (type == 2)
                    {
                        // FIXME: SetVariable, or apply instanceVolumes? -flibit
                        SetVariable(
                            "Volume",
                            ((SetVolumeEvent)INTERNAL_eventList[i]).GetVolume()
                            );
                    }
                    else
                    {
                        throw new Exception("Unhandled XACTEvent type!");
                    }
                    INTERNAL_eventPlayed[i] = true;
                }
            }

            // Clear out sound effect instances as they finish
            for (int i = 0; i < INTERNAL_instancePool.Count; i += 1)
            {
                if (INTERNAL_instancePool[i].State == SoundState.Stopped)
                {
                    // Get the event that spawned this instance...
                    PlayWaveEvent evt = (PlayWaveEvent)INTERNAL_waveEventSounds[INTERNAL_instancePool[i]];

                    // Then delete all the guff
                    INTERNAL_waveEventSounds.Remove(INTERNAL_instancePool[i]);
                    INTERNAL_instancePool[i].Dispose();
                    INTERNAL_instancePool.RemoveAt(i);
                    INTERNAL_instanceVolumes.RemoveAt(i);
                    INTERNAL_instancePitches.RemoveAt(i);
                    INTERNAL_rpcTrackVolumes.RemoveAt(i);
                    INTERNAL_rpcTrackPitches.RemoveAt(i);

                    // Increment the loop counter, try to get another loop
                    INTERNAL_eventLoops[evt] += 1;
                    PlayWave(evt);

                    // Removed a wave, have to step back...
                    i -= 1;
                }
            }

            // User control updates
            if (INTERNAL_data.IsUserControlled)
            {
                string varName = INTERNAL_data.UserControlVariable;
                if (INTERNAL_userControlledPlaying &&
                    (INTERNAL_baseEngine.INTERNAL_isGlobalVariable(varName) ?
                     !MathHelper.WithinEpsilon(INTERNAL_controlledValue, INTERNAL_baseEngine.GetGlobalVariable(varName)) :
                     !MathHelper.WithinEpsilon(INTERNAL_controlledValue, GetVariable(INTERNAL_data.UserControlVariable))))
                {
                    // TODO: Crossfading
                    foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
                    {
                        sfi.Stop();
                        sfi.Dispose();
                    }
                    INTERNAL_instancePool.Clear();
                    INTERNAL_instanceVolumes.Clear();
                    INTERNAL_instancePitches.Clear();
                    INTERNAL_rpcTrackVolumes.Clear();
                    INTERNAL_rpcTrackPitches.Clear();
                    if (!INTERNAL_calculateNextSound())
                    {
                        // Nothing to play, bail.
                        return(true);
                    }
                    INTERNAL_activeSound.GatherEvents(INTERNAL_eventList);
                    foreach (XACTEvent evt in INTERNAL_eventList)
                    {
                        INTERNAL_eventPlayed.Add(false);
                        INTERNAL_eventLoops.Add(evt, 0);
                    }
                    INTERNAL_timer.Stop();
                    INTERNAL_timer.Reset();
                    INTERNAL_timer.Start();
                }

                if (INTERNAL_activeSound == null)
                {
                    return(INTERNAL_userControlledPlaying);
                }
            }

            // If everything has been played and finished, we're done here.
            if (INTERNAL_instancePool.Count == 0)
            {
                bool allPlayed = true;
                foreach (bool played in INTERNAL_eventPlayed)
                {
                    if (!played)
                    {
                        allPlayed = false;
                        break;
                    }
                }
                if (allPlayed)
                {
                    // If this is managed, we're done completely.
                    if (INTERNAL_isManaged)
                    {
                        Dispose();
                    }
                    else
                    {
                        INTERNAL_timer.Stop();
                        INTERNAL_timer.Reset();
                        INTERNAL_category.INTERNAL_removeActiveCue(this);
                    }
                    return(INTERNAL_userControlledPlaying);
                }
            }

            // RPC updates
            float rpcVolume = 1.0f;
            float rpcPitch  = 0.0f;
            float hfGain    = 1.0f;
            float lfGain    = 1.0f;

            for (int i = 0; i < INTERNAL_activeSound.RPCCodes.Count; i += 1)
            {
                if (i > INTERNAL_instancePool.Count)
                {
                    break;
                }
                if (i > 0)
                {
                    INTERNAL_rpcTrackVolumes[i - 1] = 1.0f;
                    INTERNAL_rpcTrackPitches[i - 1] = 0.0f;
                }
                foreach (uint curCode in INTERNAL_activeSound.RPCCodes[i])
                {
                    RPC   curRPC = INTERNAL_baseEngine.INTERNAL_getRPC(curCode);
                    float result;
                    if (!INTERNAL_baseEngine.INTERNAL_isGlobalVariable(curRPC.Variable))
                    {
                        result = curRPC.CalculateRPC(GetVariable(curRPC.Variable));
                    }
                    else
                    {
                        // It's a global variable we're looking for!
                        result = curRPC.CalculateRPC(
                            INTERNAL_baseEngine.GetGlobalVariable(
                                curRPC.Variable
                                )
                            );
                    }
                    if (curRPC.Parameter == RPCParameter.Volume)
                    {
                        float vol = XACTCalculator.CalculateAmplitudeRatio(result / 100.0);
                        if (i == 0)
                        {
                            rpcVolume *= vol;
                        }
                        else
                        {
                            INTERNAL_rpcTrackVolumes[i - 1] *= vol;
                        }
                    }
                    else if (curRPC.Parameter == RPCParameter.Pitch)
                    {
                        float pitch = result / 1000.0f;
                        if (i == 0)
                        {
                            rpcPitch += pitch;
                        }
                        else
                        {
                            INTERNAL_rpcTrackPitches[i - 1] += pitch;
                        }
                    }
                    else if (curRPC.Parameter == RPCParameter.FilterFrequency)
                    {
                        // FIXME: Just listening to the last RPC!
                        float hf = result / 20000.0f;
                        float lf = 1.0f - hfGain;
                        if (i == 0)
                        {
                            hfGain = hf;
                            lfGain = lf;
                        }
                        else
                        {
                            throw new NotImplementedException("Per-track filter RPCs!");
                        }
                    }
                    else
                    {
                        throw new Exception("RPC Parameter Type: " + curRPC.Parameter.ToString());
                    }
                }
            }

            // Sound effect instance updates
            float cueVolume = GetVariable("Volume");

            for (int i = 0; i < INTERNAL_instancePool.Count; i += 1)
            {
                /* The final volume should be the combination of the
                 * authored volume, Volume variable and RPC volume results.
                 */
                INTERNAL_instancePool[i].Volume = (
                    INTERNAL_instanceVolumes[i] *
                    cueVolume *
                    rpcVolume *
                    INTERNAL_rpcTrackVolumes[i]
                    );

                /* The final pitch should be the combination of the
                 * authored pitch and RPC pitch results.
                 */
                INTERNAL_instancePool[i].Pitch = (
                    INTERNAL_instancePitches[i] +
                    rpcPitch +
                    INTERNAL_rpcTrackPitches[i]
                    );

                /* The final filter is determined by the instance's filter type,
                 * in addition to our calculation of the HF/LF gain values.
                 */
                INTERNAL_instancePool[i].INTERNAL_applyFilter(
                    INTERNAL_baseEngine.Filter,
                    hfGain,
                    lfGain
                    );

                // Update 3D position, if applicable
                if (INTERNAL_isPositional)
                {
                    INTERNAL_instancePool[i].Apply3D(
                        INTERNAL_listener,
                        INTERNAL_emitter
                        );
                }
            }

            return(true);
        }