Example #1
0
        /*
         *  JAIV1 BANK structure
         *  0x00 int32 0x42414E4B 'BANK';
         *  0x04 int32[0xF0] InstrumentPointers
         *  ---- NOTE: If the instrument pointer is 0, then the instrument for that index is NULL!
         */
        public JInstrument[] loadBank(BeBinaryReader binStream, int Base)
        {
            if (binStream.ReadUInt32() != BANK) // Check if first 4 bytes are BANK
            {
                throw new InvalidDataException("Data is not a BANK");
            }
            var InstrumentPoiners = new int[0xF0]; // Table of pointers for the instruments;
            var Instruments       = new JInstrument[0xF0];

            InstrumentPoiners = Helpers.readInt32Array(binStream, 0xF0); //  Read instrument pointers.
            for (int i = 0; i < 0xF0; i++)
            {
                binStream.BaseStream.Position = InstrumentPoiners[i] + Base; // Seek to pointer position
                var type = binStream.ReadInt32();                            // Read type
                binStream.BaseStream.Seek(-4, SeekOrigin.Current);           // Seek back 4 bytes to undo header read.
                currentInstID = (short)i;
                switch (type)
                {
                case INST:
                    Instruments[i] = loadInstrument(binStream, Base);     // Load instrument
                    break;

                case PER2:
                    Instruments[i] = loadPercussionInstrument(binStream, Base);     // Load percussion
                    break;

                default:
                    // no action, we don't know what it is and it won't misalign.
                    break;
                }
            }
            return(Instruments);
        }
Example #2
0
        public JInstrument loadPercussionInstrument(BeBinaryReader binStream, int Base)
        {
            if (binStream.ReadInt32() != Perc)
            {
                throw new InvalidDataException("Perc section started with unexpected data");
            }
            var newPERC = new JInstrument();

            newPERC.IsPercussion = true;
            newPERC.Pitch        = 1f;
            newPERC.Volume       = 1f;

            var count = binStream.ReadInt32();
            var ptrs  = Helpers.readInt32Array(binStream, count);
            var iKeys = new JInstrumentKey[count];

            for (int i = 0; i < count; i++)
            {
                var PmapOffset = ptrs[i];
                if (PmapOffset > 0)
                {
                    var newKey = new JInstrumentKey();
                    newKey.Velocities = new JInstrumentKeyVelocity[0x81];
                    var pmapDataOffs = PmapOffset + Base;  // OH LOOK ANOTHER RELATIVE TO BANK BASE.
                    binStream.BaseStream.Position = pmapDataOffs;
                    if (binStream.ReadInt32() != Pmap)
                    {
                        Console.WriteLine("ERROR: Invalid PMAP data {0:X} -- Potential misalignment!", binStream.BaseStream.Position);
                        continue;
                    }

                    newKey.Volume = binStream.ReadInt32();
                    newKey.Pitch  = binStream.ReadInt32();
                    //binStream.ReadInt32(); // byte panning
                    binStream.BaseStream.Seek(8, SeekOrigin.Current); // runtime.
                    var velRegCount = binStream.ReadInt32();
                    var velLow      = 0;
                    for (int b = 0; b < velRegCount; b++)
                    {
                        var breg = readKeyVelRegion(binStream, Base);
                        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
                    }
                    iKeys[i] = newKey;
                }
            }
            newPERC.Keys            = iKeys;
            newPERC.oscillatorCount = 0;
            return(newPERC);
        }
Example #3
0
        /*
         * 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);
        }
Example #4
0
        /* 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);
        }
Example #5
0
        /*
         *  JAIV2 LIST STRUCTURE
         *  0x00 - int32 0x4C495354 'LIST';
         *  0x04 - int32 length
         *  0x08 - int32 count
         *  0x0c - int32[count] instrumentPointers (RELATIVE TO IBANK 0x00)
         */

        public JInstrument[] loadInstrumentList(BeBinaryReader binStream, int Base)
        {
            JInstrument[] instruments = new JInstrument[0xF0];                                                                     // JSystem doesn't have more than 0xF0 instruments in each bank
            if (binStream.ReadInt32() != LIST)                                                                                     // Verify we're loading the right section
            {
                throw new InvalidDataException("LIST data section started with unexpected data " + binStream.BaseStream.Position); // Throw if it's not the right data
            }
            binStream.ReadInt32();                                                                                                 // Section Length // Section lenght doesn't matter, but we have to read it to keep alignment.
            var count = binStream.ReadInt32();                                                                                     // Count of entries in the section (Including nulls.)
            // why are these F***S relative whenever literally nothing else in the file is ? //
            var pointers = Helpers.readInt32Array(binStream, count);                                                               // This will be an in32[] of pointers

            for (int i = 0; i < count; i++)
            {
                if (pointers[i] < 1)                                  // Instrument is empty.
                {
                    continue;                                         // Instrument is empty. Skip this iteration
                }
                binStream.BaseStream.Position = Base + pointers[i];   // F**K THIS. Err I mean. Seek to the position of the instrument index + the base of the bank.
                var IID = binStream.ReadInt32();                      // read the identity at the base of each section
                binStream.BaseStream.Seek(-4, SeekOrigin.Current);    // Seek back identity (We read 4 bytes for the ID)

                switch (IID)                                          // Switch ID
                {
                case Inst:                                            // It's a regular instrument
                    instruments[i] = loadInstrument(binStream, Base); // Ask it to load (We're already just behind the Inst)
                    break;

                case Perc:     // Percussion Instrument
                    instruments[i] = loadPercussionInstrument(binStream, Base);
                    break;

                default:

                    Console.WriteLine("unknown inst index {0:X}", binStream.BaseStream.Position);
                    break;
                }
            }

            return(instruments);
        }
Example #6
0
        /*
         *  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);
        }