Esempio n. 1
0
        public SoundEffectInstance GenerateInstance(
            double soundVolume,
            float soundPitch,
            int currentLoop
            )
        {
            if (currentLoop > INTERNAL_loopCount && INTERNAL_loopCount != 255)
            {
                // We've finished all the loops!
                return(null);
            }
            INTERNAL_getNextSound();
            SoundEffectInstance result = INTERNAL_waves[INTERNAL_curWave].CreateInstance();

            result.INTERNAL_isXACTSource = true;
            result.Volume = XACTCalculator.CalculateAmplitudeRatio(
                soundVolume + (
                    random.NextDouble() *
                    (INTERNAL_maxVolume - INTERNAL_minVolume)
                    ) + INTERNAL_minVolume
                );
            result.Pitch = (
                random.Next(
                    INTERNAL_minPitch,
                    INTERNAL_maxPitch
                    ) / 1000.0f
                ) + soundPitch;
            result.FilterType = INTERNAL_filterType;
            result.IsLooped   = !INTERNAL_variationOnLoop && (INTERNAL_loopCount == 255);
            return(result);
        }
Esempio n. 2
0
        public SoundEffectInstance GenerateInstance(
            double soundVolume,
            float soundPitch
            )
        {
            INTERNAL_getNextSound();
            SoundEffectInstance result = INTERNAL_waves[INTERNAL_curWave].CreateInstance();

            result.INTERNAL_isXACTSource = true;
            result.INTERNAL_delayMS      = Timestamp;
            result.Volume = XACTCalculator.CalculateAmplitudeRatio(
                soundVolume + (
                    random.NextDouble() *
                    (INTERNAL_maxVolume - INTERNAL_minVolume)
                    ) + INTERNAL_minVolume
                );
            result.Pitch = (
                random.Next(
                    INTERNAL_minPitch,
                    INTERNAL_maxPitch
                    ) / 1000.0f
                ) + soundPitch;
            result.FilterType = INTERNAL_filterType;
            // FIXME: Better looping!
            result.IsLooped = (INTERNAL_loopCount == 255);
            return(result);
        }
Esempio n. 3
0
File: Cue.cs Progetto: raizam/FNA
        internal float INTERNAL_calculateVolume()
        {
            float retval = 1.0f;

            for (int i = 0; i < INTERNAL_activeSound.RPCCodes.Count; i += 1)
            {
                foreach (uint curCode in INTERNAL_activeSound.RPCCodes[i])
                {
                    RPC curRPC = INTERNAL_baseEngine.INTERNAL_getRPC(curCode);
                    if (curRPC.Parameter != RPCParameter.Volume)
                    {
                        continue;
                    }
                    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
                                )
                            );
                    }
                    retval *= XACTCalculator.CalculateAmplitudeRatio(result / 100.0);
                }
            }
            return(retval);
        }
Esempio n. 4
0
 public void SetHighEQGain(float value)
 {
     EFX.alEffectf(
         effectHandle,
         EFX.AL_EAXREVERB_GAINHF,
         XACTCalculator.CalculateAmplitudeRatio(
             value - 8.0f
             )
         );
 }
Esempio n. 5
0
 public void SetReverbHighEQGain(IALReverb reverb, float value)
 {
     EFX.alEffectf(
         (reverb as OpenALReverb).EffectHandle,
         EFX.AL_EAXREVERB_GAINHF,
         XACTCalculator.CalculateAmplitudeRatio(
             value - 8.0f
             )
         );
 }
Esempio n. 6
0
        public SoundEffectInstance GenerateInstance(
            double soundVolume,
            float soundPitch,
            int currentLoop,
            float?prevVolume,
            float?prevPitch
            )
        {
            if (currentLoop > INTERNAL_loopCount && INTERNAL_loopCount != 255)
            {
                // We've finished all the loops!
                return(null);
            }
            INTERNAL_getNextSound();
            SoundEffectInstance result = INTERNAL_waves[INTERNAL_curWave].CreateInstance();

            result.INTERNAL_isXACTSource = true;

            if (INTERNAL_volumeVariationAdd && currentLoop > 0)
            {
                result.Volume = prevVolume.Value + XACTCalculator.CalculateAmplitudeRatio(
                    random.NextDouble() *
                    (INTERNAL_maxVolume - INTERNAL_minVolume) +
                    INTERNAL_minVolume
                    );
            }
            else
            {
                result.Volume = XACTCalculator.CalculateAmplitudeRatio(
                    soundVolume + (
                        random.NextDouble() *
                        (INTERNAL_maxVolume - INTERNAL_minVolume)
                        ) + INTERNAL_minVolume
                    );
            }
            result.Pitch = (
                random.Next(
                    INTERNAL_minPitch,
                    INTERNAL_maxPitch
                    ) / 1000.0f
                ) + ((INTERNAL_pitchVariationAdd && currentLoop > 0) ?
                     prevPitch.Value :
                     soundPitch
                     );

            result.FilterType = INTERNAL_filterType;
            result.IsLooped   = (
                (INTERNAL_loopCount == 255) &&
                !INTERNAL_trackVariationOnLoop &&
                !INTERNAL_volumeVariationOnLoop &&
                !INTERNAL_pitchVariationOnLoop
                );
            return(result);
        }
Esempio n. 7
0
 public void SetReverbReflectionsGain(IALReverb reverb, float value)
 {
     // Cutting off possible float values above 3.16, for EFX -flibit
     EFX.alEffectf(
         (reverb as OpenALReverb).EffectHandle,
         EFX.AL_EAXREVERB_REFLECTIONS_GAIN,
         Math.Min(
             XACTCalculator.CalculateAmplitudeRatio(value),
             3.16f
             )
         );
 }
Esempio n. 8
0
 public void SetReverbGain(IALReverb reverb, float value)
 {
     // Cutting off volumes from 0db to 20db! -flibit
     EFX.alEffectf(
         (reverb as OpenALReverb).EffectHandle,
         EFX.AL_EAXREVERB_GAIN,
         Math.Min(
             XACTCalculator.CalculateAmplitudeRatio(value),
             1.0f
             )
         );
 }
Esempio n. 9
0
        public void SetReverbHighEQGain(IALReverb reverb, float value)
        {
            EFX.alEffectf(
                (reverb as OpenALReverb).EffectHandle,
                EFX.AL_EAXREVERB_GAINHF,
                XACTCalculator.CalculateReverbAmplitudeRatio(
                    value - 8.0f
                    )
                );
#if VERBOSE_AL_DEBUGGING
            CheckALError();
#endif
        }
Esempio n. 10
0
 public void SetLowEQGain(float value)
 {
     // Cutting off volumes from 0db to 4db! -flibit
     EFX.alEffectf(
         effectHandle,
         EFX.AL_EAXREVERB_GAINLF,
         Math.Min(
             XACTCalculator.CalculateAmplitudeRatio(
                 value - 8.0f
                 ),
             1.0f
             )
         );
 }
Esempio n. 11
0
        public void SetReverbGain(IALReverb reverb, float value)
        {
            // Cutting off volumes from 0db to 20db! -flibit
            EFX.alEffectf(
                (reverb as OpenALReverb).EffectHandle,
                EFX.AL_EAXREVERB_GAIN,
                Math.Min(
                    XACTCalculator.CalculateReverbAmplitudeRatio(value),
                    1.0f
                    )
                );
#if VERBOSE_AL_DEBUGGING
            CheckALError();
#endif
        }
