예제 #1
0
        public void ReadBin()
        {
            using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open)))
            {
                filemagic = reader.ReadUInt16();


                filecount = reader.ReadUInt16();


                Console.WriteLine(filecount);
                for (int i = 0; i < filecount; i++)
                {
                    sfxfile newsfxfile = new sfxfile();
                    sfxfiles.Add(newsfxfile);
                    newsfxfile.parentbinfile  = this;
                    newsfxfile.offset         = reader.ReadUInt32();
                    newsfxfile.sizedividedby4 = reader.ReadUInt32();
                    if (filemagic == 0x0103)    //hr only
                    {
                        isHR = true;
                        Console.WriteLine("hr");
                        reader.BaseStream.Position += 0x04;
                    }
                    newsfxfile.samplerate = reader.ReadUInt16();

                    newsfxfile.unk1 = reader.ReadUInt16();
                }

                Console.WriteLine(sfxfiles.Count);

                for (int i = 0; i < sfxfiles.Count; i++)
                {
                    reader.BaseStream.Position = sfxfiles[i].offset;

                    if (sfxfiles[i].sizedividedby4 * 4 < filebytes.Length)
                    {
                        sfxfiles[i].filebytes = reader.ReadBytes((int)sfxfiles[i].sizedividedby4 * 4);
                    }
                }
            }
        }
예제 #2
0
        public void ReadBin()
        {
            using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open)))
            {
                filemagic = reader.ReadUInt16();

                filecount = reader.ReadUInt16();

                for (int i = 0; i < filecount; i++)
                {
                    sfxfile newsfxfile = new sfxfile();
                    sfxfiles.Add(newsfxfile);
                    newsfxfile.parentbinfile  = this;
                    newsfxfile.offset         = reader.ReadUInt32();
                    newsfxfile.sizedividedby4 = reader.ReadUInt32();
                    if (filemagic == 0x0103)    //hr only
                    {
                        isHR = true;
                        reader.BaseStream.Position += 0x04;
                    }
                    newsfxfile.samplerate = reader.ReadUInt16();
                    newsfxfile.indexInBin = i;
                    newsfxfile.isPCM      = reader.ReadUInt16() != 2; //because 0x02 is ADPCM format
                }

                for (int i = 0; i < sfxfiles.Count; i++)
                {
                    reader.BaseStream.Position = sfxfiles[i].offset;

                    if (sfxfiles[i].sizedividedby4 * 4 < filebytes.Length)
                    {
                        sfxfiles[i].filebytes = reader.ReadBytes((int)sfxfiles[i].sizedividedby4 * 4);
                    }
                }
            }
        }
