Example #1
0
 void SetModuleData(MdatResource resource, byte[] sampleData, bool autoDelete)
 {
     lock (_mutex)
     {
         StopSongImpl(true);
         FreeResourceDataImpl();
         _resource = resource;
         _resourceSample = sampleData;
         _deleteResource = autoDelete;
     }
 }
Example #2
0
        MdatResource LoadMdatFile(Stream musicData)
        {
            var br = new BinaryReader(musicData);
            bool hasHeader = false;
            var mdatSize = musicData.Length;
            if (mdatSize >= 0x200)
            {

                // 0x0000: 10 Bytes Header "TFMX-SONG "
                var buf = System.Text.Encoding.UTF8.GetString(br.ReadBytes(10));
                hasHeader = buf == "TFMX-SONG ";
            }

            if (!hasHeader)
            {
                Debug.WriteLine("Tfmx: File is not a Tfmx Module");
                return null;
            }

            var resource = new MdatResource();

            resource.mdatAlloc = null;
            resource.mdatOffset = 0;
            resource.mdatLen = 0;

            // 0x000A: int16 flags
            resource.headerFlags = br.ReadUInt16BigEndian();
            // 0x000C: int32 ?
            // 0x0010: 6*40 Textfield
            musicData.Seek(4 + 6 * 40, SeekOrigin.Current);

            /* 0x0100: Songstart x 32*/
            for (int i = 0; i < NumSubsongs; ++i)
                resource.subsong[i].songstart = br.ReadUInt16BigEndian();
            /* 0x0140: Songend x 32*/
            for (int i = 0; i < NumSubsongs; ++i)
                resource.subsong[i].songend = br.ReadUInt16BigEndian();
            /* 0x0180: Tempo x 32*/
            for (int i = 0; i < NumSubsongs; ++i)
                resource.subsong[i].tempo = br.ReadUInt16BigEndian();

            /* 0x01c0: unused ? */
            musicData.Seek(16, SeekOrigin.Current);

            /* 0x01d0: trackstep, pattern data p, macro data p */
            var offTrackstep = br.ReadUInt32BigEndian();
            uint offPatternP, offMacroP;

            // This is how MI`s TFMX-Player tests for unpacked Modules.
            if (offTrackstep == 0)
            { // unpacked File
                resource.trackstepOffset = 0x600 + 0x200;
                offPatternP = 0x200 + 0x200;
                offMacroP = 0x400 + 0x200;
            }
            else
            { // packed File
                resource.trackstepOffset = offTrackstep;
                offPatternP = br.ReadUInt32BigEndian();
                offMacroP = br.ReadUInt32BigEndian();
            }

            // TODO: if a File is packed it could have for Ex only 2 Patterns/Macros
            // the following loops could then read beyond EOF.
            // To correctly handle this it would be necessary to sort the pointers and
            // figure out the number of Macros/Patterns
            // We could also analyze pointers if they are correct offsets,
            // so that accesses can be unchecked later

            // Read in pattern starting offsets
            musicData.Seek(offPatternP, SeekOrigin.Begin);
            for (int i = 0; i < MaxPatternOffsets; ++i)
                resource.patternOffset[i] = br.ReadUInt32BigEndian();

            // use last PatternOffset (stored at 0x5FC in mdat) if unpacked File
            // or fixed offset 0x200 if packed
            resource.sfxTableOffset = offTrackstep != 0 ? 0x200 : resource.patternOffset[127];

            // Read in macro starting offsets
            musicData.Seek(offMacroP, SeekOrigin.Begin);
            for (int i = 0; i < MaxMacroOffsets; ++i)
                resource.macroOffset[i] = br.ReadUInt32BigEndian();

            // Read in mdat-file
            // TODO: we can skip everything thats already stored in the resource-structure.
            var mdatOffset = offTrackstep != 0 ? 0x200 : 0x600;  // 0x200 is very conservative
            var allocSize = mdatSize - mdatOffset;

            musicData.Seek(mdatOffset, SeekOrigin.Begin);
            var mdatAlloc = br.ReadBytes((int)allocSize);

            resource.mdatAlloc = mdatAlloc;
            resource.mdatOffset = mdatOffset;
            resource.mdatLen = (int)mdatSize;
            return resource;
        }