Esempio n. 12
0
        public XACTClip(BinaryReader reader, double clipVolume, byte filterType)
        {
            // Number of XACT Events
            Events = new XACTEvent[reader.ReadByte()];

            for (int i = 0; i < Events.Length; i += 1)
            {
                // Full Event information
                uint eventInfo = reader.ReadUInt32();

                // XACT Event Type, Timestamp
                uint eventType      = eventInfo & 0x0000001F;
                uint eventTimestamp = (eventInfo >> 5) & 0x0000FFFF;
                // uint eventUnknown = eventInfo >> 21;

                // Random offset, unused
                reader.ReadUInt16();

                // Load the Event
                if (eventType == 0)                 // StopEvent
                {
                    // TODO: Codename OhGodNo
                }
                else if (eventType == 1)                 // Basic PlayWaveEvent
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // WaveBank Track Index
                    ushort track = reader.ReadUInt16();

                    // WaveBank Index
                    byte waveBank = reader.ReadByte();

                    // Number of times to loop wave (255 is infinite)
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Finally.
                    Events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        new ushort[] { track },
                        new byte[] { waveBank },
                        0,
                        0,
                        clipVolume,
                        clipVolume,
                        filterType,
                        loopCount,
                        false,
                        false,
                        false,
                        false,
                        0,
                        false,
                        new byte[] { 0xFF }
                        );
                }
                else if (eventType == 3)                 // PlayWaveEvent with track variation
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // Number of times to loop wave (255 is infinite)
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Number of WaveBank tracks
                    ushort numTracks = reader.ReadUInt16();

                    /* Variation Playlist Type.
                     * First 4 bytes indicates Variation Type.
                     * Next 4 bytes appear to indicate New Variation On Loop.
                     * The rest is currently unknown.
                     * -flibit
                     */
                    ushort variationValues = reader.ReadUInt16();
                    ushort variationType   = (ushort)(variationValues & 0x000F);
                    bool   variationOnLoop = (variationValues & 0x00F0) > 0;

                    // Unknown values
                    reader.ReadBytes(4);

                    // Obtain WaveBank track information
                    ushort[] tracks    = new ushort[numTracks];
                    byte[]   waveBanks = new byte[numTracks];
                    byte[]   weights   = new byte[numTracks];
                    for (ushort j = 0; j < numTracks; j += 1)
                    {
                        tracks[j]    = reader.ReadUInt16();
                        waveBanks[j] = reader.ReadByte();
                        byte minWeight = reader.ReadByte();
                        byte maxWeight = reader.ReadByte();
                        weights[j] = (byte)(maxWeight - minWeight);
                    }

                    // Finally.
                    Events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        tracks,
                        waveBanks,
                        0,
                        0,
                        clipVolume,
                        clipVolume,
                        filterType,
                        loopCount,
                        false,
                        false,
                        false,
                        false,
                        variationType,
                        variationOnLoop,
                        weights
                        );
                }
                else if (eventType == 4)                 // PlayWaveEvent with effect variation
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // WaveBank track
                    ushort track = reader.ReadUInt16();

                    // WaveBank index, unconfirmed
                    byte waveBank = reader.ReadByte();

                    // Loop Count, unconfirmed
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Pitch Variation
                    short minPitch = reader.ReadInt16();
                    short maxPitch = reader.ReadInt16();

                    // Volume Variation
                    double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
                    double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // Frequency Variation, unusued
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Q Factor Variation, unused
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Variation On Loop flags
                    ushort varFlags = reader.ReadUInt16();
                    if ((varFlags & 0x1000) == 0)
                    {
                        minPitch = 0;
                        maxPitch = 0;
                    }
                    if ((varFlags & 0x2000) == 0)
                    {
                        minVolume = clipVolume;
                        maxVolume = clipVolume;
                    }
                    // varFlags & 0xC000 is freq/qfactor, always together
                    bool pitchVarLoop  = (varFlags & 0x0100) > 0;
                    bool volumeVarLoop = (varFlags & 0x0200) > 0;
                    // varFlags & 0x0C00 is freq/qfactor loop, always together
                    bool pitchVarAdd  = (varFlags & 0x0004) > 0;
                    bool volumeVarAdd = (varFlags & 0x0001) > 0;
                    // varFlags & 0x0050 is freq/qfactor add, can be separate

                    // Finally.
                    Events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        new ushort[] { track },
                        new byte[] { waveBank },
                        minPitch,
                        maxPitch,
                        minVolume,
                        maxVolume,
                        filterType,
                        loopCount,
                        pitchVarLoop,
                        pitchVarAdd,
                        volumeVarLoop,
                        volumeVarAdd,
                        0,
                        false,
                        new byte[] { 0xFF }
                        );
                }
                else if (eventType == 6)                 // PlayWaveEvent with track/effect variation
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // Number of times to loop wave (255 is infinite)
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Pitch variation
                    short minPitch = reader.ReadInt16();
                    short maxPitch = reader.ReadInt16();

                    // Volume variation
                    double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
                    double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // Frequency Variation, unusued
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Q Factor Variation, unused
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Variation On Loop flags
                    ushort varFlags = reader.ReadUInt16();
                    if ((varFlags & 0x1000) == 0)
                    {
                        minPitch = 0;
                        maxPitch = 0;
                    }
                    if ((varFlags & 0x2000) == 0)
                    {
                        minVolume = clipVolume;
                        maxVolume = clipVolume;
                    }
                    // varFlags & 0xC000 is freq/qfactor, always together
                    bool pitchVarLoop  = (varFlags & 0x0100) > 0;
                    bool volumeVarLoop = (varFlags & 0x0200) > 0;
                    // varFlags & 0x0C00 is freq/qfactor loop, always together
                    bool pitchVarAdd  = (varFlags & 0x0004) > 0;
                    bool volumeVarAdd = (varFlags & 0x0001) > 0;
                    // varFlags & 0x0050 is freq/qfactor add, can be separate

                    // Number of WaveBank tracks
                    ushort numTracks = reader.ReadUInt16();

                    /* Variation Playlist Type.
                     * First 4 bytes indicates Variation Type.
                     * Next 4 bytes appear to indicate New Variation On Loop.
                     * The rest is currently unknown.
                     * -flibit
                     */
                    ushort variationValues = reader.ReadUInt16();
                    ushort variationType   = (ushort)(variationValues & 0x000F);
                    bool   variationOnLoop = (variationValues & 0x00F0) > 0;

                    // Unknown values
                    reader.ReadBytes(4);

                    // Obtain WaveBank track information
                    ushort[] tracks    = new ushort[numTracks];
                    byte[]   waveBanks = new byte[numTracks];
                    byte[]   weights   = new byte[numTracks];
                    for (ushort j = 0; j < numTracks; j += 1)
                    {
                        tracks[j]    = reader.ReadUInt16();
                        waveBanks[j] = reader.ReadByte();
                        byte minWeight = reader.ReadByte();
                        byte maxWeight = reader.ReadByte();
                        weights[j] = (byte)(maxWeight - minWeight);
                    }

                    // Finally.
                    Events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        tracks,
                        waveBanks,
                        minPitch,
                        maxPitch,
                        minVolume,
                        maxVolume,
                        filterType,
                        loopCount,
                        pitchVarLoop,
                        pitchVarAdd,
                        volumeVarLoop,
                        volumeVarAdd,
                        variationType,
                        variationOnLoop,
                        weights
                        );
                }
                else if (eventType == 7)                 // SetPitchEvent
                {
                    // Unknown values
                    reader.ReadBytes(2);

                    /* Event Flags
                     * 0x08 = Min/Max Values
                     * Rest is unknown
                     */
                    bool minMax = (reader.ReadByte() & 0x08) == 0x08;

                    // Min/Max Random
                    float min = reader.ReadSingle() / 1000.0f;
                    float max;
                    if (minMax)
                    {
                        max = reader.ReadSingle() / 1000.0f;
                    }
                    else
                    {
                        max = min;
                    }

                    // FIXME: Any more...? -flibit

                    Events[i] = new SetPitchEvent(
                        eventTimestamp,
                        min,
                        max
                        );
                }
                else if (eventType == 8)                 // SetVolumeEvent
                {
                    // Unknown values
                    reader.ReadBytes(2);

                    /* Event Flags
                     * 0x08 = Min/Max Values
                     * 0x01 = Add, rather than replace
                     * Rest is unknown
                     */
                    byte flags     = reader.ReadByte();
                    bool addVolume = (flags & 0x01) == 0x01;
                    bool minMax    = (flags & 0x08) == 0x08;

                    // Operand Constant
                    float min = reader.ReadSingle() / 100.0f;
                    float max;
                    if (minMax)
                    {
                        max = reader.ReadSingle() / 100.0f;

                        // Unknown bytes
                        reader.ReadBytes(5);
                    }
                    else
                    {
                        max = min;

                        // Unknown values
                        reader.ReadBytes(8);
                    }
                    if (addVolume)
                    {
                        min += (float)clipVolume;
                        max += (float)clipVolume;
                    }

                    Events[i] = new SetVolumeEvent(
                        eventTimestamp,
                        XACTCalculator.CalculateAmplitudeRatio(min),
                        XACTCalculator.CalculateAmplitudeRatio(max)
                        );
                }
                else if (eventType == 15)                 // ???
                {
                    // TODO: Codename OhGodNo -flibit
                }
                else if (eventType == 17)                 // Volume Repeat Event
                {
                    // TODO: Codename OhGodNo -flibit
                }
                else
                {
                    /* TODO: All XACT Events.
                     * The following type information is based on
                     * third-party contributions:
                     * Type 9 - Marker Event
                     * -flibit
                     */
                    throw new NotImplementedException(
                              "EVENT TYPE " + eventType.ToString() + " NOT IMPLEMENTED!"
                              );
                }
            }
        }