예제 #3
0
        public List <Byte> MakeXM()
        {
            List <Byte> output = new List <byte>();

            foreach (char c in "Extended Module: ")
            {
                output.Add((byte)c);
            }

            for (int i = 0; i < Math.Min(name.Length - 3, 20); i++)
            {
                output.Add((byte)name[i]);
            }

            while (output.Count < 0x25)
            {
                output.Add(0x20);
            }

            output.Add(0x1A);


            foreach (char c in "EPFExplorer")
            {
                output.Add((byte)c);
            }

            while (output.Count < 0x3A)
            {
                output.Add(0x00);
            }

            output.Add(0x04);
            output.Add(0x01);

            output.Add(0x14);
            output.Add(0x01);
            output.Add(0x00);
            output.Add(0x00);

            output.Add((byte)number_of_patterns_in_one_loop);
            output.Add((byte)(number_of_patterns_in_one_loop >> 8));

            output.Add((byte)restartPosition);
            output.Add((byte)(restartPosition >> 8));

            output.Add((byte)numchannels);
            output.Add((byte)(numchannels >> 8));

            output.Add((byte)numpatterns);
            output.Add((byte)(numpatterns >> 8));

            output.Add((byte)parentbinfile.samplecount);
            output.Add((byte)(parentbinfile.samplecount >> 8));

            output.Add(0x01);
            output.Add(0x00);

            output.Add((byte)tempo);
            output.Add((byte)(tempo >> 8));

            output.Add((byte)bpm);
            output.Add((byte)(bpm >> 8));

            for (int i = 0; i < patternsInPlayingOrder.Count; i++)
            {
                output.Add((byte)patternsInPlayingOrder[i].index);
            }

            while (output.Count < 0x150)
            {
                output.Add(0x00);
            }

            foreach (Pattern p in patterns)
            {
                output.Add(0x09);
                output.Add(0x00);
                output.Add(0x00);
                output.Add(0x00);

                output.Add(0x00);

                output.Add((byte)p.number_of_rows);
                output.Add((byte)(p.number_of_rows >> 8));

                output.Add((byte)(p.patternSize));
                output.Add((byte)((p.patternSize) >> 8));

                foreach (byte[] row in p.rows)
                {
                    foreach (byte b in row)
                    {
                        output.Add(b);
                    }
                }
            }

            //write instrument section

            string instrument_name = "instrument_";
            string sample_name     = "sample_";

            for (int i = 0; i < samples.Count; i++)
            {
                sfxfile sample = (i >= 0 && i < samples.Count && samples[i] != null) ? samples[i] : null;
                output.Add(252);
                output.Add(0);
                output.Add(0);
                output.Add(0);

                int namelength = 0;

                foreach (char c in (instrument_name + i.ToString()))
                {
                    output.Add((byte)c);
                    namelength++;
                }

                while (namelength < 0x16)
                {
                    output.Add(0x00);
                    namelength++;
                }

                output.Add(0);
                output.Add(1);
                output.Add(0);

                output.Add(40);
                output.Add(0);
                output.Add(0);
                output.Add(0);
                for (int j = 0; j < 96; j++)
                {
                    output.Add(0);
                }
                if (sample != null)
                {
                    for (int j = 0; j < 24; j++)
                    {
                        output.Add(sample != null ? (byte)(sample.volenv.nodes[j] & 0xFF) : (byte)0);
                        output.Add(sample != null ? (byte)(sample.volenv.nodes[j] >> 8) : (byte)0);
                    }
                    for (int j = 0; j < 24; j++)
                    {
                        output.Add(sample != null ? (byte)(sample.panenv.nodes[j] & 0xFF) : (byte)0);
                        output.Add(sample != null ? (byte)(sample.panenv.nodes[j] >> 8) : (byte)0);
                    }
                    output.Add((byte)sample.volenv.count);
                    output.Add((byte)sample.panenv.count);
                    output.Add(sample.volenv.sustainPoint != 0xFF ? sample.volenv.sustainPoint : (byte)0);
                    output.Add(sample.volenv.loopStart != 0xFF ? sample.volenv.loopStart : (byte)0);
                    output.Add(sample.volenv.loopEnd != 0xFF ? sample.volenv.loopEnd : (byte)0);
                    output.Add(sample.panenv.sustainPoint != 0xFF ? sample.panenv.sustainPoint : (byte)0);
                    output.Add(sample.panenv.loopStart != 0xFF ? sample.panenv.loopStart : (byte)0);
                    output.Add(sample.panenv.loopEnd != 0xFF ? sample.panenv.loopEnd : (byte)0);
                    output.Add((byte)(
                                   (sample.volenv.count > 0 ? 1 : 0) |
                                   (sample.volenv.sustainPoint < sample.volenv.count ? 2 : 0) |
                                   (sample.volenv.loopStart < sample.volenv.count && sample.volenv.loopEnd < sample.volenv.count ? 4 : 0)
                                   ));
                    output.Add((byte)(
                                   (sample.panenv.count > 0 ? 1 : 0) |
                                   (sample.panenv.sustainPoint < sample.panenv.count ? 2 : 0) |
                                   (sample.panenv.loopStart < sample.panenv.count && sample.panenv.loopEnd < sample.panenv.count ? 4 : 0)
                                   ));
                    output.Add(0);
                    output.Add(0);
                    output.Add(0);
                    output.Add(0);
                    output.Add(0);
                    output.Add(0);
                }
                else
                {
                    for (int j = 0; j < 96 + 16; j++)
                    {
                        output.Add(0);
                    }
                }
                for (int j = 0; j < 11; j++)
                {
                    output.Add(0);
                }
                short[] pcm = sample != null?sample.ConvertToPCM() : new short[0]
                {
                };
                output.Add((byte)((pcm.Length * 2) & 0xFF));
                output.Add((byte)(((pcm.Length * 2) >> 8) & 0xFF));
                output.Add((byte)(((pcm.Length * 2) >> 16) & 0xFF));
                output.Add((byte)(((pcm.Length * 2) >> 24) & 0xFF));
                if (sample != null)
                {
                    output.Add((byte)((sample.loopstart * 4) & 0xFF));
                    output.Add((byte)(((sample.loopstart * 4) >> 8) & 0xFF));
                    output.Add((byte)(((sample.loopstart * 4) >> 16) & 0xFF));
                    output.Add((byte)(((sample.loopstart * 4) >> 24) & 0xFF));

                    output.Add((byte)(((sample.loopend * 4) - 0x10) & 0xFF));
                    output.Add((byte)(((sample.loopend * 4) >> 8) & 0xFF));
                    output.Add((byte)(((sample.loopend * 4) >> 16) & 0xFF));
                    output.Add((byte)(((sample.loopend * 4) >> 24) & 0xFF));
                }
                else
                {
                    for (int j = 0; j < 8; j++)
                    {
                        output.Add(0);
                    }
                }
                output.Add(sample != null ? sample.defaultvol : (byte)0);
                output.Add(sample != null ? (byte)sample.finetune : (byte)0);
                output.Add((byte)(0x10 | (sample != null && sample.loopstart != 0xFFFFFFFF && sample.loopend != 0xFFFFFFFF ? 1 : 0)));
                output.Add(sample != null ? sample.defaultpan : (byte)0x80);
                output.Add(sample != null ? (byte)sample.transpose : (byte)0);
                output.Add(0);

                namelength = 0;

                foreach (char c in (sample_name + i.ToString()))
                {
                    output.Add((byte)c);
                    namelength++;
                }

                while (namelength < 0x16)
                {
                    output.Add(0x00);
                    namelength++;
                }

                short old = 0;
                for (int j = 0; j < pcm.Length; j++)
                {
                    short n = (short)(pcm[j] - old);
                    output.Add((byte)(n & 0xFF));
                    output.Add((byte)((n >> 8) & 0xFF));
                    old = pcm[j];
                }
            }

            return(output);
        }
