Beispiel #1
0
        public SoundBank(AudioEngine audioEngine, string filename)
        {
            if (audioEngine == null)
            {
                throw new ArgumentNullException("audioEngine");
            }
            if (String.IsNullOrEmpty(filename))
            {
                throw new ArgumentNullException("filename");
            }

            INTERNAL_baseEngine = audioEngine;

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

                    // Check the content version. Assuming XNA4 Refresh.
                    if (reader.ReadUInt16() != AudioEngine.ContentVersion)
                    {
                        throw new ArgumentException("SDBK Content version!");
                    }

                    // Check the tool version. Assuming XNA4 Refresh.
                    if (reader.ReadUInt16() != 43)
                    {
                        throw new ArgumentException("SDBK Tool version!");
                    }

                    // CRC, unused
                    reader.ReadUInt16();

                    // Last modified, unused
                    reader.ReadUInt64();

                    // Unknown value, Internet suggests platform
                    reader.ReadByte();

                    // Cue Counts
                    ushort numCueSimple  = reader.ReadUInt16();
                    ushort numCueComplex = reader.ReadUInt16();

                    // Unknown value
                    reader.ReadUInt16();

                    // Total Cues, unused
                    reader.ReadUInt16();

                    // Number of associated WaveBanks
                    byte numWaveBanks = reader.ReadByte();

                    // Unknown, Internet suggest number of "sounds"
                    reader.ReadUInt16();

                    // Cue Name Table Length
                    ushort cueNameTableLength = reader.ReadUInt16();

                    // Unknown value
                    reader.ReadUInt16();

                    // Cue Offsets
                    uint cueSimpleOffset  = reader.ReadUInt32();
                    uint cueComplexOffset = reader.ReadUInt32();

                    // Cue Name Table Offset
                    uint cueNameTableOffset = reader.ReadUInt32();

                    // Unknown value
                    reader.ReadUInt32();

                    // Variable Tables Offset, unused
                    reader.ReadUInt32();

                    // Unknown value
                    reader.ReadUInt32();

                    // WaveBank Name Table Offset
                    uint waveBankNameTableOffset = reader.ReadUInt32();

                    // Cue Name Hash Offsets, unused
                    reader.ReadUInt32();
                    reader.ReadUInt32();

                    // Unknown value, Internet suggest "sounds" offset
                    reader.ReadUInt32();

                    // SoundBank Name, unused
                    System.Text.Encoding.UTF8.GetString(
                        reader.ReadBytes(64), 0, 64
                        ).Replace("\0", "");

                    // Parse WaveBank names
                    soundBankStream.Seek(waveBankNameTableOffset, SeekOrigin.Begin);
                    INTERNAL_waveBankNames = new List <string>();
                    for (byte i = 0; i < numWaveBanks; i += 1)
                    {
                        INTERNAL_waveBankNames.Add(
                            System.Text.Encoding.UTF8.GetString(
                                reader.ReadBytes(64), 0, 64
                                ).Replace("\0", "")
                            );
                    }

                    // Parse Cue name list
                    soundBankStream.Seek(cueNameTableOffset, SeekOrigin.Begin);
                    string[] cueNames = System.Text.Encoding.UTF8.GetString(
                        reader.ReadBytes(cueNameTableLength),
                        0,
                        cueNameTableLength
                        ).Split('\0');

                    // Create our CueData Dictionary
                    INTERNAL_cueData = new Dictionary <string, CueData>();

                    // Parse Simple Cues
                    soundBankStream.Seek(cueSimpleOffset, SeekOrigin.Begin);
                    for (ushort i = 0; i < numCueSimple; i += 1)
                    {
                        // Cue flags, unused
                        reader.ReadByte();

                        // Cue Sound Offset
                        uint offset = reader.ReadUInt32();

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

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

                        // Parse the Sound
                        INTERNAL_cueData.Add(
                            cueNames[i],
                            new CueData(new XACTSound(reader))
                            );

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

                    // Parse Complex Cues
                    soundBankStream.Seek(cueComplexOffset, SeekOrigin.Begin);
                    for (ushort i = 0; i < numCueComplex; i += 1)
                    {
                        // Cue flags
                        byte cueFlags = reader.ReadByte();

                        if ((cueFlags & 0x04) != 0)                 // FIXME: ???
                        {
                            // Cue Sound Offset
                            uint offset = reader.ReadUInt32();

                            // Unknown value
                            reader.ReadUInt32();

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

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

                            // Parse the Sound
                            INTERNAL_cueData.Add(
                                cueNames[numCueSimple + i],
                                new CueData(new XACTSound(reader))
                                );

                            // Back to where we were...
                            reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
                        }
                        else
                        {
                            // Variation Table Offset for this Cue
                            uint offset = reader.ReadUInt32();

                            // Transition Table Offset for this Cue, unused
                            reader.ReadUInt32();

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

                            // Seek to the Variation Table in the file
                            reader.BaseStream.Seek(offset, SeekOrigin.Begin);

                            // Number of Variations in the Table
                            ushort numVariations = reader.ReadUInt16();

                            // Variation Table Flags
                            ushort varTableFlags = reader.ReadUInt16();

                            // Unknown value
                            reader.ReadUInt16();

                            // Probability Control Variable, if applicable
                            ushort variable = reader.ReadUInt16();

                            // Create data for the CueData
                            XACTSound[] cueSounds = new XACTSound[numVariations];
                            float[,] cueProbs = new float[numVariations, 2];

                            // Used to determine Variation storage format
                            int varTableType = (varTableFlags >> 3) & 0x0007;

                            for (ushort j = 0; j < numVariations; j += 1)
                            {
                                if (varTableType == 0)
                                {
                                    // Wave with byte min/max
                                    ushort track    = reader.ReadUInt16();
                                    byte   waveBank = reader.ReadByte();
                                    byte   wMin     = reader.ReadByte();
                                    byte   wMax     = reader.ReadByte();

                                    // Create the Sound
                                    cueSounds[j] = new XACTSound(track, waveBank);

                                    // Calculate probability based on weight
                                    cueProbs[j, 0] = wMax / 255.0f;
                                    cueProbs[j, 1] = wMin / 255.0f;
                                }
                                else if (varTableType == 1)
                                {
                                    // Complex with byte min/max
                                    uint varOffset = reader.ReadUInt32();
                                    byte wMin      = reader.ReadByte();
                                    byte wMax      = reader.ReadByte();

                                    // Store for sound read
                                    long varPos = reader.BaseStream.Position;

                                    // Seek to the sound in the Bank
                                    reader.BaseStream.Seek(varOffset, SeekOrigin.Begin);

                                    // Read the sound
                                    cueSounds[j] = new XACTSound(reader);

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

                                    // Calculate probability based on weight
                                    cueProbs[j, 0] = wMax / 255.0f;
                                    cueProbs[j, 1] = wMin / 255.0f;
                                }
                                else if (varTableType == 3)
                                {
                                    // Complex with float min/max
                                    uint  varOffset = reader.ReadUInt32();
                                    float wMin      = reader.ReadSingle();
                                    float wMax      = reader.ReadSingle();

                                    // Unknown value
                                    reader.ReadUInt32();

                                    // Store for sound read
                                    long varPos = reader.BaseStream.Position;

                                    // Seek to the sound in the Bank
                                    reader.BaseStream.Seek(varOffset, SeekOrigin.Begin);

                                    // Read the sound
                                    cueSounds[j] = new XACTSound(reader);

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

                                    // Calculate probability based on weight
                                    cueProbs[j, 0] = wMax;
                                    cueProbs[j, 1] = wMin;
                                }
                                else if (varTableType == 4)
                                {
                                    // Compact Wave
                                    ushort track    = reader.ReadUInt16();
                                    byte   waveBank = reader.ReadByte();

                                    // Create the Sound
                                    cueSounds[j] = new XACTSound(track, waveBank);

                                    // FIXME: Assume Sound weight is 100%
                                    cueProbs[j, 0] = 1.0f;
                                    cueProbs[j, 1] = 0.0f;
                                }
                                else
                                {
                                    throw new NotSupportedException();
                                }
                            }

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

                            // Add Built CueData to Dictionary
                            INTERNAL_cueData.Add(
                                cueNames[numCueSimple + i],
                                new CueData(
                                    cueSounds,
                                    cueProbs,
                                    (varTableType == 3) ? INTERNAL_baseEngine.INTERNAL_getVariableName(variable) : String.Empty
                                    )
                                );
                        }

                        // Cue instance limit
                        byte instanceLimit = reader.ReadByte();

                        // Fade In/Out, unused
                        reader.ReadUInt16();
                        reader.ReadUInt16();

                        // Cue max instance behavior
                        byte behavior = reader.ReadByte();

                        INTERNAL_cueData[cueNames[numCueSimple + i]].SetLimit(
                            instanceLimit,
                            behavior
                            );
                    }
                }
            IsDisposed = false;
        }