Esempio n. 13
0
File: Cue.cs Progetto: raizam/FNA
        internal bool INTERNAL_update()
        {
            // If we're not running, save some instructions...
            if (!INTERNAL_timer.IsRunning)
            {
                return(true);
            }
            elapsedFrames += 1;

            // 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)
                    {
                        eventVolume = ((SetVolumeEvent)INTERNAL_eventList[i]).GetVolume();
                    }
                    else if (type == 3)
                    {
                        eventPitch = ((SetPitchEvent)INTERNAL_eventList[i]).GetPitch();
                    }
                    else
                    {
                        throw new NotImplementedException("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]];
                    float         prevVolume = INTERNAL_instanceVolumes[i];
                    float         prevPitch  = INTERNAL_instancePitches[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, prevVolume, prevPitch);

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

            // Fade in/out
            float fadePerc = 1.0f;

            if (INTERNAL_fadeMode != FadeMode.None)
            {
                if (INTERNAL_fadeMode == FadeMode.FadeOut)
                {
                    if (INTERNAL_category.crossfadeType == CrossfadeType.Linear)
                    {
                        fadePerc = (INTERNAL_fadeEnd - (INTERNAL_timer.ElapsedMilliseconds - INTERNAL_fadeStart)) / (float)INTERNAL_fadeEnd;
                    }
                    else
                    {
                        throw new NotImplementedException("Unhandled CrossfadeType!");
                    }
                    if (fadePerc <= 0.0f)
                    {
                        Stop(AudioStopOptions.Immediate);
                        INTERNAL_fadeMode = FadeMode.None;
                        return(false);
                    }
                }
                else
                {
                    if (INTERNAL_category.crossfadeType == CrossfadeType.Linear)
                    {
                        fadePerc = INTERNAL_timer.ElapsedMilliseconds / (float)INTERNAL_fadeEnd;
                    }
                    else
                    {
                        throw new NotImplementedException("Unhandled CrossfadeType!");
                    }
                    if (fadePerc > 1.0f)
                    {
                        fadePerc          = 1.0f;
                        INTERNAL_fadeMode = FadeMode.None;
                    }
                }
            }

            // 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 - hf;
                        if (i == 0)
                        {
                            hfGain = hf;
                            lfGain = lf;
                        }
                        else
                        {
                            throw new NotImplementedException("Per-track filter RPCs!");
                        }
                    }
                    else
                    {
                        throw new NotImplementedException("RPC Parameter Type: " + curRPC.Parameter.ToString());
                    }
                }
            }

            // Sound effect instance updates
            for (int i = 0; i < INTERNAL_instancePool.Count; i += 1)
            {
                /* The final volume should be the combination of the
                 * authored volume, category volume, RPC/Event volumes, and fade.
                 */
                INTERNAL_instancePool[i].Volume = (
                    INTERNAL_instanceVolumes[i] *
                    INTERNAL_category.INTERNAL_volume.Value *
                    rpcVolume *
                    INTERNAL_rpcTrackVolumes[i] *
                    eventVolume *
                    fadePerc
                    );

                /* The final pitch should be the combination of the
                 * authored pitch and RPC/Event pitch results.
                 */
                INTERNAL_instancePool[i].Pitch = (
                    INTERNAL_instancePitches[i] +
                    rpcPitch +
                    eventPitch +
                    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.
                 */
                byte fType = INTERNAL_instancePool[i].FilterType;
                if (fType == 0xFF)
                {
                    // No-op, no filter!
                }
                else if (fType == 0)
                {
                    INTERNAL_instancePool[i].INTERNAL_applyLowPassFilter(hfGain);
                }
                else if (fType == 1)
                {
                    INTERNAL_instancePool[i].INTERNAL_applyHighPassFilter(lfGain);
                }
                else if (fType == 2)
                {
                    INTERNAL_instancePool[i].INTERNAL_applyBandPassFilter(hfGain, lfGain);
                }
                else
                {
                    throw new InvalidOperationException("Unhandled filter type!");
                }

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

            return(true);
        }
Esempio n. 14
0
        public XACTClip(BinaryReader reader, double clipVolume)
        {
            INTERNAL_clipVolume = clipVolume;

            // Number of XACT Events
            INTERNAL_events = new XACTEvent[reader.ReadByte()];

            for (int i = 0; i < INTERNAL_events.Length; i += 1)
            {
                // Full Event information
                uint eventInfo = reader.ReadUInt32();

                // XACT Event Type, Timestamp
                uint eventType = eventInfo & 0x0000001F;
                // uint eventTimestamp = (eventInfo >> 5) & 0x0000FFFF;
                // uint eventUnknown = eventInfo >> 21;

                // Random offset, unused
                reader.ReadUInt16();

                // Load the Event
                if (eventType == 1)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // WaveBank Track Index
                    ushort track = reader.ReadUInt16();

                    // WaveBank Index
                    byte waveBank = reader.ReadByte();

                    // Number of times to loop wave (255 is infinite)
                    byte loopCount = reader.ReadByte();

                    // Unknown value
                    reader.ReadUInt32();

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        new ushort[] { track },
                        new byte[] { waveBank },
                        0,
                        0,
                        0.0,
                        0.0,
                        loopCount,
                        0,
                        new byte[] { 0xFF }
                        );
                }
                else if (eventType == 3)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // Unknown values
                    reader.ReadBytes(5);

                    // Number of WaveBank tracks
                    ushort numTracks = reader.ReadUInt16();

                    // Variation Playlist Type
                    ushort variationType = reader.ReadUInt16();

                    // Unknown values
                    reader.ReadBytes(4);

                    // Obtain WaveBank track information
                    ushort[] tracks    = new ushort[numTracks];
                    byte[]   waveBanks = new byte[numTracks];
                    byte[]   weights   = new byte[numTracks];
                    for (ushort j = 0; j < numTracks; j += 1)
                    {
                        tracks[j]    = reader.ReadUInt16();
                        waveBanks[j] = reader.ReadByte();
                        byte minWeight = reader.ReadByte();
                        byte maxWeight = reader.ReadByte();
                        weights[j] = (byte)(maxWeight - minWeight);
                    }

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        tracks,
                        waveBanks,
                        0,
                        0,
                        0.0,
                        0.0,
                        0,
                        variationType,
                        weights
                        );
                }
                else if (eventType == 4)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // WaveBank track
                    ushort track = reader.ReadUInt16();

                    // WaveBank index, unconfirmed
                    byte waveBank = reader.ReadByte();

                    // Loop Count, unconfirmed
                    byte loopCount = reader.ReadByte();

                    // Unknown values
                    reader.ReadBytes(4);

                    // Pitch Variation
                    short minPitch = reader.ReadInt16();
                    short maxPitch = reader.ReadInt16();

                    // Volume Variation
                    double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
                    double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // Unknown values
                    reader.ReadSingle();
                    reader.ReadSingle();
                    reader.ReadSingle();
                    reader.ReadSingle();
                    reader.ReadByte();

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        new ushort[] { track },
                        new byte[] { waveBank },
                        minPitch,
                        maxPitch,
                        minVolume,
                        maxVolume,
                        loopCount,
                        0,
                        new byte[] { 0xFF }
                        );
                }
                else if (eventType == 6)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // Unknown values
                    reader.ReadBytes(5);

                    // Pitch variation
                    short minPitch = reader.ReadInt16();
                    short maxPitch = reader.ReadInt16();

                    // Volume variation
                    double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
                    double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // Unknown values
                    reader.ReadSingle();
                    reader.ReadSingle();
                    reader.ReadSingle();
                    reader.ReadSingle();
                    reader.ReadByte();

                    // Variation flags
                    // FIXME: There's probably more to these flags...
                    byte varFlags = reader.ReadByte();
                    if ((varFlags & 0x20) != 0x20)
                    {
                        // Throw out the volume variation.
                        minVolume = 0.0;
                        maxVolume = 0.0;
                    }
                    if ((varFlags & 0x10) != 0x10)
                    {
                        // Throw out the pitch variation
                        minPitch = 0;
                        maxPitch = 0;
                    }

                    // Number of WaveBank tracks
                    ushort numTracks = reader.ReadUInt16();

                    // Variation Playlist Type
                    ushort variationType = reader.ReadUInt16();

                    // Unknown values
                    reader.ReadBytes(4);

                    // Obtain WaveBank track information
                    ushort[] tracks    = new ushort[numTracks];
                    byte[]   waveBanks = new byte[numTracks];
                    byte[]   weights   = new byte[numTracks];
                    for (ushort j = 0; j < numTracks; j += 1)
                    {
                        tracks[j]    = reader.ReadUInt16();
                        waveBanks[j] = reader.ReadByte();
                        byte minWeight = reader.ReadByte();
                        byte maxWeight = reader.ReadByte();
                        weights[j] = (byte)(maxWeight - minWeight);
                    }

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        tracks,
                        waveBanks,
                        minPitch,
                        maxPitch,
                        minVolume,
                        maxVolume,
                        0,
                        variationType,
                        weights
                        );
                }
                else if (eventType == 8)
                {
                    // Unknown values
                    reader.ReadBytes(3);

                    // Operand Constant
                    float constant = reader.ReadSingle();

                    // Unknown values
                    reader.ReadBytes(8);

                    INTERNAL_events[i] = new SetVolumeEvent(
                        constant
                        );
                }
                else
                {
                    /* TODO: All XACT Events.
                     * The following type information is based on
                     * third-party contributions:
                     * Type 0 - Stop Event
                     * Type 7 - Pitch Event
                     * Type 9 - Marker Event
                     * -flibit
                     */
                    throw new Exception(
                              "EVENT TYPE " + eventType.ToString() + " NOT IMPLEMENTED!"
                              );
                }
            }
        }
