public SoundBankAction(EndianReader reader, uint id)
        {
            ID = id;

            Type = (SoundBankActionType)reader.ReadSByte();
            Scope = (SoundBankActionScope)reader.ReadSByte();
            ObjectID = reader.ReadUInt32();

            // TODO: read parameters and state/switch group IDs
        }
        public StateGroup(EndianReader reader)
        {
            ID = reader.ReadUInt32();
            ChangeMoment = (StateGroupChangeMoment)reader.ReadSByte();

            // Read custom states
            short numCustomStates = reader.ReadInt16();
            CustomStates = new CustomState[numCustomStates];
            for (short i = 0; i < numCustomStates; i++)
                CustomStates[i] = new CustomState(reader);
        }
        public SoundInfo(EndianReader reader)
        {
            OverrideParentEffectSettings = (reader.ReadByte() != 0);

            ReadEffects(reader);

            BusID = reader.ReadUInt32();
            ParentID = reader.ReadUInt32();

            OverrideParentPrioritySettings = (reader.ReadByte() != 0);
            OffsetPriorityAtMaxDistance = (reader.ReadByte() != 0);

            byte numParameters = reader.ReadByte();
            // TODO: actually store the parameter values instead of skipping over them
            reader.Skip(numParameters);
            reader.Skip(numParameters * 4);

            sbyte unknownCount = reader.ReadSByte();
            if (unknownCount > 0)
            {
                reader.Skip(unknownCount);
                reader.Skip(unknownCount * 8);
            }

            ReadPositioningInfo(reader);

            // Read auxiliary send settings
            OverrideParentGameDefinedAuxiliarySendSettings = (reader.ReadByte() != 0);
            UseGameDefinedAuxiliarySends = (reader.ReadByte() != 0);
            OverrideParentUserDefinedAuxiliarySendSettings = (reader.ReadByte() != 0);
            ReadUserDefinedAuxiliarySends(reader);

            bool unknown = (reader.ReadByte() != 0);
            /*if (unknown)
                reader.Skip(4);*/

            // Read voice settings
            LimitMethod = (SoundLimitMethod)reader.ReadSByte();
            VirtualVoiceBehavior = (SoundVirtualVoiceBehavior)reader.ReadSByte();
            OverrideParentPlaybackLimitSettings = (reader.ReadByte() != 0);
            OverrideParentVirtualVoiceSettings = (reader.ReadByte() != 0);

            ReadStateGroups(reader);
            ReadRTPCs(reader);

            reader.Skip(4); // I think this is part of the sound info data...
        }
        private void ReadObjects(EndianReader reader)
        {
            int numObjects = reader.ReadInt32();
            long offset = reader.Position;

            for (int i = 0; i < numObjects; i++)
            {
                // Read the object's header
                ObjectType type = (ObjectType)reader.ReadSByte();
                int size = reader.ReadInt32();
                offset += 5;

                // Read the object's ID
                uint id = reader.ReadUInt32();

                // Read the rest of the object based upon its type
                IWwiseObject obj = null;
                switch (type)
                {
                    case ObjectType.Voice:
                        obj = new SoundBankVoice(reader, id);
                        break;

                    case ObjectType.Action:
                        obj = new SoundBankAction(reader, id);
                        break;

                    case ObjectType.Event:
                        SoundBankEvent ev = new SoundBankEvent(reader, id);
                        _eventsById[ev.ID] = ev;
                        obj = ev;
                        break;

                    case ObjectType.SequenceContainer:
                        obj = new SoundBankSequenceContainer(reader, id);
                        break;

                    case ObjectType.SwitchContainer:
                        obj = new SoundBankSwitchContainer(reader, id);
                        break;

                    case ObjectType.ActorMixer:
                        obj = new SoundBankActorMixer(reader, id);
                        break;

                    case ObjectType.MusicPlaylistContainer:
                        obj = new SoundBankMusicPlaylist(reader, id);
                        break;

                    case ObjectType.MusicSegment:
                        obj = new SoundBankMusicSegment(reader, id);
                        break;

                    case ObjectType.MusicTrack:
                        obj = new SoundBankMusicTrack(reader, id);
                        break;

                    case ObjectType.MusicSwitchContainer:
                        obj = new SoundBankMusicSwitchContainer(reader, id);
                        break;
                }

                // Register the object if something was read
                if (obj != null)
                    _objects.Add(obj);

                // Skip to the next object
                offset += size;
                reader.SeekTo(offset);
            }
        }