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) { // 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. Events[i] = new PlayWaveEvent( eventTimestamp, new ushort[] { track }, new byte[] { waveBank }, 0, 0, clipVolume, clipVolume, filterType, loopCount, 0, false, 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 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, variationType, variationOnLoop, 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(); // Unknown value reader.ReadUInt16(); // Finally. Events[i] = new PlayWaveEvent( eventTimestamp, new ushort[] { track }, new byte[] { waveBank }, minPitch, maxPitch, minVolume, maxVolume, filterType, loopCount, 0, false, 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(); // Unknown value 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 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, variationType, variationOnLoop, weights ); } else if (eventType == 7) { // 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) { // 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 // 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 NotImplementedException( "EVENT TYPE " + eventType.ToString() + " NOT IMPLEMENTED!" ); } } }
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) { // 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. Events[i] = new PlayWaveEvent( eventTimestamp, new ushort[] { track }, new byte[] { waveBank }, 0, 0, clipVolume, clipVolume, filterType, loopCount, 0, false, 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 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, variationType, variationOnLoop, 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(); // Unknown value reader.ReadUInt16(); // Finally. Events[i] = new PlayWaveEvent( eventTimestamp, new ushort[] { track }, new byte[] { waveBank }, minPitch, maxPitch, minVolume, maxVolume, filterType, loopCount, 0, false, 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(); // Unknown value 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 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, variationType, variationOnLoop, weights ); } else if (eventType == 7) { // 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) { // 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 // 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 NotImplementedException( "EVENT TYPE " + eventType.ToString() + " NOT IMPLEMENTED!" ); } } }