Esempio n. 15
0
        public XACTClip(BinaryReader reader, double clipVolume)
        {
            // Number of XACT Events
            INTERNAL_events = new XACTEvent[reader.ReadByte()];

            for (int i = 0; i < INTERNAL_events.Length; i += 1)
            {
                // Full Event information
                uint eventInfo = reader.ReadUInt32();

                // XACT Event Type, Timestamp
                uint eventType      = eventInfo & 0x0000001F;
                uint eventTimestamp = (eventInfo >> 5) & 0x0000FFFF;
                // uint eventUnknown = eventInfo >> 21;

                // Random offset, unused
                reader.ReadUInt16();

                // Load the Event
                if (eventType == 0)
                {
                    // TODO: Codename OhGodNo
                    // Stop Event
                }
                else if (eventType == 1)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // WaveBank Track Index
                    ushort track = reader.ReadUInt16();

                    // WaveBank Index
                    byte waveBank = reader.ReadByte();

                    // Number of times to loop wave (255 is infinite)
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        new ushort[] { track },
                        new byte[] { waveBank },
                        0,
                        0,
                        clipVolume,
                        clipVolume,
                        -1,
                        loopCount,
                        0,
                        new byte[] { 0xFF }
                        );
                }
                else if (eventType == 3)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // Number of times to loop wave (255 is infinite)
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Number of WaveBank tracks
                    ushort numTracks = reader.ReadUInt16();

                    /* Variation Playlist Type.
                     * First 4 bytes indicates Variation Type.
                     * Next 4 bytes appear to indicate New Variation On Loop.
                     * The rest is currently unknown.
                     * -flibit
                     */
                    ushort variationType = (ushort)(reader.ReadUInt16() & 0x000F);

                    // Unknown values
                    reader.ReadBytes(4);

                    // Obtain WaveBank track information
                    ushort[] tracks    = new ushort[numTracks];
                    byte[]   waveBanks = new byte[numTracks];
                    byte[]   weights   = new byte[numTracks];
                    for (ushort j = 0; j < numTracks; j += 1)
                    {
                        tracks[j]    = reader.ReadUInt16();
                        waveBanks[j] = reader.ReadByte();
                        byte minWeight = reader.ReadByte();
                        byte maxWeight = reader.ReadByte();
                        weights[j] = (byte)(maxWeight - minWeight);
                    }

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        tracks,
                        waveBanks,
                        0,
                        0,
                        clipVolume,
                        clipVolume,
                        -1,
                        loopCount,
                        variationType,
                        weights
                        );
                }
                else if (eventType == 4)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // WaveBank track
                    ushort track = reader.ReadUInt16();

                    // WaveBank index, unconfirmed
                    byte waveBank = reader.ReadByte();

                    // Loop Count, unconfirmed
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Pitch Variation
                    short minPitch = reader.ReadInt16();
                    short maxPitch = reader.ReadInt16();

                    // Volume Variation
                    double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
                    double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // Frequency Variation, unusued
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Q Factor Variation, unused
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Filter Type
                    byte filterType = reader.ReadByte();

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        new ushort[] { track },
                        new byte[] { waveBank },
                        minPitch,
                        maxPitch,
                        minVolume,
                        maxVolume,
                        (int)filterType,
                        loopCount,
                        0,
                        new byte[] { 0xFF }
                        );
                }
                else if (eventType == 6)
                {
                    // Unknown value
                    reader.ReadByte();

                    /* Event Flags
                     * 0x01 = Break Loop
                     * 0x02 = Use Speaker Position
                     * 0x04 = Use Center Speaker
                     * 0x08 = New Speaker Position On Loop
                     */
                    reader.ReadByte();

                    // Number of times to loop wave (255 is infinite)
                    byte loopCount = reader.ReadByte();

                    // Speaker position angle/arc, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Pitch variation
                    short minPitch = reader.ReadInt16();
                    short maxPitch = reader.ReadInt16();

                    // Volume variation
                    double minVolume = XACTCalculator.ParseDecibel(reader.ReadByte());
                    double maxVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // Frequency Variation, unusued
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Q Factor Variation, unused
                    reader.ReadSingle();
                    reader.ReadSingle();

                    // Filter Type
                    byte filterType = reader.ReadByte();

                    // Variation flags
                    // FIXME: There's probably more to these flags...
                    byte varFlags = reader.ReadByte();
                    if ((varFlags & 0x20) != 0x20)
                    {
                        // Throw out the volume variation.
                        minVolume = clipVolume;
                        maxVolume = clipVolume;
                    }
                    if ((varFlags & 0x10) != 0x10)
                    {
                        // Throw out the pitch variation
                        minPitch = 0;
                        maxPitch = 0;
                    }

                    // Number of WaveBank tracks
                    ushort numTracks = reader.ReadUInt16();

                    /* Variation Playlist Type.
                     * First 4 bytes indicates Variation Type.
                     * Next 4 bytes appear to indicate New Variation On Loop.
                     * The rest is currently unknown.
                     * -flibit
                     */
                    ushort variationType = (ushort)(reader.ReadUInt16() & 0x000F);

                    // Unknown values
                    reader.ReadBytes(4);

                    // Obtain WaveBank track information
                    ushort[] tracks    = new ushort[numTracks];
                    byte[]   waveBanks = new byte[numTracks];
                    byte[]   weights   = new byte[numTracks];
                    for (ushort j = 0; j < numTracks; j += 1)
                    {
                        tracks[j]    = reader.ReadUInt16();
                        waveBanks[j] = reader.ReadByte();
                        byte minWeight = reader.ReadByte();
                        byte maxWeight = reader.ReadByte();
                        weights[j] = (byte)(maxWeight - minWeight);
                    }

                    // Finally.
                    INTERNAL_events[i] = new PlayWaveEvent(
                        eventTimestamp,
                        tracks,
                        waveBanks,
                        minPitch,
                        maxPitch,
                        minVolume,
                        maxVolume,
                        (int)filterType,
                        loopCount,
                        variationType,
                        weights
                        );
                }
                else if (eventType == 7)
                {
                    // TODO: Codename OhGodNo -flibit
                    // Pitch Event
                }
                else if (eventType == 8)
                {
                    // Unknown values
                    reader.ReadBytes(2);

                    /* Event Flags
                     * 0x01 = Add, rather than replace
                     * Rest is unknown
                     */
                    bool addVolume = (reader.ReadByte() & 0x01) == 0x01;

                    // Operand Constant
                    float constant = reader.ReadSingle() / 100.0f;
                    if (addVolume)
                    {
                        constant += (float)clipVolume;
                    }

                    // Unknown values
                    reader.ReadBytes(8);

                    INTERNAL_events[i] = new SetVolumeEvent(
                        eventTimestamp,
                        XACTCalculator.CalculateAmplitudeRatio(constant)
                        );
                }
                else if (eventType == 15)
                {
                    // TODO: Codename OhGodNo -flibit
                    // Unknown Event!
                }
                else if (eventType == 17)
                {
                    // TODO: Codename OhGodNo -flibit
                    // Volume Repeat Event
                }
                else
                {
                    /* TODO: All XACT Events.
                     * The following type information is based on
                     * third-party contributions:
                     * Type 9 - Marker Event
                     * -flibit
                     */
                    throw new Exception(
                              "EVENT TYPE " + eventType.ToString() + " NOT IMPLEMENTED!"
                              );
                }
            }
        }
Esempio n. 16
0
        public XACTSound(BinaryReader reader)
        {
            // Sound Effect Flags
            byte soundFlags = reader.ReadByte();
            bool complex    = (soundFlags & 0x01) != 0;

            // AudioCategory Index
            Category = reader.ReadUInt16();

            // Sound Volume
            Volume = XACTCalculator.ParseDecibel(reader.ReadByte());

            // Sound Pitch
            Pitch = (reader.ReadInt16() / 1000.0f);

            // Unknown value
            reader.ReadByte();

            // Length of Sound Entry, unused
            reader.ReadUInt16();

            // Number of Sound Clips
            if (complex)
            {
                INTERNAL_clips = new XACTClip[reader.ReadByte()];
            }
            else
            {
                // Simple Sounds always have 1 PlayWaveEvent.
                INTERNAL_clips = new XACTClip[1];
                ushort track    = reader.ReadUInt16();
                byte   waveBank = reader.ReadByte();
                INTERNAL_clips[0] = new XACTClip(track, waveBank);
            }

            // Parse RPC Properties
            List <uint> rpcCodeList = new List <uint>();

            if ((soundFlags & 0x0E) != 0)
            {
                // RPC data length
                ushort rpcDataLength = reader.ReadUInt16();
                ushort totalDataRead = 2;

                /* For some reason XACT can have separate sets of codes.
                 * I dunno why, but I bet we should be separating them too.
                 * -flibit
                 */
                while (totalDataRead < rpcDataLength)
                {
                    // Number of RPC Presets (in this block)
                    byte numCodes = reader.ReadByte();

                    // Obtain RPC curve codes (in this block)
                    for (byte i = 0; i < numCodes; i += 1)
                    {
                        rpcCodeList.Add(reader.ReadUInt32());
                    }

                    totalDataRead += (ushort)(1 + (4 * numCodes));
                }
            }
            RPCCodes = rpcCodeList.ToArray();             // Array may be empty! It's okay!

            // Parse DSP Presets
            DSPCodes = new uint[0];             // Eww... -flibit
            if ((soundFlags & 0x10) != 0)
            {
                // DSP Presets Length, unused
                reader.ReadUInt16();

                // Number of DSP Presets
                DSPCodes = new uint[reader.ReadByte()];

                // Obtain DSP Preset codes
                for (byte j = 0; j < DSPCodes.Length; j += 1)
                {
                    DSPCodes[j] = reader.ReadUInt32();
                }
            }

            // Parse Sound Events
            if (complex)
            {
                for (int i = 0; i < INTERNAL_clips.Length; i += 1)
                {
                    // XACT Clip volume
                    double clipVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // XACT Clip Offset in Bank
                    uint offset = reader.ReadUInt32();

                    // Unknown value
                    reader.ReadUInt32();

                    // Store this for when we're done reading the clip.
                    long curPos = reader.BaseStream.Position;

                    // Go to the Clip in the Bank.
                    reader.BaseStream.Seek(offset, SeekOrigin.Begin);

                    // Parse the Clip.
                    INTERNAL_clips[i] = new XACTClip(reader, clipVolume);

                    // Back to where we were...
                    reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
                }
            }

            HasLoadedTracks = false;
        }