예제 #4
0
        public void ReadMusicBin()
        {
            using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open)))
            {
                filemagic = reader.ReadUInt16();

                if (filemagic == 0x0103)
                {
                    isHR = true;
                }

                samplecount = reader.ReadByte();
                filecount   = reader.ReadByte(); //music file count

                reader.BaseStream.Position   = 0x08;
                offsetOfMusicInstructionData = reader.ReadUInt32();


                reader.BaseStream.Position = 0x10;

                Console.WriteLine(filecount);
                for (int i = 0; i < filecount; i++)
                {
                    xmfile newxmfile = new xmfile();
                    xmfiles.Add(newxmfile);
                    newxmfile.parentbinfile = this;
                    newxmfile.offset        = reader.ReadUInt32();
                }

                offset_of_end_of_index_table = (int)reader.BaseStream.Position;

                Console.WriteLine(xmfiles.Count);

                for (int i = 0; i < xmfiles.Count; i++)
                {
                    if (i < xmfiles.Count - 1)
                    {
                        xmfiles[i].size = xmfiles[i + 1].offset - xmfiles[i].offset;
                    }
                    else
                    {
                        xmfiles[i].size = (uint)(filebytes.Length - xmfiles[i].offset); //it might be bigger than its intended size, but it won't matter once it's exported to XM
                    }

                    reader.BaseStream.Position = xmfiles[i].offset;

                    if (xmfiles[i].size < filebytes.Length)
                    {
                        xmfiles[i].filebytes = reader.ReadBytes((int)xmfiles[i].size);
                        xmfiles[i].ReadSongInfo();
                    }
                }


                if (xmfiles[2].offset == 2054556)
                {
                    ApplyEPFMusicFileNames();
                }
                else if (xmfiles[2].offset == 2339468)
                {
                    ApplyHRMusicFileNames();
                }
                else
                {
                    foreach (xmfile xm in xmfiles)
                    {
                        xm.name = Path.GetFileName(filename) + xm.offset;
                    }
                }


                samples = new sfxfile[samplecount];

                int pos = offset_of_end_of_index_table;

                for (int i = 0; i < samplecount; i++)
                {
                    sfxfile newSample = new sfxfile();

                    /*
                     * So it turns out that the chunk of data at the top of each sample,
                     * which was previously ignored, is actually chock full of information
                     * about the sample, including some instrument parameters including
                     * volume and panning envelopes. The previous behavior of splitting by
                     * 0x02004000 was flawed as well - PCM samples would have 0x00004000 in
                     * that place instead, causing all sorts of wacky issues when trying to
                     * decode an ADPCM sample that is followed by one or more PCM samples
                     * (this happened quite a bit during debugging).
                     *
                     * To keep things sane for the future, I'm including a speculative
                     * specification for the data contained in this chunk. Take this with a
                     * grain of salt, but I believe it should be correct (as long as my ears
                     * are working properly). Some of the descriptions may require
                     * understanding of the format of XM instruments.
                     *
                     * Offset  | Size     | Description
                     * --------+----------+-------------------------------------------------
                     * 0x00    | 4        | The size of the sample data divided by 4.
                     * 0x04    | 4        | The position of the start of the loop divided by 4, or 0xFFFFFFFF for no loop. (?)
                     * 0x08    | 4        | The position of the end of the loop divided by 4, or size+1 for no loop. (?)
                     * 0x0C    | 1        | The type of sample. 0 = s16 PCM, 2 = MS IMA ADPCM
                     * 0x0D    | 1        | Unknown (always 0). Could be upper byte of above.
                     * 0x0E    | 1        | Default volume for the sample.
                     * 0x0F    | 1        | Unknown (always 0). Could be upper byte of above.
                     * 0x10    | 1        | Finetune value. Stored as a signed byte.
                     * 0x11    | 1        | Transpose value. Stored as a signed byte. (For some reason, if the sample is PCM you should decrease this value by 12.)
                     * 0x12    | 0/4      | This field is present in HR but not EPF. Not sure what's in it yet. If on HR, add 4 to each subsequent offset.
                     * 0x12    | 1        | Default pan position. Stored as an unsigned byte, with 0x80 = center.
                     * 0x13    | 1        | Unknown (always 0).
                     * 0x14    | 1        | Number of nodes in the volume envelope.
                     * 0x15    | 1        | Position of volume envelope sustain node, or 0xFF for no sustain.
                     * 0x16    | 1        | Position of volume envelope loop start, or 0xFF for no loop.
                     * 0x17    | 1        | Position of volume envelope loop end, or 0xFF for no loop.
                     * 0x18    | 2*24     | Nodes in the volume envelope, alternating (x, y).
                     * 0x48    | 1        | Number of nodes in the panning envelope.
                     * 0x49    | 1        | Position of panning envelope sustain node, or 0xFF for no sustain.
                     * 0x4A    | 1        | Position of panning envelope loop start, or 0xFF for no loop.
                     * 0x4B    | 1        | Position of panning envelope loop end, or 0xFF for no loop.
                     * 0x4C    | 2*24     | Nodes in the panning envelope, alternating (x, y).
                     * 0x7C    | <size>   | The actual sample data.
                     */

                    uint offset = (uint)pos;
                    int  length = (filebytes[pos] | (filebytes[pos + 1] << 8) | (filebytes[pos + 2] << 16) | (filebytes[pos + 3] << 24)) * 4;
                    newSample.loopstart = (uint)(filebytes[pos + 4] | (filebytes[pos + 5] << 8) | (filebytes[pos + 6] << 16) | (filebytes[pos + 7] << 24)) * 4;
                    newSample.loopend   = (uint)(filebytes[pos + 8] | (filebytes[pos + 9] << 8) | (filebytes[pos + 10] << 16) | (filebytes[pos + 11] << 24)) * 4;
                    newSample.isPCM     = filebytes[pos + 12] != 2;
                    newSample.finetune  = (sbyte)filebytes[pos + 16];
                    newSample.transpose = (sbyte)filebytes[pos + 17];
                    if (newSample.isPCM)
                    {
                        newSample.transpose -= 12;
                    }
                    newSample.defaultvol = filebytes[pos + 14];
                    if (isHR)
                    {
                        pos += 22;
                    }
                    else
                    {
                        pos += 18;
                    }
                    if (!isHR && i >= 68 && i <= 73)
                    {
                        newSample.defaultpan = 0x80;                              // override for odd right-panned samples
                    }
                    else
                    {
                        newSample.defaultpan = filebytes[pos];
                    }

                    // Hot-patch for Snake Game samples, which have the wrong transpose
                    // (also changing finetune since that seems to make it sound better)
                    if (isHR)
                    {
                        if (i == 54 || i == 58 || i == 59)
                        {
                            newSample.transpose--;
                        }
                        if (i == 54 || i == 57 || i == 58 || i == 59)
                        {
                            newSample.defaultpan = 0x80;
                        }
                        if (i == 54)
                        {
                            newSample.finetune = -16;
                        }
                        else if (i == 57)
                        {
                            newSample.finetune = -30;
                        }
                        else if (i == 59)
                        {
                            newSample.finetune = -26;
                        }
                    }

                    newSample.volenv.count        = filebytes[pos + 2];
                    newSample.volenv.sustainPoint = filebytes[pos + 3];
                    newSample.volenv.loopStart    = filebytes[pos + 4];
                    newSample.volenv.loopEnd      = filebytes[pos + 5];
                    for (int j = 0; j < 24; j++)
                    {
                        newSample.volenv.nodes[j] = (short)(filebytes[pos + j * 2 + 6] | (filebytes[pos + j * 2 + 7] << 8));
                    }

                    newSample.panenv.count        = filebytes[pos + 54];
                    newSample.panenv.sustainPoint = filebytes[pos + 55];
                    newSample.panenv.loopStart    = filebytes[pos + 56];
                    newSample.panenv.loopEnd      = filebytes[pos + 57];
                    for (int j = 0; j < 24; j++)
                    {
                        newSample.panenv.nodes[j] = (short)(filebytes[pos + j * 2 + 58] | (filebytes[pos + j * 2 + 59] << 8));
                    }

                    pos += 106;

                    newSample.parentbinfile = this;

                    newSample.samplerate = 44100;
                    newSample.filebytes  = new byte[length];
                    Array.Copy(filebytes, pos, newSample.filebytes, 0, length);
                    newSample.offset = offset;
                    pos += length;


                    samples[i] = newSample;
                }

                foreach (xmfile xm in xmfiles)
                {
                    xm.samples = new List <sfxfile>(samples);
                }
            }
        }
