Ejemplo n.º 1
0
        internal RpcVariable[] CreateCueVariables()
        {
            var clone = new RpcVariable[_cueVariables.Length];

            Array.Copy(_cueVariables, clone, _cueVariables.Length);
            return(clone);
        }
Ejemplo n.º 2
0
        /// <param name="settingsFile">Path to a XACT settings file.</param>
        /// <param name="lookAheadTime">
        /// Determines how many milliseconds the engine will look ahead when
        /// determing when to transition to another sound.
        /// </param>
        /// <param name="rendererId">A string that specifies the audio renderer to use.</param>
        /// <remarks>
        /// For the best results, use a <paramref name="lookAheadTime"/> of 250 milliseconds or greater.
        /// </remarks>
        public AudioEngine(string settingsFile, TimeSpan lookAheadTime, string rendererId)
        {
            if (string.IsNullOrEmpty(settingsFile))
            {
                throw new ArgumentNullException(nameof(settingsFile));
            }

            // Read the xact settings file
            // Credits to alisci01 for initial format documentation
            using (var reader = new BinaryReader(OpenStream(settingsFile)))
            {
                uint magic = reader.ReadUInt32();
                if (magic != 0x46534758) //'XGFS'
                {
                    throw new InvalidDataException("XGS format not recognized");
                }

                reader.ReadUInt16(); // toolVersion
                uint formatVersion = reader.ReadUInt16();
                if (formatVersion != 42)
                {
                    Debug.WriteLine("Warning: XGS format " + formatVersion + " not supported!");
                }

                reader.ReadUInt16(); // crc
                reader.ReadUInt32(); // lastModifiedLow
                reader.ReadUInt32(); // lastModifiedHigh
                reader.ReadByte();   //unkn, 0x03. Platform?

                uint numCats = reader.ReadUInt16();
                uint numVars = reader.ReadUInt16();

                reader.ReadUInt16(); //unkn, 0x16
                reader.ReadUInt16(); //unkn, 0x16

                uint numRpc        = reader.ReadUInt16();
                uint numDspPresets = reader.ReadUInt16();
                uint numDspParams  = reader.ReadUInt16();

                uint catsOffset = reader.ReadUInt32();
                uint varsOffset = reader.ReadUInt32();

                reader.ReadUInt32(); //unknown, leads to a short with value of 1?
                reader.ReadUInt32(); // catNameIndexOffset
                reader.ReadUInt32(); //unknown, two shorts of values 2 and 3?
                reader.ReadUInt32(); // varNameIndexOffset

                uint catNamesOffset = reader.ReadUInt32();
                uint varNamesOffset = reader.ReadUInt32();
                uint rpcOffset      = reader.ReadUInt32();
                reader.ReadUInt32(); // dspPresetsOffset
                uint dspParamsOffset = reader.ReadUInt32();

                reader.BaseStream.Seek(catNamesOffset, SeekOrigin.Begin);
                string[] categoryNames = ReadNullTerminatedStrings(numCats, reader);

                Categories = new AudioCategory[numCats];
                reader.BaseStream.Seek(catsOffset, SeekOrigin.Begin);
                for (int i = 0; i < numCats; i++)
                {
                    Categories[i] = new AudioCategory(this, categoryNames[i], reader);
                    _categoryLookup.Add(categoryNames[i], i);
                }

                reader.BaseStream.Seek(varNamesOffset, SeekOrigin.Begin);
                string[] varNames = ReadNullTerminatedStrings(numVars, reader);

                var variables       = new List <RpcVariable>();
                var cueVariables    = new List <RpcVariable>();
                var globalVariables = new List <RpcVariable>();
                reader.BaseStream.Seek(varsOffset, SeekOrigin.Begin);
                for (var i = 0; i < numVars; i++)
                {
                    var v = new RpcVariable
                    {
                        Name      = varNames[i],
                        Flags     = reader.ReadByte(),
                        InitValue = reader.ReadSingle(),
                        MinValue  = reader.ReadSingle(),
                        MaxValue  = reader.ReadSingle()
                    };
                    v.Value = v.InitValue;

                    variables.Add(v);
                    if (!v.IsGlobal)
                    {
                        cueVariables.Add(v);
                    }
                    else
                    {
                        globalVariables.Add(v);
                        _variableLookup.Add(v.Name, globalVariables.Count - 1);
                    }
                }
                _cueVariables = cueVariables.ToArray();
                _variables    = globalVariables.ToArray();

                var reverbCurves = new List <RpcCurve>();
                RpcCurves = new RpcCurve[numRpc];
                if (numRpc > 0)
                {
                    reader.BaseStream.Seek(rpcOffset, SeekOrigin.Begin);
                    for (var i = 0; i < numRpc; i++)
                    {
                        var curve = new RpcCurve
                        {
                            FileOffset = (uint)reader.BaseStream.Position
                        };

                        var variable = variables[reader.ReadUInt16()];
                        if (variable.IsGlobal)
                        {
                            curve.IsGlobal = true;
                            curve.Variable = globalVariables.FindIndex(e => e.Name == variable.Name);
                        }
                        else
                        {
                            curve.IsGlobal = false;
                            curve.Variable = cueVariables.FindIndex(e => e.Name == variable.Name);
                        }

                        var pointCount = (int)reader.ReadByte();
                        curve.Parameter = (RpcParameter)reader.ReadUInt16();

                        curve.Points = new RpcPoint[pointCount];
                        for (var j = 0; j < pointCount; j++)
                        {
                            curve.Points[j].Position = reader.ReadSingle();
                            curve.Points[j].Value    = reader.ReadSingle();
                            curve.Points[j].Type     = (RpcPointType)reader.ReadByte();
                        }

                        // If the parameter is greater than the max then this is a DSP
                        // parameter which is for reverb.
                        var dspParameter = curve.Parameter - RpcParameter.NumParameters;
                        if (dspParameter >= 0 && variable.IsGlobal)
                        {
                            reverbCurves.Add(curve);
                        }

                        RpcCurves[i] = curve;
                    }
                }
                _reverbCurves = reverbCurves.ToArray();

                if (numDspPresets > 0)
                {
                    // Note:  It seemed like MS designed this to support multiple
                    // DSP effects, but in practice XACT only has one... Microsoft Reverb.
                    //
                    // So because of this we know exactly how many presets and
                    // parameters we should have.
                    if (numDspPresets != 1)
                    {
                        throw new Exception("Unexpected number of DSP presets!");
                    }
                    if (numDspParams != 22)
                    {
                        throw new Exception("Unexpected number of DSP parameters!");
                    }

                    reader.BaseStream.Seek(dspParamsOffset, SeekOrigin.Begin);
                    _reverbSettings = new ReverbSettings(reader);
                }
            }

            _stopwatch = new Stopwatch();
            _stopwatch.Start();
        }