Esempio n. 17
0
        public AudioEngine(string settingsFile)
        {
            if (String.IsNullOrEmpty(settingsFile))
            {
                throw new ArgumentNullException("settingsFile");
            }

            using (Stream stream = TitleContainer.OpenStream(settingsFile))
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    // Check the file header. Should be 'XGFS'
                    if (reader.ReadUInt32() != 0x46534758)
                    {
                        throw new ArgumentException("XGFS format not recognized!");
                    }

                    // Check the Content and Tool versions
                    if (reader.ReadUInt16() != ContentVersion)
                    {
                        throw new ArgumentException("XGFS Content version!");
                    }
                    if (reader.ReadUInt16() != 42)
                    {
                        throw new ArgumentException("XGFS Tool version!");
                    }

                    // Unknown value
                    reader.ReadUInt16();

                    // Last Modified, Unused
                    reader.ReadUInt64();

                    // Unknown value
                    reader.ReadByte();

                    // Number of AudioCategories
                    ushort numCategories = reader.ReadUInt16();

                    // Number of XACT Variables
                    ushort numVariables = reader.ReadUInt16();

                    // Unknown value, KEY#1 Length?
                    reader.ReadUInt16();

                    // Unknown value, KEY#2 Length?
                    reader.ReadUInt16();

                    // Number of RPC Variables
                    ushort numRPCs = reader.ReadUInt16();

                    // Number of DSP Presets/Parameters
                    ushort numDSPPresets    = reader.ReadUInt16();
                    ushort numDSPParameters = reader.ReadUInt16();

                    // Category Offset in XGS File
                    uint categoryOffset = reader.ReadUInt32();

                    // Variable Offset in XGS File
                    uint variableOffset = reader.ReadUInt32();

                    // Unknown value, KEY#1 Offset?
                    reader.ReadUInt32();

                    // Category Name Index Offset, unused
                    reader.ReadUInt32();

                    // Unknown value, KEY#2 Offset?
                    reader.ReadUInt32();

                    // Variable Name Index Offset, unused
                    reader.ReadUInt32();

                    // Category Name Offset in XGS File
                    uint categoryNameOffset = reader.ReadUInt32();

                    // Variable Name Offset in XGS File
                    uint variableNameOffset = reader.ReadUInt32();

                    // RPC Variable Offset in XGS File
                    uint rpcOffset = reader.ReadUInt32();

                    // DSP Preset/Parameter Offsets in XGS File
                    uint dspPresetOffset    = reader.ReadUInt32();
                    uint dspParameterOffset = reader.ReadUInt32();

                    // Obtain the Audio Category Names
                    reader.BaseStream.Seek(categoryNameOffset, SeekOrigin.Begin);
                    string[] categoryNames = new string[numCategories];
                    for (int i = 0; i < numCategories; i += 1)
                    {
                        List <char> builtString = new List <char>();
                        while (reader.PeekChar() != 0)
                        {
                            builtString.Add(reader.ReadChar());
                        }
                        reader.ReadChar();                 // Null terminator
                        categoryNames[i] = new string(builtString.ToArray());
                    }

                    // Obtain the Audio Categories
                    reader.BaseStream.Seek(categoryOffset, SeekOrigin.Begin);
                    INTERNAL_categories = new List <AudioCategory>();
                    for (int i = 0; i < numCategories; i += 1)
                    {
                        // Maximum instances
                        byte maxInstances = reader.ReadByte();

                        // Fade In/Out
                        ushort fadeInMS  = reader.ReadUInt16();
                        ushort fadeOutMS = reader.ReadUInt16();

                        // Instance Behavior Flags
                        int maxBehavior = reader.ReadByte() & 0x0F;                 // FIXME: What?

                        // Unknown value
                        reader.ReadUInt16();

                        // Volume
                        float volume = XACTCalculator.CalculateVolume(reader.ReadByte());

                        // Visibility Flags, unused
                        reader.ReadByte();

                        // Add to the engine list
                        INTERNAL_categories.Add(
                            new AudioCategory(
                                categoryNames[i],
                                volume,
                                maxInstances,
                                maxBehavior,
                                fadeInMS,
                                fadeOutMS
                                )
                            );
                    }

                    // Obtain the Variable Names
                    reader.BaseStream.Seek(variableNameOffset, SeekOrigin.Begin);
                    string[] variableNames = new string[numVariables];
                    for (int i = 0; i < numVariables; i += 1)
                    {
                        List <char> builtString = new List <char>();
                        while (reader.PeekChar() != 0)
                        {
                            builtString.Add(reader.ReadChar());
                        }
                        reader.ReadChar();                 // Null terminator
                        variableNames[i] = new string(builtString.ToArray());
                    }

                    // Obtain the Variables
                    reader.BaseStream.Seek(variableOffset, SeekOrigin.Begin);
                    INTERNAL_variables = new List <Variable>();
                    for (int i = 0; i < numVariables; i += 1)
                    {
                        // Variable Accessibility (See Variable constructor)
                        byte varFlags = reader.ReadByte();

                        // Variable Value, Boundaries
                        float initialValue = reader.ReadSingle();
                        float minValue     = reader.ReadSingle();
                        float maxValue     = reader.ReadSingle();

                        // Add to the engine list
                        INTERNAL_variables.Add(
                            new Variable(
                                variableNames[i],
                                (varFlags & 0x01) != 0,
                                (varFlags & 0x02) != 0,
                                (varFlags & 0x04) == 0,
                                (varFlags & 0x08) != 0,
                                initialValue,
                                minValue,
                                maxValue
                                )
                            );
                    }

                    // Append built-in properties to Variable list
                    bool hasVolume = false;
                    foreach (Variable curVar in INTERNAL_variables)
                    {
                        if (curVar.Name.Equals("Volume"))
                        {
                            hasVolume = true;
                        }
                    }
                    if (!hasVolume)
                    {
                        INTERNAL_variables.Add(
                            new Variable(
                                "Volume",
                                true,
                                false,
                                false,
                                false,
                                1.0f,
                                0.0f,
                                1.0f
                                )
                            );
                    }

                    // Obtain the RPC Curves
                    reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin);
                    INTERNAL_RPCs = new Dictionary <long, RPC>();
                    for (int i = 0; i < numRPCs; i += 1)
                    {
                        // RPC "Code", used by the SoundBanks
                        long rpcCode = reader.BaseStream.Position;

                        // RPC Variable
                        ushort rpcVariable = reader.ReadUInt16();

                        // Number of RPC Curve Points
                        byte numPoints = reader.ReadByte();

                        // RPC Parameter
                        ushort rpcParameter = reader.ReadUInt16();

                        // RPC Curve Points
                        RPCPoint[] rpcPoints = new RPCPoint[numPoints];
                        for (byte j = 0; j < numPoints; j += 1)
                        {
                            float x    = reader.ReadSingle();
                            float y    = reader.ReadSingle();
                            byte  type = reader.ReadByte();
                            rpcPoints[j] = new RPCPoint(
                                x, y,
                                (RPCPointType)type
                                );
                        }

                        // Add to the engine list
                        INTERNAL_RPCs.Add(
                            rpcCode,
                            new RPC(
                                INTERNAL_variables[rpcVariable].Name,
                                rpcParameter,
                                rpcPoints
                                )
                            );
                    }

                    // Obtain the DSP Parameters
                    reader.BaseStream.Seek(dspParameterOffset, SeekOrigin.Begin);
                    INTERNAL_dspParameters = new List <DSPParameter>();
                    for (int i = 0; i < numDSPParameters; i += 1)
                    {
                        // Effect Parameter Type
                        byte type = reader.ReadByte();

                        // Effect value, boundaries
                        float value  = reader.ReadSingle();
                        float minVal = reader.ReadSingle();
                        float maxVal = reader.ReadSingle();

                        // Unknown value
                        reader.ReadUInt16();

                        // Add to Parameter list
                        INTERNAL_dspParameters.Add(
                            new DSPParameter(
                                type,
                                value,
                                minVal,
                                maxVal
                                )
                            );
                    }

                    // Obtain the DSP Presets
                    reader.BaseStream.Seek(dspPresetOffset, SeekOrigin.Begin);
                    INTERNAL_dspPresets = new Dictionary <long, DSPPreset>();
                    int total = 0;
                    for (int i = 0; i < numDSPPresets; i += 1)
                    {
                        // DSP "Code", used by the SoundBanks
                        long dspCode = reader.BaseStream.Position;

                        // Preset Accessibility
                        bool global = (reader.ReadByte() == 1);

                        // Number of preset parameters
                        uint numParams = reader.ReadUInt32();

                        // Obtain DSP Parameters
                        DSPParameter[] parameters = new DSPParameter[numParams];
                        for (uint j = 0; j < numParams; j += 1)
                        {
                            parameters[j] = INTERNAL_dspParameters[total];
                            total        += 1;
                        }

                        // Add to DSP Preset list
                        // FIXME: Did XNA4 PC ever go past Reverb?
                        INTERNAL_dspPresets.Add(
                            dspCode,
                            new DSPPreset(
                                "Reverb",
                                global,
                                parameters
                                )
                            );
                    }
                }

            // Create the WaveBank Dictionary
            INTERNAL_waveBanks = new Dictionary <string, WaveBank>();

            // Finally.
            IsDisposed = false;
        }
Esempio n. 18
0
 public float GetVolume()
 {
     // FIXME: There's probably more that this event does...
     return(XACTCalculator.CalculateAmplitudeRatio(INTERNAL_constant));
 }