Beispiel #2
0
        public SoundBank(AudioEngine audioEngine, string filename)
        {
            if (audioEngine == null)
            {
                throw new ArgumentNullException("audioEngine");
            }
            if (String.IsNullOrEmpty(filename))
            {
                throw new ArgumentNullException("filename");
            }

            INTERNAL_baseEngine = audioEngine;

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

                // Check the content version. Assuming XNA4 Refresh.
                if (reader.ReadUInt16() != AudioEngine.ContentVersion)
                {
                    throw new ArgumentException("SDBK Content version!");
                }

                // Check the tool version. Assuming XNA4 Refresh.
                if (reader.ReadUInt16() != 43)
                {
                    throw new ArgumentException("SDBK Tool version!");
                }

                // CRC, unused
                reader.ReadUInt16();

                // Last modified, unused
                reader.ReadUInt64();

                // Unknown value, Internet suggests platform
                reader.ReadByte();

                // Cue Counts
                ushort numCueSimple = reader.ReadUInt16();
                ushort numCueComplex = reader.ReadUInt16();

                // Unknown value
                reader.ReadUInt16();

                // Total Cues, unused
                reader.ReadUInt16();

                // Number of associated WaveBanks
                byte numWaveBanks = reader.ReadByte();

                // Unknown, Internet suggest number of "sounds"
                reader.ReadUInt16();

                // Cue Name Table Length
                ushort cueNameTableLength = reader.ReadUInt16();

                // Unknown value
                reader.ReadUInt16();

                // Cue Offsets
                uint cueSimpleOffset = reader.ReadUInt32();
                uint cueComplexOffset = reader.ReadUInt32();

                // Cue Name Table Offset
                uint cueNameTableOffset = reader.ReadUInt32();

                // Unknown value
                reader.ReadUInt32();

                // Variable Tables Offset, unused
                reader.ReadUInt32();

                // Unknown value
                reader.ReadUInt32();

                // WaveBank Name Table Offset
                uint waveBankNameTableOffset = reader.ReadUInt32();

                // Cue Name Hash Offsets, unused
                reader.ReadUInt32();
                reader.ReadUInt32();

                // Unknown value, Internet suggest "sounds" offset
                reader.ReadUInt32();

                // SoundBank Name, unused
                reader.ReadBytes(64);

                // Parse WaveBank names
                soundBankStream.Seek(waveBankNameTableOffset, SeekOrigin.Begin);
                INTERNAL_waveBankNames = new List<string>();
                for (byte i = 0; i < numWaveBanks; i += 1)
                {
                    INTERNAL_waveBankNames.Add(
                        System.Text.Encoding.UTF8.GetString(
                            reader.ReadBytes(64), 0, 64
                        ).Replace("\0", "")
                    );
                }

                // Parse Cue name list
                soundBankStream.Seek(cueNameTableOffset, SeekOrigin.Begin);
                string[] cueNames = System.Text.Encoding.UTF8.GetString(
                    reader.ReadBytes(cueNameTableLength),
                    0,
                    cueNameTableLength
                ).Split('\0');

                // Create our CueData Dictionary
                INTERNAL_cueData = new Dictionary<string, CueData>();

                // Parse Simple Cues
                soundBankStream.Seek(cueSimpleOffset, SeekOrigin.Begin);
                for (ushort i = 0; i < numCueSimple; i += 1)
                {
                    // Cue flags, unused
                    reader.ReadByte();

                    // Cue Sound Offset
                    uint offset = reader.ReadUInt32();

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

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

                    // Parse the Sound
                    INTERNAL_cueData.Add(
                        cueNames[i],
                        new CueData(new XACTSound(reader))
                    );

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

                // Parse Complex Cues
                soundBankStream.Seek(cueComplexOffset, SeekOrigin.Begin);
                for (ushort i = 0; i < numCueComplex; i += 1)
                {
                    // Cue flags
                    byte cueFlags = reader.ReadByte();

                    if ((cueFlags & 0x04) != 0) // FIXME: ???
                    {
                        // Cue Sound Offset
                        uint offset = reader.ReadUInt32();

                        // Unknown value
                        reader.ReadUInt32();

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

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

                        // Parse the Sound
                        INTERNAL_cueData.Add(
                            cueNames[numCueSimple + i],
                            new CueData(new XACTSound(reader))
                        );

                        // Back to where we were...
                        reader.BaseStream.Seek(curPos, SeekOrigin.Begin);
                    }
                    else
                    {
                        // Variation Table Offset for this Cue
                        uint offset = reader.ReadUInt32();

                        // Transition Table Offset for this Cue, unused
                        reader.ReadUInt32();

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

                        // Seek to the Variation Table in the file
                        reader.BaseStream.Seek(offset, SeekOrigin.Begin);

                        // Number of Variations in the Table
                        ushort numVariations = reader.ReadUInt16();

                        // Variation Table Flags
                        ushort varTableFlags = reader.ReadUInt16();

                        // Unknown value
                        reader.ReadUInt16();

                        // Probability Control Variable, if applicable
                        ushort variable = reader.ReadUInt16();

                        // Create data for the CueData
                        XACTSound[] cueSounds = new XACTSound[numVariations];
                        float[,] cueProbs = new float[numVariations, 2];

                        // Used to determine Variation storage format
                        int varTableType = (varTableFlags >> 3) & 0x0007;

                        for (ushort j = 0; j < numVariations; j += 1)
                        {
                            if (varTableType == 0)
                            {
                                // Wave with byte min/max
                                ushort track = reader.ReadUInt16();
                                byte waveBank = reader.ReadByte();
                                byte wMin = reader.ReadByte();
                                byte wMax = reader.ReadByte();

                                // Create the Sound
                                cueSounds[j] = new XACTSound(track, waveBank);

                                // Calculate probability based on weight
                                cueProbs[j, 0] = wMax / 255.0f;
                                cueProbs[j, 1] = wMin / 255.0f;
                            }
                            else if (varTableType == 1)
                            {
                                // Complex with byte min/max
                                uint varOffset = reader.ReadUInt32();
                                byte wMin = reader.ReadByte();
                                byte wMax = reader.ReadByte();

                                // Store for sound read
                                long varPos = reader.BaseStream.Position;

                                // Seek to the sound in the Bank
                                reader.BaseStream.Seek(varOffset, SeekOrigin.Begin);

                                // Read the sound
                                cueSounds[j] = new XACTSound(reader);

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

                                // Calculate probability based on weight
                                cueProbs[j, 0] = wMax / 255.0f;
                                cueProbs[j, 1] = wMin / 255.0f;
                            }
                            else if (varTableType == 3)
                            {
                                // Complex with float min/max
                                uint varOffset = reader.ReadUInt32();
                                float wMin = reader.ReadSingle();
                                float wMax = reader.ReadSingle();

                                // Unknown value
                                reader.ReadUInt32();

                                // Store for sound read
                                long varPos = reader.BaseStream.Position;

                                // Seek to the sound in the Bank
                                reader.BaseStream.Seek(varOffset, SeekOrigin.Begin);

                                // Read the sound
                                cueSounds[j] = new XACTSound(reader);

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

                                // Calculate probability based on weight
                                cueProbs[j, 0] = wMax;
                                cueProbs[j, 1] = wMin;
                            }
                            else if (varTableType == 4)
                            {
                                // Compact Wave
                                ushort track = reader.ReadUInt16();
                                byte waveBank = reader.ReadByte();

                                // Create the Sound
                                cueSounds[j] = new XACTSound(track, waveBank);

                                // FIXME: Assume Sound weight is 100%
                                cueProbs[j, 0] = 1.0f;
                                cueProbs[j, 1] = 0.0f;
                            }
                            else
                            {
                                throw new NotSupportedException();
                            }
                        }

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

                        // Add Built CueData to Dictionary
                        INTERNAL_cueData.Add(
                            cueNames[numCueSimple + i],
                            new CueData(
                                cueSounds,
                                cueProbs,
                                (varTableType == 3) ? INTERNAL_baseEngine.INTERNAL_getVariableName(variable) : String.Empty
                            )
                        );
                    }

                    // Cue instance limit
                    byte instanceLimit = reader.ReadByte();

                    // Fade In/Out, unused
                    reader.ReadUInt16();
                    reader.ReadUInt16();

                    // Cue max instance behavior
                    byte behavior = reader.ReadByte();

                    INTERNAL_cueData[cueNames[numCueSimple + i]].SetLimit(
                        instanceLimit,
                        behavior
                    );
                }
            }
            IsDisposed = false;
        }