Beispiel #1
0
        public MOD(Data.Buffer data)
        {
            data.SetEndianess(Endian.Endianess.Big);

            Log.Info.Write(ErrorSystemType.Data, $"Loading MOD song: {System.Text.Encoding.ASCII.GetString(data.Pop(20).ReinterpretAsArray(20))}"); // songname

            // add dummy sample 0
            samples.Add(new Sample());

            for (int i = 1; i < 32; ++i)                                                                                                               // samples 1-31
            {
                Log.Info.Write(ErrorSystemType.Data, $"Sample {i} name: {System.Text.Encoding.ASCII.GetString(data.Pop(22).ReinterpretAsArray(22))}"); // samplename

                samples.Add(new Sample()
                {
                    Length            = data.Pop <UInt16>() * 2,
                    FineTune          = ConvertFineTune(data.Pop <byte>() & 0xf),
                    Volume            = data.Pop <byte>(), // 0-64, change in dB = 20*log10(Volume/64)
                    RepeatPointOffset = data.Pop <UInt16>() * 2,
                    RepeatLength      = Math.Max(0, data.Pop <UInt16>() - 1) * 2
                });
            }

            int songLength = data.Pop <byte>();

            if (songLength < 1 || songLength > 128)
            {
                throw new ExceptionAudio("Invalid MOD format.");
            }

            data.Skip(1);

            byte[] songPatterns = data.Pop(128).ReinterpretAsArray(128);

            var magic = data.Pop(4).ToString();

            if (magic != "M!K!" && magic != "M.K.")
            {
                throw new ExceptionAudio("Invalid or unsupported MOD format.");
            }

            int            numPatterns = songPatterns.Max() + 1;
            List <Pattern> patterns    = new List <Pattern>(numPatterns);

            for (int i = 0; i < numPatterns; ++i)
            {
                var pattern = new Pattern();

                for (int div = 0; div < 64; ++div)
                {
                    for (int chan = 0; chan < 4; ++chan)
                    {
                        pattern.AddNote(chan, new Note(data));
                    }
                }

                patterns.Add(pattern);
            }

            for (int i = 0; i < samples.Count; ++i)
            {
                if (samples[i].Length > 0)
                {
                    data.Skip(2); // ignore tracker word
                    samples[i].Length -= 2;

                    uint length = (uint)samples[i].Length;

                    if (length > 0)
                    {
                        samples[i].SetData(data.Pop(length).ReinterpretAsArray(length));
                    }
                }
            }

            for (int i = 0; i < songLength; ++i)
            {
                song.Add(patterns[songPatterns[i]]);
            }
        }
Beispiel #2
0
        public XMI(Data.Buffer data)
        {
            // Note: Chunk length and so on are encoded as big endian.
            // But as we don't use them we use little endian because
            // the XMI data is encoded in little endian.
            data.SetEndianess(Endian.Endianess.Little);

            // Form chunk
            if (data.ToString(4) != "FORM")
            {
                return;
            }

            data.Pop(4);       // FORM
            data.Pop <uint>(); // FORM chunk length

            // format XDIR
            if (data.ToString(4) != "XDIR")
            {
                return;
            }

            data.Pop(4); // XDIR

            if (data.ToString(4) != "INFO")
            {
                return;
            }

            data.Pop(4);       // INFO
            data.Pop <uint>(); // INFO chunk length

            int numTracks = data.Pop <ushort>();

            if (numTracks != 1)
            {
                return; // we only support one track per file
            }
            if (data.ToString(4) != "CAT ")
            {
                return;
            }

            data.Pop(4);       // CAT_
            data.Pop <uint>(); // CAT chunk length

            // format XMID
            if (data.ToString(4) != "XMID")
            {
                return;
            }

            data.Pop(4); // XMID

            // load the one track

            // Form chunk
            if (data.ToString(4) != "FORM")
            {
                return;
            }

            data.Pop(4);       // FORM
            data.Pop <uint>(); // FORM chunk length

            // format XMID
            if (data.ToString(4) != "XMID")
            {
                return;
            }

            data.Pop(4); // XMID

            // TIMB chunk
            if (data.ToString(4) != "TIMB")
            {
                return;
            }

            data.Pop(4);       // TIMB
            data.Pop <uint>(); // TIMB chunk length

            int count = data.Pop <ushort>();

            for (int j = 0; j < count; ++j)
            {
                // we don't need the TIMB information, just skip it
                data.Pop(2);
            }

            // EVNT chunk
            if (data.ToString(4) != "EVNT")
            {
                return;
            }

            data.Pop(4);       // EVNT
            data.Pop <uint>(); // EVNT chunk length

            // read xmi/midi events
            while (data.Readable())
            {
                ParseEvent(data);
            }

            var eventIndices = new Dictionary <Event, int>();

            for (int i = 0; i < events.Count; ++i)
            {
                eventIndices.Add(events[i], i);
            }

            events.Sort((a, b) =>
            {
                int result = a.StartTime.CompareTo(b.StartTime);

                if (result == 0)
                {
                    return(eventIndices[a].CompareTo(eventIndices[b]));
                }

                return(result);
            });
        }