Esempio n. 19
0
        public XACTSound(BinaryReader reader)
        {
            // Sound Effect Flags
            byte soundFlags = reader.ReadByte();
            bool complex    = (soundFlags & 0x01) != 0;

            // AudioCategory Index
            Category = reader.ReadUInt16();

            // Sound Volume
            Volume = XACTCalculator.ParseDecibel(reader.ReadByte());

            // Sound Pitch
            Pitch = (reader.ReadInt16() / 1000.0f);

            // Unknown value
            reader.ReadByte();

            // Length of Sound Entry, unused
            reader.ReadUInt16();

            // Number of Sound Clips
            if (complex)
            {
                INTERNAL_clips = new XACTClip[reader.ReadByte()];
            }
            else
            {
                // Simple Sounds always have 1 PlayWaveEvent.
                INTERNAL_clips = new XACTClip[1];
                ushort track    = reader.ReadUInt16();
                byte   waveBank = reader.ReadByte();
                INTERNAL_clips[0] = new XACTClip(track, waveBank);
            }

            // Parse RPC Properties
            RPCCodes = new List <uint[]>();
            if ((soundFlags & 0x0E) != 0)
            {
                // RPC data length
                ushort rpcDataLength = reader.ReadUInt16();
                ushort totalDataRead = 2;

                while (totalDataRead < rpcDataLength)
                {
                    // Number of RPC Presets (for this track)
                    uint[] codeList = new uint[reader.ReadByte()];

                    // Obtain RPC curve codes (in this block)
                    for (int i = 0; i < codeList.Length; i += 1)
                    {
                        codeList[i] = reader.ReadUInt32();
                    }

                    // Add this track's code list to the master list
                    RPCCodes.Add(codeList);

                    totalDataRead += (ushort)(1 + (4 * codeList.Length));
                }
            }

            // Parse DSP Presets
            DSPCodes = new uint[0];             // Eww... -flibit
            if ((soundFlags & 0x10) != 0)
            {
                // DSP Presets Length, unused
                reader.ReadUInt16();

                // Number of DSP Presets
                DSPCodes = new uint[reader.ReadByte()];

                // Obtain DSP Preset codes
                for (byte j = 0; j < DSPCodes.Length; j += 1)
                {
                    DSPCodes[j] = reader.ReadUInt32();
                }
            }

            // Parse Sound Events
            if (complex)
            {
                for (int i = 0; i < INTERNAL_clips.Length; i += 1)
                {
                    // XACT Clip volume
                    double clipVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // XACT Clip Offset in Bank
                    uint offset = reader.ReadUInt32();

                    // XACT Clip filter
                    byte filterFlags = reader.ReadByte();
                    byte filterType;
                    if ((filterFlags & 0x01) == 0x01)
                    {
                        filterType = (byte)((filterFlags >> 1) & 0x02);
                    }
                    else
                    {
                        filterType = 0xFF;
                    }
                    reader.ReadByte();                     // QFactor?
                    reader.ReadUInt16();                   // Frequency

                    // Store this for when we're done reading the clip.
                    long curPos = reader.BaseStream.Position;

                    // Go to the Clip in the Bank.
                    reader.BaseStream.Seek(offset, SeekOrigin.Begin);

                    // Parse the Clip.
                    INTERNAL_clips[i] = new XACTClip(reader, clipVolume, filterType);

                    // Back to where we were...
                    reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
                }
            }

            HasLoadedTracks = false;
        }
Esempio n. 20
0
        internal bool INTERNAL_update()
        {
            // If we're not running, save some instructions...
            if (!INTERNAL_timer.IsRunning)
            {
                return(true);
            }
            elapsedFrames += 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.InitializeClips();
                    INTERNAL_timer.Stop();
                    INTERNAL_timer.Reset();
                    INTERNAL_timer.Start();
                }

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

            // Trigger events for each track
            foreach (XACTClipInstance clip in INTERNAL_activeSound.Clips)
            {
                // Play events when the timestamp has been hit.
                for (int i = 0; i < clip.Events.Count; i += 1)
                {
                    EventInstance evt = clip.Events[i];

                    if (!evt.Played &&
                        INTERNAL_timer.ElapsedMilliseconds > evt.Timestamp)
                    {
                        evt.Apply(
                            this,
                            null,
                            INTERNAL_timer.ElapsedMilliseconds / 1000.0f
                            );
                    }
                }
            }


            // 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...
                    PlayWaveEventInstance evtInstance =
                        INTERNAL_playWaveEventBySound[INTERNAL_instancePool[i]];
                    double prevVolume = INTERNAL_instanceVolumes[i];
                    short  prevPitch  = INTERNAL_instancePitches[i];

                    // Then delete all the guff
                    INTERNAL_playWaveEventBySound.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
                    evtInstance.LoopCount += 1;
                    PlayWave(evtInstance, prevVolume, prevPitch);

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

            // Fade in/out
            float fadePerc = 1.0f;

            if (INTERNAL_fadeMode != FadeMode.None)
            {
                if (INTERNAL_fadeMode == FadeMode.FadeOut)
                {
                    if (INTERNAL_category.crossfadeType == CrossfadeType.Linear)
                    {
                        fadePerc = (
                            INTERNAL_fadeEnd -
                            (
                                INTERNAL_timer.ElapsedMilliseconds -
                                INTERNAL_fadeStart
                            )
                            ) / (float)INTERNAL_fadeEnd;
                    }
                    else
                    {
                        throw new NotImplementedException("Unhandled CrossfadeType!");
                    }
                    if (fadePerc <= 0.0f)
                    {
                        Stop(AudioStopOptions.Immediate);
                        INTERNAL_fadeMode = FadeMode.None;
                        return(false);
                    }
                }
                else if (INTERNAL_fadeMode == FadeMode.FadeIn)
                {
                    if (INTERNAL_category.crossfadeType == CrossfadeType.Linear)
                    {
                        fadePerc = INTERNAL_timer.ElapsedMilliseconds / (float)INTERNAL_fadeEnd;
                    }
                    else
                    {
                        throw new NotImplementedException("Unhandled CrossfadeType!");
                    }
                    if (fadePerc > 1.0f)
                    {
                        fadePerc          = 1.0f;
                        INTERNAL_fadeMode = FadeMode.None;
                    }
                }
                else if (INTERNAL_fadeMode == FadeMode.ReleaseRpc)
                {
                    float releasePerc = (
                        INTERNAL_timer.ElapsedMilliseconds -
                        INTERNAL_fadeStart
                        ) / (float)INTERNAL_maxRpcReleaseTime;
                    if (releasePerc > 1.0f)
                    {
                        Stop(AudioStopOptions.Immediate);
                        INTERNAL_fadeMode = FadeMode.None;
                        return(false);
                    }
                }
                else
                {
                    throw new NotImplementedException("Unsupported FadeMode!");
                }
            }

            // If everything has been played and finished, we're done here.
            if (INTERNAL_instancePool.Count == 0)
            {
                bool allPlayed = true;
                foreach (XACTClipInstance clipInstance in INTERNAL_activeSound.Clips)
                {
                    foreach (EventInstance evt in clipInstance.Events)
                    {
                        if (!evt.Played)
                        {
                            allPlayed = false;
                            break;
                        }
                    }
                }
                if (allPlayed)
                {
                    // If this is managed, we're done completely.
                    if (INTERNAL_isManaged)
                    {
                        Dispose();
                    }
                    else
                    {
                        KillCue();
                    }
                    if (INTERNAL_userControlledPlaying)
                    {
                        // We're "still" "playing" right now...
                        return(true);
                    }
                    IsStopped = true;
                    return(false);
                }
            }

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

            for (int i = 0; i < INTERNAL_activeSound.Sound.RPCCodes.Count; i += 1)
            {
                // Are we processing an RPC targeting the sound itself rather than a track?
                bool isSoundRpc = i == 0 && INTERNAL_activeSound.Sound.HasSoundRpcs;

                // If there is an RPC targeting the sound instance itself, it is handled in rpcVolume/rpcPitch, and the first track is at i-1.
                int trackRpcIndex = INTERNAL_activeSound.Sound.HasSoundRpcs ? i - 1 : i;

                // If this RPC Code is for a track that is not active yet, we have nothing to do.
                if (trackRpcIndex >= INTERNAL_instancePool.Count)
                {
                    // FIXME: This presumes that tracks start in order, which doesn't have to be true.
                    break;
                }
                if (!isSoundRpc)
                {
                    INTERNAL_rpcTrackVolumes[trackRpcIndex] = 0.0f;
                    INTERNAL_rpcTrackPitches[trackRpcIndex] = 0.0f;
                }

                foreach (uint curCode in INTERNAL_activeSound.Sound.RPCCodes[i])
                {
                    RPC   curRPC = INTERNAL_baseEngine.INTERNAL_getRPC(curCode);
                    float result;
                    if (!INTERNAL_baseEngine.INTERNAL_isGlobalVariable(curRPC.Variable))
                    {
                        float variableValue;

                        if (curRPC.Variable.Equals("AttackTime"))
                        {
                            PlayWaveEvent playWaveEvent =
                                (PlayWaveEvent)INTERNAL_activeSound.Sound.INTERNAL_clips[trackRpcIndex].Events[0];

                            long elapsedFromPlay = INTERNAL_timer.ElapsedMilliseconds
                                                   - playWaveEvent.Timestamp;
                            variableValue = elapsedFromPlay;
                        }
                        else if (curRPC.Variable.Equals("ReleaseTime"))
                        {
                            if (INTERNAL_fadeMode == FadeMode.ReleaseRpc)
                            {
                                long elapsedFromStop = INTERNAL_timer.ElapsedMilliseconds - INTERNAL_fadeStart;
                                variableValue = elapsedFromStop;
                            }
                            else
                            {
                                variableValue = 0.0f;
                            }
                        }
                        else
                        {
                            variableValue = GetVariable(curRPC.Variable);
                        }

                        result = curRPC.CalculateRPC(variableValue);
                    }
                    else
                    {
                        // It's a global variable we're looking for!
                        result = curRPC.CalculateRPC(
                            INTERNAL_baseEngine.GetGlobalVariable(
                                curRPC.Variable
                                )
                            );
                    }
                    if (curRPC.Parameter == RPCParameter.Volume)
                    {
                        // If this RPC targets the sound instance itself then apply to the dedicated variable.
                        if (isSoundRpc)
                        {
                            rpcVolume += result;
                        }
                        else
                        {
                            INTERNAL_rpcTrackVolumes[trackRpcIndex] += result;
                        }
                    }
                    else if (curRPC.Parameter == RPCParameter.Pitch)
                    {
                        float pitch = result;
                        if (isSoundRpc)
                        {
                            rpcPitch += pitch;
                        }
                        else
                        {
                            INTERNAL_rpcTrackPitches[trackRpcIndex] += pitch;
                        }
                    }
                    else if (curRPC.Parameter == RPCParameter.FilterFrequency)
                    {
                        // FIXME: Just listening to the last RPC!
                        float hf = result / 20000.0f;
                        float lf = 1.0f - hf;
                        if (isSoundRpc)
                        {
                            hfGain = hf;
                            lfGain = lf;
                        }
                        else
                        {
                            throw new NotImplementedException("Per-track filter RPCs!");
                        }
                    }
                    else
                    {
                        throw new NotImplementedException(
                                  "RPC Parameter Type: " + curRPC.Parameter.ToString()
                                  );
                    }
                }
            }

            // Sound effect instance updates
            for (int i = 0; i < INTERNAL_instancePool.Count; i += 1)
            {
                /* The final volume should be the combination of the
                 * authored volume, category volume, RPC sound/track
                 * volumes, event volumes, and fade.
                 */
                INTERNAL_instancePool[i].Volume = XACTCalculator.CalculateAmplitudeRatio(
                    INTERNAL_instanceVolumes[i] +
                    rpcVolume +
                    INTERNAL_rpcTrackVolumes[i] +
                    eventVolume
                    ) * INTERNAL_category.INTERNAL_volume.Value * fadePerc;

                /* The final pitch should be the combination of the
                 * authored pitch, RPC sound/track pitches, and event
                 * pitch.
                 *
                 * XACT uses -1200 to 1200 (+/- 12 semitones),
                 * XNA uses -1.0f to 1.0f (+/- 1 octave).
                 */
                INTERNAL_instancePool[i].Pitch = (
                    INTERNAL_instancePitches[i] +
                    rpcPitch +
                    INTERNAL_rpcTrackPitches[i] +
                    eventPitch
                    ) / 1200.0f;

                /* The final filter is determined by the instance's filter type,
                 * in addition to our calculation of the HF/LF gain values.
                 */
                byte fType = INTERNAL_instancePool[i].FilterType;
                if (fType == 0xFF)
                {
                    // No-op, no filter!
                }
                else if (fType == 0)
                {
                    INTERNAL_instancePool[i].INTERNAL_applyLowPassFilter(hfGain);
                }
                else if (fType == 1)
                {
                    INTERNAL_instancePool[i].INTERNAL_applyHighPassFilter(lfGain);
                }
                else if (fType == 2)
                {
                    INTERNAL_instancePool[i].INTERNAL_applyBandPassFilter(hfGain, lfGain);
                }
                else
                {
                    throw new InvalidOperationException("Unhandled filter type!");
                }

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

            return(true);
        }