예제 #5
0
        public void ReadMusicBin()
        {
            using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open)))
            {
                filemagic = reader.ReadUInt16();

                if (filemagic == 0x0103)
                {
                    isHR = true;
                }

                samplecount = reader.ReadByte();
                filecount   = reader.ReadByte(); //music file count

                reader.BaseStream.Position   = 0x08;
                offsetOfMusicInstructionData = reader.ReadUInt32();


                reader.BaseStream.Position = 0x10;

                Console.WriteLine(filecount);
                for (int i = 0; i < filecount; i++)
                {
                    xmfile newxmfile = new xmfile();
                    xmfiles.Add(newxmfile);
                    newxmfile.parentbinfile = this;
                    newxmfile.offset        = reader.ReadUInt32();
                }

                offset_of_end_of_index_table = (int)reader.BaseStream.Position;

                Console.WriteLine(xmfiles.Count);

                for (int i = 0; i < xmfiles.Count; i++)
                {
                    if (i < xmfiles.Count - 1)
                    {
                        xmfiles[i].size = xmfiles[i + 1].offset - xmfiles[i].offset;
                    }
                    else
                    {
                        xmfiles[i].size = (uint)(filebytes.Length - xmfiles[i].offset); //it might be bigger than its intended size, but it won't matter once it's exported to XM
                    }

                    reader.BaseStream.Position = xmfiles[i].offset;

                    if (xmfiles[i].size < filebytes.Length)
                    {
                        xmfiles[i].filebytes = reader.ReadBytes((int)xmfiles[i].size);
                        xmfiles[i].ReadSongInfo();
                    }
                }


                if (xmfiles[2].offset == 2054556)
                {
                    ApplyEPFMusicFileNames();
                }
                else if (xmfiles[2].offset == 2339468)
                {
                    ApplyHRMusicFileNames();
                }
                else
                {
                    foreach (xmfile xm in xmfiles)
                    {
                        xm.name = Path.GetFileName(filename) + xm.offset;
                    }
                }


                samples = new sfxfile[samplecount];

                int pos = (int)(offset_of_end_of_index_table + 76);

                if (isHR)
                {
                    pos += 4;
                }


                bool keepgoing = true;

                for (int i = 0; i < samplecount; i++)
                {
                    List <byte> newSampleBytes = new List <byte>();

                    int i_within_loop = i;

                    uint offset = (uint)pos;

                    while (keepgoing)
                    {
                        if (pos + 3 >= filebytes.Length)
                        {
                            keepgoing = false;
                            i         = samplecount - 1;
                        }
                        else if (filebytes[pos] == 0x02 && filebytes[pos + 1] == 0x00 && filebytes[pos + 2] == 0x40 && filebytes[pos + 3] == 0x00)
                        {
                            keepgoing = false;
                            pos      += 64;
                            if (isHR)
                            {
                                pos += 4;
                            }
                        }
                        else
                        {
                            newSampleBytes.Add(filebytes[pos]);
                            pos++;
                        }
                    }

                    newSampleBytes.RemoveRange(newSampleBytes.Count - 0x13, 0x13);

                    sfxfile newSample = new sfxfile();
                    newSample.parentbinfile = this;

                    newSample.samplerate = 44100;
                    newSample.filebytes  = newSampleBytes.ToArray();
                    newSample.offset     = offset;

                    samples[i_within_loop] = newSample;
                    keepgoing = true;
                }
            }
        }