/* * JAIV1 Oscillator Format * 0x00 - byte mode * 0x01 - byte[3] unknown * 0x04 - float rate * 0x08 - int32 attackVectorOffset * 0x0C - int32 releaseVectorOffset * 0x10 - float width * 0x14 - float vertex */ public JOscillator loadOscillator(BeBinaryReader binStream, int Base) { var Osc = new JOscillator(); // Create new oscillator var target = binStream.ReadByte(); // load target -- what is it affecting? binStream.BaseStream.Seek(3, SeekOrigin.Current); // read 3 bytes? Osc.rate = binStream.ReadSingle(); // Read the rate at which the oscillator progresses -- this will be relative to the number of ticks per beat. var attackSustainTableOffset = binStream.ReadInt32(); // Offset of AD table var releaseDecayTableOffset = binStream.ReadInt32(); // Offset of SR table Osc.Width = binStream.ReadSingle(); // We should load these next, this is the width, ergo the value of the oscillator at 32768. Osc.Vertex = binStream.ReadSingle(); // This is the vertex, the oscillator will always cross this point. // To determine the value of an oscillator, it's Vertex + Width*(value/32768) -- each vector should progress the value, depending on the mode. if (attackSustainTableOffset > 0) // first is AS table { binStream.BaseStream.Position = attackSustainTableOffset + Base; // Seek to the vector table Osc.envelopes[0] = readEnvelope(binStream, Base); // Load the table } if (releaseDecayTableOffset > 0) // Next is RD table { binStream.BaseStream.Position = releaseDecayTableOffset + Base; // Seek to the vector and load it Osc.envelopes[1] = readEnvelope(binStream, Base); // loadddd } Osc.target = (JOscillatorTarget)target; return(Osc); }
/* * JAIV2 Oscillator Structure * 0x00 - int32 0x4F736369 'Osci' * 0x04 - byte mode * 0x05 - byte[3] unknown * 0x08 - float rate * 0x0c - int32 attackVectorOffset (RELATIVE TO ENVT + 0x08) * 0x10 - int32 releaseVectorOffset (RELATIVE TO ENVT + 0x08) * 0x14 - float width * 0x18 - float vertex */ /* NOTE THAT THESE OSCILLATORS HAVE THE SAME FORMAT AS JAIV1, HOWEVER THE VECTORS ARE IN THE ENVT */ public JOscillator loadOscillator(BeBinaryReader binStream, int EnvTableBase) { var Osc = new JOscillator(); // Create new oscillator if (binStream.ReadInt32() != Osci) // Read first 4 bytes { throw new InvalidDataException("Oscillator format is invalid. " + binStream.BaseStream.Position); } var target = binStream.ReadByte(); // load target -- what is it affecting? binStream.BaseStream.Seek(3, SeekOrigin.Current); // read 3 bytes? Osc.rate = binStream.ReadSingle(); // Read the rate at which the oscillator progresses -- this will be relative to the number of ticks per beat. var attackSustainTableOffset = binStream.ReadInt32(); // Offset of AD table var releaseDecayTableOffset = binStream.ReadInt32(); // Offset of SR table Osc.Width = binStream.ReadSingle(); // We should load these next, this is the width, ergo the value of the oscillator at 32768. Osc.Vertex = binStream.ReadSingle(); // This is the vertex, the oscillator will always cross this point. // To determine the value of an oscillator, it's Vertex + Width*(value/32768) -- each vector should progress the value, depending on the mode. // We need to add + 8 to the offsets, because the pointers are the offset based on where the data starts, not the section if (attackSustainTableOffset > 0) // first is AS table { binStream.BaseStream.Position = attackSustainTableOffset + EnvTableBase + 8; // Seek to the vector table Osc.envelopes[0] = readEnvelope(binStream, EnvTableBase + 8); // Load the table } if (releaseDecayTableOffset > 0) // Next is RD table { binStream.BaseStream.Position = releaseDecayTableOffset + EnvTableBase + 8; // Seek to the vector and load it Osc.envelopes[1] = readEnvelope(binStream, EnvTableBase + 8); // loadddd } Osc.target = OscillatorTargetConversionLUT[target]; return(Osc); }
/* * JAIV1 Velocity Region Structure * 0x00 byte baseVelocity; * 0x04 byte[0x03] unused; * 0x07 short wsysID; * 0x09 short waveID; * 0x0D float Volume; * 0x11 float Pitch; */ public JInstrumentKeyVelocity readKeyVelRegion(BeBinaryReader binStream, int Base) { JInstrumentKeyVelocity newReg = new JInstrumentKeyVelocity(); newReg.baseVel = binStream.ReadByte(); binStream.BaseStream.Seek(3, SeekOrigin.Current);; // Skip 3 bytes. newReg.velocity = newReg.baseVel; newReg.wsysid = binStream.ReadInt16(); newReg.wave = binStream.ReadInt16(); newReg.Volume = binStream.ReadSingle(); newReg.Pitch = binStream.ReadSingle(); return(newReg); }
/* * JAIV1 PER2 Structure * 0x00 int32 0x50455232 'PER2' * 0x04 byte[0x84] unused; // the actual f**k? Waste of 0x84 perfectly delicious bytes. * 0x8C *PercussionKey[100] * * PER2 PercussionKey Structure * float pitch; * float volume; * byte[0x8] unused? * int32 velocityRegionCount * VelocityRegion[velocityRegionCount] velocities * */ public JInstrument loadPercussionInstrument(BeBinaryReader binStream, int Base) { var Inst = new JInstrument(); if (binStream.ReadUInt32() != PER2) // Check if first 4 bytes are PER2 { throw new InvalidDataException("Data is not an PER2"); } Inst.Pitch = 1.0f; Inst.Volume = 1.0f; Inst.IsPercussion = true; binStream.BaseStream.Seek(0x84, SeekOrigin.Current); JInstrumentKey[] keys = new JInstrumentKey[100]; int[] keyPointers = new int[100]; keyPointers = Helpers.readInt32Array(binStream, 100); // read the pointers. for (int i = 0; i < 100; i++) // Loop through all pointers. { if (keyPointers[i] == 0) { continue; } binStream.BaseStream.Position = keyPointers[i] + Base; // Set position to key pointer pos (relative to base) var newKey = new JInstrumentKey(); newKey.Pitch = binStream.ReadSingle(); // read the pitch newKey.Volume = binStream.ReadSingle(); // read the volume binStream.BaseStream.Seek(8, SeekOrigin.Current); // runtime values, skip var velRegCount = binStream.ReadInt32(); // read count of regions we have newKey.Velocities = new JInstrumentKeyVelocity[0xff]; // 0xFF just in case. int[] velRegPointers = Helpers.readInt32Array(binStream, velRegCount); var velLow = 0; // Again, these are regions -- see LoadInstrument for this exact code ( a few lines above ) for (int b = 0; b < velRegCount; b++) { binStream.BaseStream.Position = velRegPointers[b] + Base; var breg = readKeyVelRegion(binStream, Base); // Read the vel region. for (int c = 0; c < breg.baseVel - velLow; c++) { // They're velocity regions, so we're going to have a toothy / gappy piano. So we need to span the missing gaps with the previous region config. // This means that if the last key was 4, and the next key was 8 -- whatever parameters 4 had will span keys 4 5 6 and 7. newKey.Velocities[c] = breg; // store the region newKey.Velocities[127] = breg; } velLow = breg.baseVel; // store the velocity for spanning } keys[i] = newKey; } Inst.Keys = keys; return(Inst); }
/* JAIV2 Instrument Structure * 0x00 int32 = 0x496E7374 'Inst' * 0x04 int32 oscillatorCount * 0x08 int32[oscillatorCount] oscillatorIndicies * ???? int32 0 * ???? int32 keyRegionCount * ???? keyRegion[keyRegionCount] * ???? float gain * ???? float freqmultiplier * */ public JInstrument loadInstrument(BeBinaryReader binStream, int Base) { var newInst = new JInstrument(); newInst.IsPercussion = false; // Instrument isn't percussion // This is wrong, they come at the end of the instrument //newInst.Pitch = 1; // So these kinds of instruments don't initialize with a pitch value, which is strange. //newInst.Volume = 1; // I guess they figured that it was redundant since they're already doing it in 3 other places. if (binStream.ReadInt32() != Inst) { throw new InvalidDataException("Inst section started with unexpected data"); } var osciCount = binStream.ReadInt32(); // Read the count of the oscillators. newInst.oscillatorCount = (byte)osciCount; // Hope no instrument never ever ever has > 255 oscillators lol. newInst.oscillators = new JOscillator[osciCount]; // Initialize the instrument with the proper amount of oscillaotrs for (int i = 0; i < osciCount; i++) // Loop through and read each oscillator. { var osciIndex = binStream.ReadInt32(); // Each oscillator is stored as a 32 bit index. newInst.oscillators[i] = bankOscillators[osciIndex]; // We loaded the oscillators already, I hope. So this will grab them by their index. } var notpadding = binStream.ReadInt32(); // NOT PADDING. F**K. Probably effects. Helpers.readInt32Array(binStream, notpadding); var keyRegCount = binStream.ReadInt32(); var keyLow = 0; // For region spanning. JInstrumentKey[] keys = new JInstrumentKey[0x81]; // Always go for one more. for (int i = 0; i < keyRegCount; i++) // Loop through all pointers. { var bkey = readKeyRegion(binStream, Base); // Read the key region //Console.WriteLine("KREG BASE KEY {0}", bkey.baseKey); for (int b = 0; b < bkey.baseKey - keyLow; b++) { // They're key regions, so we're going to have a toothy / gappy piano. So we need to span the missing gaps with the previous region config. // This means that if the last key was 4, and the next key was 8 -- whatever parameters 4 had will span keys 4 5 6 and 7. keys[b + keyLow] = bkey; // span the keys keys[127] = bkey; } keyLow = bkey.baseKey; // Store our last key } newInst.Keys = keys; newInst.Volume = binStream.ReadSingle(); // ^^ newInst.Pitch = binStream.ReadSingle(); // Pitch and volume come last??? // WE HAVE READ EVERY BYTE IN THE INST, WOOO return(newInst); }
/// <summary> /// Gets the ticks from the binary data. /// </summary> /// <param name="data">The data.</param> /// <returns></returns> public List <Tick> LoadTicks(byte[] data) { var result = new List <Tick>(); byte[] decompressed = SevenZip.Compression.LZMA.SevenZipHelper.Decompress(data); using (var reader = new BeBinaryReader(new MemoryStream(decompressed))) { while (reader.BaseStream.Position != reader.BaseStream.Length) { var tick = new Tick(); tick.Milliseconds = reader.ReadInt32(); tick.Ask = reader.ReadInt32(); tick.Bid = reader.ReadInt32(); tick.AskVolume = reader.ReadSingle(); tick.BidVolume = reader.ReadSingle(); result.Add(tick); } } return(result); }
private JWave loadWave(BeBinaryReader binStream, int Base) { var newWave = new JWave(); binStream.ReadByte(); // First byte unknown? newWave.format = binStream.ReadByte(); // Read wave format, usually 5 newWave.key = binStream.ReadByte(); // Read the base tuning key //Console.WriteLine(newWave.key); binStream.ReadByte(); // fourth byte unknown? newWave.sampleRate = binStream.ReadSingle(); // Read the samplerate newWave.wsys_start = binStream.ReadInt32(); // Read the offset in the AW newWave.wsys_size = binStream.ReadInt32(); // Read the length in the AW newWave.loop = binStream.ReadUInt32() == UInt32.MaxValue ? true : false; // Check if it loops? newWave.loop_start = binStream.ReadInt32(); // Even if looping is disabled, it should still read loops newWave.loop_end = binStream.ReadInt32(); // Sample index of loop end newWave.sampleCount = binStream.ReadInt32(); // Sample count return(newWave); }
/* * JAIV1 INST Structure * 0x00 int32 0x494E5354 'INST' * 0x04 int32 0 - unused? * 0x08 float frequencyMultiplier * 0x0C float gainMultiplier * 0x10 int32 oscillator table offset * 0x14 int32 oscillator table count * 0x18 int32 effect table offset * 0x1C int32 effect table size * 0x20 int32 sensor object table * 0x24 int32 sensor object table count * 0x28 int32 key_region_count * 0x2C *KeyRegion[key_region_count] * */ public JInstrument loadInstrument(BeBinaryReader binStream, int Base) { var Inst = new JInstrument(); if (binStream.ReadUInt32() != INST) // Check if first 4 bytes are INST { throw new InvalidDataException("Data is not an INST"); } binStream.ReadUInt32(); // oh god oh god oh god its null Inst.Pitch = binStream.ReadSingle(); Inst.Volume = binStream.ReadSingle(); var osc1Offset = binStream.ReadUInt32(); var osc2Offset = binStream.ReadUInt32(); binStream.ReadUInt32(); // *NOT IMPLEMENTED* // binStream.ReadUInt32(); // *NOT IMPLEMENTED* // binStream.ReadUInt32(); // *NOT IMPLEMENTED* // binStream.ReadUInt32(); // *NOT IMPLEMENTED* // // * trashy furry screaming * // int keyregCount = binStream.ReadInt32(); // Read number of key regions JInstrumentKey[] keys = new JInstrumentKey[0x81]; // Always go for one more. int[] keyRegionPointers = new int[keyregCount]; keyRegionPointers = Helpers.readInt32Array(binStream, keyregCount); var keyLow = 0; // For region spanning. for (int i = 0; i < keyregCount; i++) // Loop through all pointers. { binStream.BaseStream.Position = keyRegionPointers[i] + Base; // Set position to key pointer pos (relative to base) var bkey = readKeyRegion(binStream, Base); // Read the key region for (int b = 0; b < bkey.baseKey - keyLow; b++) { // They're key regions, so we're going to have a toothy / gappy piano. So we need to span the missing gaps with the previous region config. // This means that if the last key was 4, and the next key was 8 -- whatever parameters 4 had will span keys 4 5 6 and 7. keys[b + keyLow] = bkey; // span the keys keys[127] = bkey; } keyLow = bkey.baseKey; // Store our last key } Inst.Keys = keys; byte oscCount = 0; if (osc1Offset > 0) { oscCount++; } if (osc2Offset > 0) { oscCount++; } Inst.oscillatorCount = oscCount; // Redundant? Inst.oscillators = new JOscillator[oscCount]; // new oscillator array if (osc1Offset != 0) // if the oscillator isnt null { binStream.BaseStream.Position = osc1Offset + Base; // seek to it's position Inst.oscillators[0] = loadOscillator(binStream, Base); // then load it. } if (osc2Offset != 0) // if the second oscillator isn't null { binStream.BaseStream.Position = osc2Offset + Base; // seek to its position Inst.oscillators[1] = loadOscillator(binStream, Base); // and load it. } return(Inst); }
private void loadIBNKJaiV2(BeBinaryReader instReader) { long anchor = 0; var BaseAddress = instReader.BaseStream.Position; var current_header = instReader.ReadUInt32(); if (current_header != 0x49424e4b) // Check to see if it equals IBNK { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("0x{0:X}", BaseAddress); throw new InvalidDataException("Scanned header is not an IBNK."); } var IBNKSize = instReader.ReadUInt32(); id = instReader.ReadInt32(); var flags = instReader.ReadUInt32(); // usually 1, determines if the bank is melodic or used for sound effects. Usually the bank is melodic. instReader.BaseStream.Seek(0x10, SeekOrigin.Current); // Skip 16 bytes, always 0x00, please document if wrong. var i = 0; while (true) { anchor = instReader.BaseStream.Position; // Store current section base. i++; // Console.WriteLine("Iteration {0} 0x{1:X}", i,anchor); current_header = instReader.ReadUInt32(); // Console.WriteLine("GOT HD {0:X}", current_header); if (current_header == 0x00) { break; // End of section. } else if (current_header < 0xFFFF) // Read below for explanation { // I've noticed VERY RARELY, that the section pointer is wrong by two bytes. This sucks. So we check if it's less than two full bytes. // If it is, we seek back 2 bytes then read again, and our alignment is fixed :). // of course, this comes after our check to see if it's 0, which indicates end of section instReader.BaseStream.Seek(-2, SeekOrigin.Current); Console.WriteLine("[!] Misalignment detected in IBNK, new position 0x{0:X}", instReader.BaseStream.Position); anchor = instReader.BaseStream.Position; // 3/14/2019, i forgot this. It's S M R T to update your read base. current_header = instReader.ReadUInt32(); Console.WriteLine("New header {0:X}", current_header); } var next_section = ReadJARCSizePointer(instReader); // if that works, go ahead and grab the 'pointer' to the next section. if (current_header < 0xFFFF) { Console.WriteLine("Corrupt IBNK 0x{0:X}", BaseAddress); break; } switch (current_header) { case 0x4F534354: // OSCT case 0x52414E44: // RAND case 0x454E5654: // EVNT case 0x53454E53: // SENS instReader.BaseStream.Position = anchor + next_section; // Skip section. break; case INST: { var NewINST = new Instrument(); var InstCount = instReader.ReadInt32(); NewINST.Keys = new InstrumentKey[0xF0]; for (int instid = 0; instid < InstCount; instid++) { current_header = instReader.ReadUInt32(); var iebase = instReader.BaseStream.Position; if (current_header != Inst) { break; // F**K. } NewINST.oscillator = instReader.ReadInt32(); NewINST.id = instReader.ReadInt32(); instReader.ReadInt32(); // cant figure out what these are. var keyCounts = instReader.ReadInt32(); // How many key regions are in here. int KeyHigh = 0; int KeyLow = 0; for (int k = 0; k < keyCounts; k++) { var NewKey = new InstrumentKey(); NewKey.keys = new InstrumentKeyVelocity[0x81]; byte key = instReader.ReadByte(); // Read the key identifierr KeyHigh = key; // Set the highest key to what we just read. instReader.BaseStream.Seek(3, SeekOrigin.Current); // 3 bytes, unused. var VelocityRegionCount = instReader.ReadInt32(); // read the number of entries in the velocity region array\ if (VelocityRegionCount > 0x7F) { Console.WriteLine("Alignment is f****d, IBNK load aborted."); Console.WriteLine("E: VelocityRegionCount is too thicc. {0} > 128", VelocityRegionCount); Console.WriteLine("IBASE: 0x{0:X} + 0x{1:X} ({2:X})", anchor, iebase - anchor, (instReader.BaseStream.Position - anchor) - (iebase - anchor)); return; } for (int b = 0; b < VelocityRegionCount; b++) { var NewVelR = new InstrumentKeyVelocity(); int VelLow = 0; int VelHigh = 0; { var velocity = instReader.ReadByte(); // The velocity of this key. VelHigh = velocity; instReader.BaseStream.Seek(3, SeekOrigin.Current); // Unused. NewVelR.velocity = velocity; NewVelR.wave = instReader.ReadUInt16(); // This will be the ID of the wave inside of that wavesystem NewVelR.wsysid = instReader.ReadUInt16(); // This will be the ID of the WAVESYSTEM that its in NewVelR.Volume = instReader.ReadSingle(); // Finetune, volume, float NewVelR.Pitch = instReader.ReadSingle(); // finetune pitch, float. for (int idx = 0; idx < (VelHigh - VelLow); idx++) // See below for what this is doing { NewKey.keys[(VelLow + idx)] = NewVelR; NewKey.keys[127] = NewVelR; } VelLow = VelHigh; } } for (int idx = 0; idx < (KeyHigh - KeyLow); idx++) // The keys are gappy. { NewINST.Keys[(KeyLow + idx)] = NewKey; // So we want to interpolate the previous keys across the empty ones, so that way it's a region NewINST.Keys[127] = NewKey; } KeyLow = KeyHigh; // Set our new lowest key to the previous highest } } instReader.BaseStream.Position = anchor + next_section; // SAFETY. break; } case PERC: instReader.BaseStream.Position = anchor + next_section; break; case 0x4C495354: // LIST instReader.BaseStream.Position = anchor + next_section; // Skip section // Explanation: This is just a set of pointers relative to BaseAddress for the instruments, nothing special because we're // already parsing them above. break; default: instReader.BaseStream.Position = anchor + next_section; // Skip section. break; } } }
private void loadIBNKJaiV1(BeBinaryReader instReader) { long anchor = 0; var BaseAddress = instReader.BaseStream.Position; var current_header = 0u; current_header = instReader.ReadUInt32(); // read the first 4 byteas if (current_header != 0x49424e4b) // Check to see if it equals IBNK { throw new InvalidDataException("Scanned header is not an IBNK."); } var size = instReader.ReadUInt32(); id = instReader.ReadInt32(); // Global virtual ID instReader.BaseStream.Seek(0x14, SeekOrigin.Current); // 0x14 bytes always blank current_header = instReader.ReadUInt32(); // We should be reading "BANK" for (int inst_id = 0; inst_id < 0xF0; inst_id++) { var inst_offset = instReader.ReadInt32(); // Read the relative pointer to the instrument anchor = instReader.BaseStream.Position; // store the position to jump back into. if (inst_offset > 0) // If we have a 0 offset, then the instrument is unassigned. { instReader.BaseStream.Position = BaseAddress + inst_offset; // Seek to the offset of the instrument. current_header = instReader.ReadUInt32(); // Read the 4 byte identity of the instrument. var NewINST = new Instrument(); NewINST.Keys = new InstrumentKey[0xF0]; switch (current_header) { case INST: { instReader.ReadUInt32(); // The first 4 bytes following an instrument is always 0, for some reason. Maybe reserved. NewINST.Pitch = instReader.ReadSingle(); // 4 byte float pitch NewINST.Volume = instReader.ReadSingle(); // 4 byte float volume /* Lots of skipping, i havent added these yet, but i'll comment what they are. */ var poscioffs = instReader.ReadUInt32(); // offset to first oscillator table var poscicnt = instReader.ReadUInt32(); // Offset to second oscillator count // Console.WriteLine("Oscillator at 0x{0:X}, length {1}", poscioffs, poscicnt); //Console.ReadLine(); instReader.ReadUInt32(); // Offset to first effect object instReader.ReadUInt32(); // offset to second effect object instReader.ReadUInt32(); // offset of first sensor object instReader.ReadUInt32(); // offset of second sensor object /*////////////////////////////////////////////////////////////////////////////*/ var keyCounts = instReader.ReadInt32(); // How many key regions are in here. int KeyHigh = 0; int KeyLow = 0; for (int k = 0; k < keyCounts; k++) { var NewKey = new InstrumentKey(); NewKey.keys = new InstrumentKeyVelocity[0x81]; var keyreg_offset = instReader.ReadInt32(); // This will be where the data for our key region is. var keyptr_return = instReader.BaseStream.Position; // This is our position after reading the pointer, we'll need to return to it instReader.BaseStream.Position = BaseAddress + keyreg_offset; // Seek to the key region byte key = instReader.ReadByte(); // Read the key identifierr KeyHigh = key; // Set the highest key to what we just read. instReader.BaseStream.Seek(3, SeekOrigin.Current); // 3 bytes, unused. var VelocityRegionCount = instReader.ReadInt32(); // read the number of entries in the velocity region array for (int b = 0; b < VelocityRegionCount; b++) { var NewVelR = new InstrumentKeyVelocity(); var velreg_offs = instReader.ReadInt32(); // read the offset of the velocity region var velreg_retn = instReader.BaseStream.Position; // another one of these. Return pointer instReader.BaseStream.Position = velreg_offs + BaseAddress; int VelLow = 0; int VelHigh = 0; { var velocity = instReader.ReadByte(); // The velocity of this key. VelHigh = velocity; instReader.BaseStream.Seek(3, SeekOrigin.Current); // Unused. NewVelR.velocity = velocity; NewVelR.wsysid = instReader.ReadUInt16(); // This will be the ID of the WAVESYSTEM that its in NewVelR.wave = instReader.ReadUInt16(); // This will be the ID of the wave inside of that wavesystem NewVelR.Volume = instReader.ReadSingle(); // Finetune, volume, float NewVelR.Pitch = instReader.ReadSingle(); // finetune pitch, float. for (int idx = 0; idx < ((1 + VelHigh) - VelLow); idx++) // See below for what this is doing { NewKey.keys[(VelLow + idx)] = NewVelR; NewKey.keys[127] = NewVelR; } VelLow = VelHigh; } instReader.BaseStream.Position = velreg_retn; // return to our pointer position [THIS IS BELOW] } for (int idx = 0; idx < (KeyHigh - KeyLow); idx++) // The keys are gappy. { NewINST.Keys[(KeyLow + idx)] = NewKey; // So we want to interpolate the previous keys across the empty ones, so that way it's a region NewINST.Keys[127] = NewKey; } KeyLow = KeyHigh; // Set our new lowest key to the previous highest instReader.BaseStream.Position = keyptr_return; // return to our last pointer position } break; } case PER2: { NewINST.IsPercussion = true; instReader.BaseStream.Seek(0x84, SeekOrigin.Current); // 0x88 - 4 (PERC) for (int per = 0; per < 100; per++) { var NewKey = new InstrumentKey(); NewKey.keys = new InstrumentKeyVelocity[0x81]; var keyreg_offset = instReader.ReadInt32(); // This will be where the data for our key region is. var keyptr_return = instReader.BaseStream.Position; // This is our position after reading the pointer, we'll need to return to it if (keyreg_offset == 0) { continue; // Skip, its empty. } instReader.BaseStream.Position = BaseAddress + keyreg_offset; // seek to position. NewINST.Pitch = instReader.ReadSingle(); NewINST.Volume = instReader.ReadSingle(); instReader.BaseStream.Seek(8, SeekOrigin.Current); var VelocityRegionCount = instReader.ReadInt32(); // read the number of entries in the velocity region array for (int b = 0; b < VelocityRegionCount; b++) { var NewVelR = new InstrumentKeyVelocity(); var velreg_offs = instReader.ReadInt32(); // read the offset of the velocity region var velreg_retn = instReader.BaseStream.Position; // another one of these. Return pointer instReader.BaseStream.Position = velreg_offs + BaseAddress; int VelLow = 0; int VelHigh = 0; { var velocity = instReader.ReadByte(); // The velocity of this key. VelHigh = velocity; instReader.BaseStream.Seek(3, SeekOrigin.Current); // Unused. NewVelR.velocity = velocity; NewVelR.wsysid = instReader.ReadUInt16(); // This will be the ID of the WAVESYSTEM that its in NewVelR.wave = instReader.ReadUInt16(); // This will be the ID of the wave inside of that wavesystem NewVelR.Volume = instReader.ReadSingle(); // Finetune, volume, float NewVelR.Pitch = instReader.ReadSingle(); // finetune pitch, float. for (int idx = 0; idx < (VelHigh - (VelLow)); idx++) // See below for what this is doing { NewKey.keys[(VelLow + (idx))] = NewVelR; NewKey.keys[127] = NewVelR; } VelLow = VelHigh; } instReader.BaseStream.Position = velreg_retn; // return to our pointer position [THIS IS BELOW] } instReader.BaseStream.Position = keyptr_return; NewINST.Keys[per] = NewKey; // oops, add to instrument data or else it doesnt load x.x NewINST.Keys[127] = NewKey; } break; } case PERC: break; } Instruments[inst_id] = NewINST; // Store it in the instruments bank } instReader.BaseStream.Position = anchor; // return back to our original pos to read the next pointer } }
private int back = 0; // utility public void LoadWSYS(BeBinaryReader WSYSReader) { BaseAddress = WSYSReader.BaseStream.Position; waves = new WSYSWave[32768]; // TEMPORARY. Fix WSYS Loading! current_header = WSYSReader.ReadInt32(); if (current_header != WSYS) { Console.WriteLine("Error: Section base at {0} is not WSYS, is instead {1:X}", BaseAddress, current_header); return; } size = WSYSReader.ReadInt32(); id = WSYSReader.ReadInt32(); WSYSReader.ReadUInt32(); // 4 bytes, not used. .. I think // A little messy, but both of these need to be loaded before we can continue. var winfo_offset = WSYSReader.ReadInt32(); // relative offset to wave info offset pointer table. var wbct_offset = WSYSReader.ReadInt32(); // relative offset to wave info offset pointer table. int[] winfOffsets; int[] wbctOffsets; { // Load WINF offsets. WSYSReader.BaseStream.Position = BaseAddress + winfo_offset; current_header = WSYSReader.ReadInt32(); // Should be WINF winfOffsets = new int[WSYSReader.ReadInt32()]; // 4 bytes count for (int i = 0; i < winfOffsets.Length; i++) { winfOffsets[i] = WSYSReader.ReadInt32(); // Int32's following the length. } // Load WBCT data WSYSReader.BaseStream.Position = BaseAddress + wbct_offset; current_header = WSYSReader.ReadInt32(); // Should be WBCT WSYSReader.ReadUInt32(); // 4 bytes unused? wbctOffsets = new int[WSYSReader.ReadInt32()]; // 4 bytes count for (int i = 0; i < wbctOffsets.Length; i++) { wbctOffsets[i] = WSYSReader.ReadInt32(); // Int32's following the length. } } groups = new WSYSGroup[winfOffsets.Length]; for (int i = 0; i < winfOffsets.Length; i++) { /* This is loading the data for a WINF */ WSYSReader.BaseStream.Position = BaseAddress + winfOffsets[i]; var Group = new WSYSGroup(); Group.path = Helpers.readArchiveName(WSYSReader); var fobj = File.OpenRead("./Banks/" + Group.path); // Open the .AW file (AW contains only ADPCM data, nothing else.) var fobj_reader = new BeBinaryReader(fobj); // Create a reader for it. int waveInfoCounts = WSYSReader.ReadInt32(); // 4 byte count int[] info_offsets = new int[waveInfoCounts]; for (int q = 0; q < waveInfoCounts; q++) { info_offsets[q] = WSYSReader.ReadInt32(); } Group.IDMap = new int[UInt16.MaxValue]; // We have to initialize the containers for the wave information Group.Waves = new WSYSWave[waveInfoCounts]; /* Since the count should be equal, we're loading the info for the WBCT in he re as well */ WSYSReader.BaseStream.Position = BaseAddress + wbctOffsets[i]; // The first several bytes of the WBCT are uselss, a WBCT points directly to a SCNE. current_header = WSYSReader.ReadInt32(); // This should be SCNE. WSYSReader.ReadUInt64(); // The next 8 bytes are useless. var cdf_offset = WSYSReader.ReadInt32(); // However, the next 4 contain the pointer to c_DF relative to our base. WSYSReader.BaseStream.Position = BaseAddress + cdf_offset; current_header = WSYSReader.ReadInt32(); // Should be C_DF. int waveid_count = WSYSReader.ReadInt32(); // Count of our WAVE ID int[] waveid_offsets = new int[waveid_count]; // Be ready to store them for (int q = 0; q < waveid_count; q++) { waveid_offsets[q] = WSYSReader.ReadInt32(); // Read each waveid } // Finally, we're going to get our wave data. for (int wav = 0; wav < waveInfoCounts; wav++) { var o_Wave = new WSYSWave(); WSYSReader.BaseStream.Position = BaseAddress + waveid_offsets[wav]; var aw_id = WSYSReader.ReadInt16(); // Strangely enough, it has an AW_ID here. This tells which file it sits in? I guess they're normally loaded separately. o_Wave.id = WSYSReader.ReadInt16(); // This is the waveid for this wave, it's normally globally unique, but some games hot-load banks. WSYSReader.BaseStream.Position = BaseAddress + info_offsets[wav]; // Seek to the offset of the actual wave parameters. WSYSReader.ReadByte(); // I have no clue what the first byte does. o_Wave.format = WSYSReader.ReadByte(); // Tells what format it's in, usually type 5 AFC (ADPCM) o_Wave.key = WSYSReader.ReadByte(); // Tells the base key for this wave (0-127 usually) WSYSReader.ReadByte(); // I have no clue what this byte does. //var srate = WSYSReader.ReadBytes(4); o_Wave.sampleRate = WSYSReader.ReadSingle(); /* * oh. its a float. * oops * if (o_Wave.format == 5) * { * o_Wave.sampleRate = 32000; /// ???? * } * * if (o_Wave.sampleRate == 5666) // What the actual f**k. Broken value, can't figure out why. * { * o_Wave.sampleRate = 44100; // I guess set the srate to 44100? * } */ o_Wave.w_start = WSYSReader.ReadUInt32(); // 4 byte start in AW o_Wave.w_size = WSYSReader.ReadUInt32(); // 4 byte size in AW var b = WSYSReader.ReadUInt32(); o_Wave.loop = b == UInt32.MaxValue ? true : false; // Weird looping flag? o_Wave.loop_start = (int)Math.Floor(((WSYSReader.ReadInt32() / 8f)) * 16f); o_Wave.loop_end = (int)Math.Floor(((WSYSReader.ReadInt32() / 8f)) * 16f); o_Wave.sampleCount = WSYSReader.ReadInt32(); // 4 byte sample cont // Console.WriteLine("L {0:X} (0x{1:X}), LS {2:X} , LE {3:X}, SC {4:X} SZ {5:X}", o_Wave.loop, b, o_Wave.loop_start, o_Wave.loop_end,o_Wave.sampleCount,o_Wave.w_size); //Console.ReadLine(); var name = string.Format("0x{0:X}.wav", o_Wave.id); var name2 = string.Format("0x{0:X}.par", o_Wave.id); if (!Directory.Exists("./WSYS_CACHE")) { Directory.CreateDirectory("./WSYS_CACHE"); } if (!Directory.Exists("./WSYS_CACHE/AW_" + Group.path)) { Directory.CreateDirectory("./WSYS_CACHE/AW_" + Group.path); } o_Wave.pcmpath = "./WSYS_CACHE/AW_" + Group.path + "/" + name; Group.Waves[wav] = o_Wave; // We're done with just about everything except the PCM data now (ADPCM / AFC conversion) Group.IDMap[o_Wave.id] = wav; waves[o_Wave.id] = o_Wave; // TEMPORARY, FIX WSYS LOADING! fobj_reader.BaseStream.Position = o_Wave.w_start; var adpcm = fobj_reader.ReadBytes((int)o_Wave.w_size); if (!File.Exists(o_Wave.pcmpath)) { Helpers.AFCtoPCM16(adpcm, o_Wave.sampleRate, (int)o_Wave.w_size, o_Wave.format, o_Wave.pcmpath); } } } }