Esempio n. 21
0
        public XACTSound(BinaryReader reader)
        {
            // Sound Effect Flags
            byte soundFlags = reader.ReadByte();
            bool complex    = (soundFlags & 0x01) != 0;

            // AudioCategory Index
            Category = reader.ReadUInt16();

            // Sound Volume
            Volume = XACTCalculator.ParseDecibel(reader.ReadByte());

            // Sound Pitch
            Pitch = (reader.ReadInt16() / 1000.0f);

            // Unknown value
            reader.ReadByte();

            // Length of Sound Entry, unused
            reader.ReadUInt16();

            // Number of Sound Clips
            if (complex)
            {
                INTERNAL_clips = new XACTClip[reader.ReadByte()];
            }
            else
            {
                // Simple Sounds always have 1 PlayWaveEvent.
                INTERNAL_clips = new XACTClip[1];
                ushort track    = reader.ReadUInt16();
                byte   waveBank = reader.ReadByte();
                INTERNAL_clips[0] = new XACTClip(track, waveBank);
            }

            // Parse RPC Properties
            RPCCodes = new uint[0];             // Eww... -flibit
            if ((soundFlags & 0x0E) != 0)
            {
                // RPC data length, unused
                ushort rpcDataLength = reader.ReadUInt16();

                // Number of RPC Presets
                RPCCodes = new uint[reader.ReadByte()];

                // Obtain RPC curve codes
                for (byte i = 0; i < RPCCodes.Length; i += 1)
                {
                    RPCCodes[i] = reader.ReadUInt32();
                }

                // Seek past the rest - we dunno what it is yet.
                reader.BaseStream.Seek(
                    rpcDataLength - 2 - 1 - (4 * RPCCodes.Length),
                    SeekOrigin.Current
                    );
            }

            // Parse DSP Presets
            DSPCodes = new uint[0];             // Eww... -flibit
            if ((soundFlags & 0x10) != 0)
            {
                // DSP Presets Length, unused
                reader.ReadUInt16();

                // Number of DSP Presets
                DSPCodes = new uint[reader.ReadByte()];

                // Obtain DSP Preset codes
                for (byte j = 0; j < DSPCodes.Length; j += 1)
                {
                    DSPCodes[j] = reader.ReadUInt32();
                }
            }

            // Parse Sound Events
            if (complex)
            {
                for (int i = 0; i < INTERNAL_clips.Length; i += 1)
                {
                    // XACT Clip volume
                    double clipVolume = XACTCalculator.ParseDecibel(reader.ReadByte());

                    // XACT Clip Offset in Bank
                    uint offset = reader.ReadUInt32();

                    // Unknown value
                    reader.ReadUInt32();

                    // Store this for when we're done reading the clip.
                    long curPos = reader.BaseStream.Position;

                    // Go to the Clip in the Bank.
                    reader.BaseStream.Seek(offset, SeekOrigin.Begin);

                    // Parse the Clip.
                    INTERNAL_clips[i] = new XACTClip(reader, clipVolume);

                    // Back to where we were...
                    reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
                }
            }

            HasLoadedTracks = false;
        }
