示例#1
0
        /// <summary>
        /// If exist, immediately stop and destroy all effects with given parameters.
        /// </summary>
        public static TR_AUDIO_SEND Kill(int effectID, TR_AUDIO_EMITTER emitterType = TR_AUDIO_EMITTER.Global, int emitterID = 0)
        {
            var playingSound = IsEffectPlaying(effectID, emitterType, emitterID);

            if(playingSound != -1)
            {
                EngineWorld.AudioSources[playingSound].Stop();
                return TR_AUDIO_SEND.Processed;
            }

            return TR_AUDIO_SEND.Ignored;
        }
示例#2
0
        public static int IsEffectPlaying(int effectID = -1, TR_AUDIO_EMITTER emitterType = TR_AUDIO_EMITTER.Unknown, int emitterID = -1)
        {
            for (var i = 0; i < EngineWorld.AudioSources.Count; i++)
            {
                var c = EngineWorld.AudioSources[i];
                if((effectID == -1 || effectID == c.EffectIndex) &&
                    (emitterType == TR_AUDIO_EMITTER.Unknown || emitterType == c.EmitterType) &&
                    (emitterID == -1 || emitterID == c.EmitterID))
                {
                    if (c.IsPlaying) return i;
                }
            }

            return -1;
        }
示例#3
0
        /// <summary>
        /// Send to play effect with given parameters.
        /// </summary>
        public static TR_AUDIO_SEND Send(uint effectID, TR_AUDIO_EMITTER emitterType = TR_AUDIO_EMITTER.Global,
            int emitterID = 0)
        {
            var sourceNumber = 0;
            AudioEffect effect;

            // If there are no audio buffers or effect index is wrong, don't process.

            if (EngineWorld.AudioBuffers.Length == 0 || effectID < 0) return TR_AUDIO_SEND.Ignored;

            // Remap global engine effect ID to local effect ID.

            if (effectID >= EngineWorld.AudioMap.Count)
            {
                return TR_AUDIO_SEND.NoSample; // Sound is out of bounds; stop.
            }

            var realID = (int) EngineWorld.AudioMap[(int) effectID];

            // Pre-step 1: if there is no effect associated with this ID, bypass audio send.

            if (realID == -1)
            {
                return TR_AUDIO_SEND.Ignored;
            }
            else
            {
                effect = EngineWorld.AudioEffects[realID];
            }

            // Pre-step 2: check if sound non-looped and chance to play isn't zero,
            // then randomly select if it should be played or not.

            if (effect.Loop != LoopType.Forward && effect.Chance > 0)
            {
                if (effect.Chance < Helper.CPPRand() % 0x7FFF)
                {
                    // Bypass audio send, if chance test is not passed.
                    return TR_AUDIO_SEND.Ignored;
                }
            }

            // Pre-step 3: Calculate if effect's hearing sphere intersect listener's hearing sphere.
            // If it's not, bypass audio send (cause we don't want it to occupy channel, if it's not
            // heard).

            if (!IsInRange(emitterType, emitterID, effect.Range, effect.Gain))
            {
                return TR_AUDIO_SEND.Ignored;
            }

            // Pre-step 4: check if R (Rewind) flag is set for this effect, if so,
            // find any effect with similar ID playing for this entity, and stop it.
            // Otherwise, if W (Wait) or L (Looped) flag is set, and same effect is
            // playing for current entity, don't send it and exit function.

            sourceNumber = IsEffectPlaying((int) effectID, emitterType, emitterID);

            if (sourceNumber != -1)
            {
                if (effect.Loop == LoopType.PingPong)
                {
                    EngineWorld.AudioSources[sourceNumber].Stop();
                }
                else if (effect.Loop != LoopType.None) // Any other looping case (Wait / Loop).
                {
                    return TR_AUDIO_SEND.Ignored;
                }
            }
            else
            {
                sourceNumber = GetFreeSource(); // Get free source
            }

            if (sourceNumber != -1) // Everything is OK, we're sending audio to channel.
            {
                var bufferIndex = 0;

                // Step 1. Assign buffer to source.

                if (effect.SampleCount > 1)
                {
                    // Select random buffer, if effect info contains more than 1 assigned samples.
                    bufferIndex = unchecked((int) (Helper.CPPRand() % effect.SampleCount + effect.SampleIndex));
                }
                else
                {
                    // Just assign buffer to source, if there is only one assigned sample.
                    bufferIndex = (int) effect.SampleIndex;
                }

                var source = EngineWorld.AudioSources[sourceNumber];

                source.SetBuffer(bufferIndex);

                // Step 2. Check looped flag, and if so, set source type to looped.

                source.IsLooping = effect.Loop == LoopType.Forward;

                // Step 3. Apply internal sound parameters.

                source.EmitterID = emitterID;
                source.EmitterType = emitterType;
                source.EffectIndex = effectID;

                // Step 4. Apply sound effect properties.

                source.Pitch = effect.Pitch;
                if (effect.RandomizePitch) // Vary pitch, if flag is set.
                {
                    source.Pitch += (Helper.CPPRand() % effect.RandomizePitchVar - 25.0f) / 200.0f;
                }

                source.Gain = effect.Gain;
                if (effect.RandomizeGain) // Vary gain, if flag is set.
                {
                    source.Gain += (Helper.CPPRand() % effect.RandomizeGainVar - 25.0f) / 200.0f;
                }

                source.SetRange(effect.Range); // Set audible range

                source.Play(); // Everything is OK, play sound now!

                return TR_AUDIO_SEND.Processed;
            }

            return TR_AUDIO_SEND.NoChannel;
        }
示例#4
0
        public static bool IsInRange(TR_AUDIO_EMITTER emitterType, int entityID, float range, float gain)
        {
            var vec = Vector3.Zero;

            switch (emitterType)
            {
                case TR_AUDIO_EMITTER.Entity:
                    var ent = EngineWorld.GetEntityByID((uint)entityID);
                    if (ent == null) return false;
                    vec = ent.Transform.Origin;
                    break;
                case TR_AUDIO_EMITTER.SoundSource:
                    if ((uint) entityID + 1 > EngineWorld.AudioEmitters.Count) return false;
                    vec = EngineWorld.AudioEmitters[entityID].Position;
                    break;
                case TR_AUDIO_EMITTER.Global:
                    return true;
                default:
                    return false;
            }

            // We add 1/4 of overall distance to fix up some issues with
            // pseudo-looped sounds that are called at certain frames in animations.

            var dist = (ListenerPosition - vec).LengthSquared / (gain + 1.25f);

            return dist < range * range;
        }