Esempio n. 22
0
        public AudioEngine(string settingsFile)
        {
            if (String.IsNullOrEmpty(settingsFile))
            {
                throw new ArgumentNullException("settingsFile");
            }

            using (Stream stream = TitleContainer.OpenStream(settingsFile))
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    // Check the file header. Should be 'XGSF'
                    if (reader.ReadUInt32() != 0x46534758)
                    {
                        throw new ArgumentException("XGSF format not recognized!");
                    }

                    // Check the Content and Tool versions
                    if (reader.ReadUInt16() != ContentVersion)
                    {
                        throw new ArgumentException("XGSF Content version!");
                    }
                    if (reader.ReadUInt16() != 42)
                    {
                        throw new ArgumentException("XGSF Tool version!");
                    }

                    // Unknown value
                    reader.ReadUInt16();

                    // Last Modified, Unused
                    reader.ReadUInt64();

                    // XACT Version, Unused
                    reader.ReadByte();

                    // Number of AudioCategories
                    ushort numCategories = reader.ReadUInt16();

                    // Number of XACT Variables
                    ushort numVariables = reader.ReadUInt16();

                    // KEY#1 Length
                    /*ushort numKeyOne =*/ reader.ReadUInt16();

                    // KEY#2 Length
                    /*ushort numKeyTwo =*/ reader.ReadUInt16();

                    // Number of RPC Variables
                    ushort numRPCs = reader.ReadUInt16();

                    // Number of DSP Presets/Parameters
                    ushort numDSPPresets    = reader.ReadUInt16();
                    ushort numDSPParameters = reader.ReadUInt16();

                    // Category Offset in XGS File
                    uint categoryOffset = reader.ReadUInt32();

                    // Variable Offset in XGS File
                    uint variableOffset = reader.ReadUInt32();

                    // KEY#1 Offset
                    /*uint keyOneOffset =*/ reader.ReadUInt32();

                    // Category Name Index Offset, unused
                    reader.ReadUInt32();

                    // KEY#2 Offset
                    /*uint keyTwoOffset =*/ reader.ReadUInt32();

                    // Variable Name Index Offset, unused
                    reader.ReadUInt32();

                    // Category Name Offset in XGS File
                    uint categoryNameOffset = reader.ReadUInt32();

                    // Variable Name Offset in XGS File
                    uint variableNameOffset = reader.ReadUInt32();

                    // RPC Variable Offset in XGS File
                    uint rpcOffset = reader.ReadUInt32();

                    // DSP Preset/Parameter Offsets in XGS File
                    uint dspPresetOffset    = reader.ReadUInt32();
                    uint dspParameterOffset = reader.ReadUInt32();

                    /* Unknown table #1
                     * reader.BaseStream.Seek(keyOneOffset, SeekOrigin.Begin);
                     * for (int i = 0; i < numKeyOne; i += 1)
                     * {
                     *      // Appears to consistently be 16 shorts?
                     *      System.Console.WriteLine(reader.ReadInt16());
                     * }
                     * /* OhGodNo
                     *  1, -1,  4, -1,
                     *  3, -1, -1,  7,
                     * -1,  2,  5, -1,
                     *  6,  0, -1, -1
                     *
                     * Naddachance
                     *  1, -1,  4, -1,
                     *  5, -1, -1, -1,
                     * -1,  2, -1, -1,
                     *  3,  0, -1, -1
                     *
                     * TFA
                     *  1, -1, -1, -1,
                     * -1, -1, -1, -1,
                     * -1,  2, -1, -1,
                     * -1, -0, -1, -1
                     */

                    /* Unknown table #2
                     * reader.BaseStream.Seek(keyTwoOffset, SeekOrigin.Begin);
                     * for (int i = 0; i < numKeyTwo; i += 1)
                     * {
                     *      // Appears to be between 16-20 shorts?
                     *      System.Console.WriteLine(reader.ReadInt16());
                     * }
                     * /* OhGodNo
                     *  2,  7,  1, -1,
                     * -1, 10, 19, -1,
                     *  11, 3, -1, -1,
                     *  8, -1, 14,  5,
                     * 12,  0,  4,  6
                     *
                     * Naddachance
                     *  2,  3, -1, -1,
                     *  9, -1,  7, -1,
                     * 10,  0,  1,  5,
                     * -1, -1, -1, -1
                     *
                     * TFA
                     *  2,  3, -1, -1,
                     * -1, -1, -1, -1,
                     * -1,  0,  1,  5,
                     * -1, -1, -1, -1
                     */

                    // Obtain the Audio Category Names
                    reader.BaseStream.Seek(categoryNameOffset, SeekOrigin.Begin);
                    string[] categoryNames = new string[numCategories];
                    for (int i = 0; i < numCategories; i += 1)
                    {
                        List <char> builtString = new List <char>();
                        while (reader.PeekChar() != 0)
                        {
                            builtString.Add(reader.ReadChar());
                        }
                        reader.ReadChar();                 // Null terminator
                        categoryNames[i] = new string(builtString.ToArray());
                    }

                    // Obtain the Audio Categories
                    reader.BaseStream.Seek(categoryOffset, SeekOrigin.Begin);
                    INTERNAL_categories = new List <AudioCategory>();
                    for (int i = 0; i < numCategories; i += 1)
                    {
                        // Maximum instances
                        byte maxInstances = reader.ReadByte();

                        // Fade In/Out
                        ushort fadeInMS  = reader.ReadUInt16();
                        ushort fadeOutMS = reader.ReadUInt16();

                        // Instance Behavior Flags
                        byte instanceFlags = reader.ReadByte();
                        int  fadeType      = instanceFlags & 0x07;
                        int  maxBehavior   = instanceFlags >> 3;

                        // Parent Category
                        short parent = reader.ReadInt16();

                        // Volume
                        float volume = XACTCalculator.CalculateAmplitudeRatio(
                            XACTCalculator.ParseDecibel(
                                reader.ReadByte()
                                )
                            );

                        // Visibility Flags, unused
                        reader.ReadByte();

                        // Add to the engine list and the parent category
                        INTERNAL_categories.Add(
                            new AudioCategory(
                                categoryNames[i],
                                volume,
                                maxInstances,
                                maxBehavior,
                                fadeInMS,
                                fadeOutMS,
                                fadeType
                                )
                            );
                        if (parent != -1)
                        {
                            INTERNAL_categories[parent].subCategories.Add(
                                INTERNAL_categories[i]
                                );
                        }
                    }

                    // Obtain the Variable Names
                    reader.BaseStream.Seek(variableNameOffset, SeekOrigin.Begin);
                    string[] variableNames = new string[numVariables];
                    for (int i = 0; i < numVariables; i += 1)
                    {
                        List <char> builtString = new List <char>();
                        while (reader.PeekChar() != 0)
                        {
                            builtString.Add(reader.ReadChar());
                        }
                        reader.ReadChar();                 // Null terminator
                        variableNames[i] = new string(builtString.ToArray());
                    }

                    // Obtain the Variables
                    reader.BaseStream.Seek(variableOffset, SeekOrigin.Begin);
                    INTERNAL_variables = new List <Variable>();
                    for (int i = 0; i < numVariables; i += 1)
                    {
                        // Variable Accessibility (See Variable constructor)
                        byte varFlags = reader.ReadByte();

                        // Variable Value, Boundaries
                        float initialValue = reader.ReadSingle();
                        float minValue     = reader.ReadSingle();
                        float maxValue     = reader.ReadSingle();

                        // Add to the engine list
                        INTERNAL_variables.Add(
                            new Variable(
                                variableNames[i],
                                (varFlags & 0x01) != 0,
                                (varFlags & 0x02) != 0,
                                (varFlags & 0x04) == 0,
                                (varFlags & 0x08) != 0,
                                initialValue,
                                minValue,
                                maxValue
                                )
                            );
                    }

                    // Obtain the RPC Curves
                    reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin);
                    INTERNAL_RPCs = new Dictionary <long, RPC>();
                    for (int i = 0; i < numRPCs; i += 1)
                    {
                        // RPC "Code", used by the SoundBanks
                        long rpcCode = reader.BaseStream.Position;

                        // RPC Variable
                        ushort rpcVariable = reader.ReadUInt16();

                        // Number of RPC Curve Points
                        byte numPoints = reader.ReadByte();

                        // RPC Parameter
                        ushort rpcParameter = reader.ReadUInt16();

                        // RPC Curve Points
                        RPCPoint[] rpcPoints = new RPCPoint[numPoints];
                        for (byte j = 0; j < numPoints; j += 1)
                        {
                            float x    = reader.ReadSingle();
                            float y    = reader.ReadSingle();
                            byte  type = reader.ReadByte();
                            rpcPoints[j] = new RPCPoint(
                                x, y,
                                (RPCPointType)type
                                );
                        }

                        // Add to the engine list
                        INTERNAL_RPCs.Add(
                            rpcCode,
                            new RPC(
                                INTERNAL_variables[rpcVariable].Name,
                                rpcParameter,
                                rpcPoints
                                )
                            );
                    }

                    // Obtain the DSP Parameters
                    reader.BaseStream.Seek(dspParameterOffset, SeekOrigin.Begin);
                    INTERNAL_dspParameters = new List <DSPParameter>();
                    for (int i = 0; i < numDSPParameters; i += 1)
                    {
                        // Effect Parameter Type
                        byte type = reader.ReadByte();

                        // Effect value, boundaries
                        float value  = reader.ReadSingle();
                        float minVal = reader.ReadSingle();
                        float maxVal = reader.ReadSingle();

                        // Unknown value
                        reader.ReadUInt16();

                        // Add to Parameter list
                        INTERNAL_dspParameters.Add(
                            new DSPParameter(
                                type,
                                value,
                                minVal,
                                maxVal
                                )
                            );
                    }

                    // Obtain the DSP Presets
                    reader.BaseStream.Seek(dspPresetOffset, SeekOrigin.Begin);
                    INTERNAL_dspPresets = new Dictionary <long, DSPPreset>();
                    int total = 0;
                    for (int i = 0; i < numDSPPresets; i += 1)
                    {
                        // DSP "Code", used by the SoundBanks
                        long dspCode = reader.BaseStream.Position;

                        // Preset Accessibility
                        bool global = (reader.ReadByte() == 1);

                        // Number of preset parameters
                        uint numParams = reader.ReadUInt32();

                        // Obtain DSP Parameters
                        DSPParameter[] parameters = new DSPParameter[numParams];
                        for (uint j = 0; j < numParams; j += 1)
                        {
                            parameters[j] = INTERNAL_dspParameters[total];
                            total        += 1;
                        }

                        // Add to DSP Preset list
                        INTERNAL_dspPresets.Add(
                            dspCode,
                            new DSPPreset(
                                global,
                                parameters
                                )
                            );
                    }
                }

            // Create the WaveBank Dictionary
            INTERNAL_waveBanks = new Dictionary <string, WaveBank>();

            // Finally.
            IsDisposed = false;
        }
Esempio n. 23
0
        internal bool INTERNAL_update()
        {
            // If this is our first update, time to play!
            if (INTERNAL_queuedPlayback)
            {
                INTERNAL_queuedPlayback = false;
                foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
                {
                    sfi.Play();
                    if (INTERNAL_queuedPaused)
                    {
                        sfi.Pause();
                    }
                }
                INTERNAL_queuedPaused = false;
            }

            for (int i = 0; i < INTERNAL_instancePool.Count; i += 1)
            {
                if (INTERNAL_instancePool[i].INTERNAL_timer.ElapsedMilliseconds > INTERNAL_instancePool[i].INTERNAL_delayMS)
                {
                    // Okay, play this NOW!
                    INTERNAL_instancePool[i].Play();
                    if (IsPaused)
                    {
                        INTERNAL_instancePool[i].Pause();
                    }
                }
                if (INTERNAL_instancePool[i].State == SoundState.Stopped)
                {
                    INTERNAL_instancePool[i].Dispose();
                    INTERNAL_instancePool.RemoveAt(i);
                    INTERNAL_instanceVolumes.RemoveAt(i);
                    INTERNAL_instancePitches.RemoveAt(i);
                    i -= 1;
                }
            }

            // User control updates
            if (INTERNAL_data.IsUserControlled)
            {
                if (INTERNAL_userControlledPlaying &&
                    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();
                    if (!INTERNAL_calculateNextSound())
                    {
                        // Nothing to play, bail.
                        return(true);
                    }
                    INTERNAL_setupSounds();
                    foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
                    {
                        sfi.Play();
                    }
                }

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

            if (INTERNAL_isPositional)
            {
                foreach (SoundEffectInstance sfi in INTERNAL_instancePool)
                {
                    sfi.Apply3D(
                        INTERNAL_listener,
                        INTERNAL_emitter
                        );
                }
            }

            float rpcVolume = 1.0f;
            float rpcPitch  = 0.0f;

            foreach (uint curCode in INTERNAL_activeSound.RPCCodes)
            {
                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)
                {
                    rpcVolume *= XACTCalculator.CalculateAmplitudeRatio(result / 100.0);
                }
                else if (curRPC.Parameter == RPCParameter.Pitch)
                {
                    rpcPitch += result / 1000.0f;
                }
                else if (curRPC.Parameter == RPCParameter.FilterFrequency)
                {
                    // TODO: Filters?
                }
                else
                {
                    throw new Exception("RPC Parameter Type: " + curRPC.Parameter.ToString());
                }
            }
            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] * GetVariable("Volume") * rpcVolume;

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

            // Finally, check if we're still active.
            if (IsStopped && !INTERNAL_queuedPlayback && !INTERNAL_userControlledPlaying)
            {
                // If this is managed, we're done here.
                if (INTERNAL_isManaged)
                {
                    Dispose();
                }
                return(false);
            }
            return(true);
        }