Ejemplo n.º 1
0
        static void Main(string[] args)
        {
            Console.WriteLine("m4a2s version 0.1, Copyright (C) 2017 ipatix");
            Console.WriteLine("m4a2s comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt");
            Console.WriteLine("This is free software, and you are welcome to redistribute it");
            Console.WriteLine("under certain conditions; see LICENSE.txt for details.");


            int songtable = 0;

            if (args.Length != 3)
            {
                ShowUsage();
            }
            if (!File.Exists(args[0]))
            {
                ShowUsage();
            }
            if (!Directory.Exists(args[2]))
            {
                ShowUsage();
            }

            try
            {
                songtable = Convert.ToInt32(args[1], 16);
            }
            catch
            {
                ShowUsage();
            }

            string romPath    = args[0];
            string destFolder = args[2];


            if (!Directory.Exists(Path.Combine(destFolder, "seq")))
            {
                Directory.CreateDirectory(Path.Combine(destFolder, "seq"));
            }
            if (!Directory.Exists(Path.Combine(destFolder, "wave")))
            {
                Directory.CreateDirectory(Path.Combine(destFolder, "wave"));
            }
            if (!Directory.Exists(Path.Combine(destFolder, "bank")))
            {
                Directory.CreateDirectory(Path.Combine(destFolder, "bank"));
            }


            Rom.LoadRom(romPath, songtable);


            /*
             * build up the rom index
             */
            Console.WriteLine("Building up index");
            Stopwatch sw = new Stopwatch();

            sw.Start();
            Index.IndexRom();
            sw.Stop();
            Console.WriteLine("Index successfully build in {0} ms", sw.ElapsedMilliseconds);
            sw.Reset();
            sw.Start();

            Hashtable index = Index.GetHashtable();

            foreach (DictionaryEntry Hent in index)
            {
                Entity ent = (Entity)Hent.Value;

                string fileName;
                switch (ent.Type)
                {
                case EntityType.Bank:
                    fileName = Path.Combine(Path.Combine(destFolder, "bank"), ent.Guid + ".s");
                    Voicegroup.disassemble(index, ent, fileName);
                    break;

                case EntityType.KeyMap:
                    fileName = Path.Combine(Path.Combine(destFolder, "bank"), ent.Guid + ".s");
                    KeyMap.disassemble(ent, fileName);
                    break;

                case EntityType.Wave:
                    fileName = Path.Combine(Path.Combine(destFolder, "wave"), ent.Guid + ".s");
                    Wave.disassemble(ent, fileName);
                    break;

                case EntityType.GbWave:
                    fileName = Path.Combine(Path.Combine(destFolder, "wave"), ent.Guid + ".s");
                    GbWave.disassemble(ent, fileName);
                    break;

                case EntityType.Song:
                    fileName = Path.Combine(Path.Combine(destFolder, "seq"), ent.Guid + ".s");
                    Song.disassemble(index, ent, fileName);
                    break;

                default:
                    throw new Exception("Invalid Entity Type!");
                }

                Console.WriteLine("Succesfully disassembled Entity from 0x{0} to file: {1}", ent.Offset.ToString("X7"), fileName);
            }


            Songtable.disassemble(index, Path.Combine(destFolder, "_songtable.s"));
            sw.Stop();
            Console.WriteLine("Succesfully disassembled Songtable from 0x{0}", Rom.SongtableOffset);
            Console.WriteLine("Finished exporting data after {0} ms", sw.ElapsedMilliseconds);
        }
Ejemplo n.º 2
0
        public static void disassemble(Hashtable index, Entity song, string destFile)
        {
            StringBuilder oasm = new StringBuilder();

            oasm.AppendLine("@ File generated by m4a2s Song-Module");

            // read header information from ROM

            int songOffset = song.Offset;

            Rom.Reader.BaseStream.Position = songOffset;

            byte numTracks = Rom.Reader.ReadByte();
            byte numBlocks = Rom.Reader.ReadByte(); // as usual, the usage of this byte is unknown
            byte priority  = Rom.Reader.ReadByte();
            byte reverb    = Rom.Reader.ReadByte();

            int vgrOffset = Rom.Reader.ReadInt32() - Rom.Map;

            int[] trackOffsets = new int[numTracks];

            for (int i = 0; i < numTracks; i++)
            {
                trackOffsets[i] = Rom.Reader.ReadInt32() - Rom.Map;
            }

            oasm.AppendLine("\t.include \"MPlayDef.s\"");
            oasm.AppendLine();
            oasm.AppendLine("\t.equ\t" + song.Guid + "_grp, " + ((Entity)index[vgrOffset]).Guid);
            oasm.AppendLine("\t.equ\t" + song.Guid + "_pri, " + priority);
            oasm.AppendLine("\t.equ\t" + song.Guid + "_rev, " + reverb);
            oasm.AppendLine("\t.equ\t" + song.Guid + "_mvl, 127");
            oasm.AppendLine("\t.equ\t" + song.Guid + "_key, 0");
            oasm.AppendLine();
            oasm.AppendLine("\t.section .rodata");
            oasm.AppendLine("\t.global\t" + song.Guid);
            oasm.AppendLine("\t.align\t2");
            oasm.AppendLine();


            for (int cTrack = 0; cTrack < numTracks; cTrack++)
            {
                oasm.AppendLine("@*********************** Track " + (cTrack + 1).ToString("D2") + " ***********************@");
                oasm.AppendLine();
                oasm.AppendLine(song.Guid + "_" + cTrack + ":");

                // set reader position
                Rom.Reader.BaseStream.Position = trackOffsets[cTrack];

                Event lastEvent = Event.None;

                while (true)
                {
                    byte cmd = Rom.Reader.ReadByte();

                    // if delay
                    if (cmd >= 0x80 && cmd <= (0x80 + 48))
                    {
                        oasm.AppendLine("\t.byte\t" + Tables.Wxx[cmd - 0x80]);
                    }
                    // if FINE
                    else if (cmd == 0xB1)
                    {
                        oasm.AppendLine("\t.byte\tFINE");
                        oasm.AppendLine();
                        break;
                    }
                    // if GOTO
                    else if (cmd == 0xB2)
                    {
                        oasm.AppendLine("\t.byte\tGOTO");
                        int targetPosition = Rom.Reader.ReadInt32() - Rom.Map;
                        oasm.AppendLine("\t .word\t" + song.Guid + "_" + cTrack + " + 0x" +
                                        (targetPosition - trackOffsets[cTrack]).ToString("X"));
                        oasm.AppendLine("\t.byte\tFINE");
                        oasm.AppendLine();
                        break;
                    }
                    // if PATT
                    else if (cmd == 0xB3)
                    {
                        oasm.AppendLine("\t.byte\tPATT");
                        int targetPosition = Rom.Reader.ReadInt32() - Rom.Map;
                        oasm.AppendLine("\t .word\t" + song.Guid + "_" + cTrack + " + 0x" + (targetPosition - trackOffsets[cTrack]).ToString("X"));
                    }
                    // if PEND
                    else if (cmd == 0xB4)
                    {
                        oasm.AppendLine("\t.byte\tPEND");
                    }
                    // if REPT
                    else if (cmd == 0xB5)
                    {
                        byte numRepeats = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\tREPT  , " + numRepeats);
                        int targetPosition = Rom.Reader.ReadInt32() - Rom.Map;
                        oasm.AppendLine("\t .word\t" + song.Guid + "_" + cTrack + " + 0x" + (targetPosition - trackOffsets[cTrack]).ToString("X"));
                    }
                    // if MEMACC
                    else if (cmd == 0xB9)
                    {
                        byte par1 = Rom.Reader.ReadByte();
                        byte par2 = Rom.Reader.ReadByte();
                        byte par3 = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\tMEMACC, " + par1 + ", " + par2 + ", " + par3);
                    }
                    // if PRIO
                    else if (cmd == 0xBA)
                    {
                        byte prio = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\tPRIO  , " + prio);
                    }
                    // if TEMPO
                    else if (cmd == 0xBB)
                    {
                        int speed = Rom.Reader.ReadByte() * 2;
                        oasm.AppendLine("\t.byte\tTEMPO , " + speed + "/2");
                    }
                    // if KEYSH
                    else if (cmd == 0xBC)
                    {
                        int    shift = Rom.Reader.ReadSByte();
                        string str;
                        if (shift < 0)
                        {
                            str = shift.ToString();
                        }
                        else
                        {
                            str = "+" + shift;
                        }
                        oasm.AppendLine("\t.byte\tKEYSH , " + song.Guid + "_key" + str);
                    }
                    // if VOICE
                    else if (cmd == 0xBD)
                    {
                        byte instr = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\t\tVOICE , " + instr);
                    }

                    /*
                     * from here repeatable commands will follow
                     */
                    // if VOL
                    else if (cmd == 0xBE)
                    {
                        byte vol = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\t\tVOL   , " + vol + "*" + song.Guid + "_mvl/mxv");
                        lastEvent = Event.Vol;
                    }
                    // if PAN
                    else if (cmd == 0xBF)
                    {
                        byte   pan = Rom.Reader.ReadByte();
                        string str;
                        if (pan < 0x40)
                        {
                            str = (pan - 0x40).ToString();
                        }
                        else
                        {
                            str = "+" + (pan - 0x40);
                        }
                        oasm.AppendLine("\t.byte\t\tPAN   , c_v" + str);
                        lastEvent = Event.Pan;
                    }
                    // if BEND
                    else if (cmd == 0xC0)
                    {
                        byte   bend = Rom.Reader.ReadByte();
                        string str;
                        if (bend < 0x40)
                        {
                            str = (bend - 0x40).ToString();
                        }
                        else
                        {
                            str = "+" + (bend - 0x40);
                        }
                        oasm.AppendLine("\t.byte\t\tBEND  , c_v" + str);
                        lastEvent = Event.Bend;
                    }
                    // if BENDR
                    else if (cmd == 0xC1)
                    {
                        byte bendr = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\t\tBENDR , " + bendr);
                        lastEvent = Event.Bendr;
                    }
                    // if LFOS
                    else if (cmd == 0xC2)
                    {
                        byte lfos = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\t\tLFOS  , " + lfos);
                    }
                    // if LFODL
                    else if (cmd == 0xC3)
                    {
                        byte lfodl = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\t\tLFODL , " + lfodl);
                    }
                    // if MOD
                    else if (cmd == 0xC4)
                    {
                        byte mod = Rom.Reader.ReadByte();
                        oasm.AppendLine("\t.byte\t\tMOD   , " + mod);
                        lastEvent = Event.Mod;
                    }
                    // if MODT
                    else if (cmd == 0xC5)
                    {
                        byte modt = Rom.Reader.ReadByte();
                        if (modt < 3)
                        {
                            oasm.AppendLine("\t.byte\t\tMODT  , " + Tables.Modt[modt]);
                        }
                        else
                        {
                            oasm.AppendLine("\t.byte\t\tMODT  , " + modt);
                        }
                    }
                    // if TUNE
                    else if (cmd == 0xC8)
                    {
                        byte   tune = Rom.Reader.ReadByte();
                        string str;
                        if (tune < 0x40)
                        {
                            str = (tune - 0x40).ToString();
                        }
                        else
                        {
                            str = "+" + (tune - 0x40);
                        }
                        oasm.AppendLine("\t.byte\t\tTUNE  , c_v" + str);
                        lastEvent = Event.Tune;
                    }
                    // if XCMD
                    else if (cmd == 0xCD)
                    {
                        byte xcmdtype = Rom.Reader.ReadByte();
                        byte xcmdarg  = Rom.Reader.ReadByte();
                        if (xcmdtype == 0x8)
                        {
                            oasm.AppendLine("\t.byte\t\tXCMD  , xIECV , " + xcmdarg);
                        }
                        else if (xcmdtype == 0x9)
                        {
                            oasm.AppendLine("\t.byte\t\tXCMD  , xIECL , " + xcmdarg);
                        }
                        else
                        {
                            throw new NotSupportedException("Invalid XCMD Type");
                        }
                        lastEvent = Event.Xcmd;
                    }
                    // if EOT
                    else if (cmd == 0xCE)
                    {
                        if (Rom.ReaderPeekByte() <= 127)
                        {
                            oasm.AppendLine("\t.byte\t\tEOT   , " + Tables.Note[Rom.Reader.ReadByte()]);
                        }
                        else
                        {
                            oasm.AppendLine("\t.byte\t\tEOT");
                        }

                        lastEvent = Event.Eot;
                    }
                    // if NOTE
                    else if (cmd >= 0xCF && cmd <= (0xD0 + 47))
                    {
                        oasm.Append("\t.byte\t\t" + Tables.Nxx[cmd - 0xCF]);
                        if (Rom.ReaderPeekByte() > 127) // peek note pitch
                        {
                            oasm.AppendLine();
                        }
                        else
                        {
                            oasm.Append("   , " + Tables.Note[Rom.Reader.ReadByte()]);
                            if (Rom.ReaderPeekByte() > 127) // peek note velocity
                            {
                                oasm.AppendLine();
                            }
                            else
                            {
                                oasm.Append(", v" + Rom.Reader.ReadByte().ToString("D3"));
                                if (Rom.ReaderPeekByte() > 127)
                                {
                                    oasm.AppendLine();
                                }
                                else
                                {
                                    oasm.AppendLine(", " + Tables.Gtp(Rom.Reader.ReadByte()));
                                }
                            }
                        }
                        lastEvent = Event.Note;
                    }
                    else if (cmd >= 0x0 && cmd <= 0x7F)
                    {
                        if (lastEvent == Event.Bend)
                        {
                            int    bend = cmd - 0x40;
                            string str;
                            if (bend < 0)
                            {
                                str = bend.ToString();
                            }
                            else
                            {
                                str = "+" + bend;
                            }
                            oasm.AppendLine("\t.byte\t\t        c_v" + str);
                        }
                        else if (lastEvent == Event.Bendr)
                        {
                            oasm.AppendLine("\t.byte\t\t        " + cmd);
                        }
                        else if (lastEvent == Event.Eot)
                        {
                            oasm.AppendLine("\t.byte\t\t        " + Tables.Note[cmd]);
                        }
                        else if (lastEvent == Event.Mod)
                        {
                            oasm.AppendLine("\t.byte\t\t        " + cmd);
                        }
                        else if (lastEvent == Event.None)
                        {
                            Console.Write(oasm.ToString());
                            throw new Exception("Trying to repeat an event that hasn't occured yet");
                        }
                        else if (lastEvent == Event.Note)
                        {
                            oasm.Append("\t.byte\t\t        " + Tables.Note[cmd]);
                            if (Rom.ReaderPeekByte() > 128) // probe for velocity
                            {
                                oasm.AppendLine();
                            }
                            else
                            {
                                oasm.Append(", v" + Rom.Reader.ReadByte().ToString("D3"));
                                if (Rom.ReaderPeekByte() > 128) // peek for gate time
                                {
                                    oasm.AppendLine();
                                }
                                else
                                {
                                    oasm.AppendLine(", " + Tables.Gtp(Rom.Reader.ReadByte()));
                                }
                            }
                        }
                        else if (lastEvent == Event.Pan)
                        {
                            int    pan = cmd - 0x40;
                            string str;
                            if (pan < 0)
                            {
                                str = pan.ToString();
                            }
                            else
                            {
                                str = "+" + pan;
                            }
                            oasm.AppendLine("\t.byte\t\t        c_v" + str);
                        }
                        else if (lastEvent == Event.Tune)
                        {
                            int    tune = cmd - 0x40;
                            string str;
                            if (tune < 0)
                            {
                                str = tune.ToString();
                            }
                            else
                            {
                                str = "+" + tune;
                            }
                            oasm.AppendLine("\t.byte\t\t        c_v" + str);
                        }
                        else if (lastEvent == Event.Vol)
                        {
                            oasm.AppendLine("\t.byte\t\t        " + cmd + "*" + song.Guid + "_mvl/mxv");
                        }
                        else if (lastEvent == Event.Xcmd)
                        {
                            byte xcmdtype = cmd;
                            byte xcmdarg  = Rom.Reader.ReadByte();

                            if (xcmdtype == 0x8)
                            {
                                oasm.AppendLine("\t.byte\t\t        xIECV , " + xcmdarg);
                            }
                            else if (xcmdtype == 0x9)
                            {
                                oasm.AppendLine("\t.byte\t\t        xIECL , " + xcmdarg);
                            }
                            else
                            {
                                Console.Write(oasm.ToString());
                                throw new NotSupportedException("Invalid XCMD Type");
                            }
                        }
                        else
                        {
                            throw new Exception("This Exception shouldn't be able to occur!");
                        }
                    }
                    // if an unsupported command occurs
                    else
                    {
                        throw new Exception("Unsupported command 0x" + cmd.ToString("X2")
                                            + " at offset 0x" + (Rom.Reader.BaseStream.Position - 1).ToString("X7")
                                            + " on track " + cTrack
                                            + " from song-header at 0x" + song.Offset.ToString("X7"));
                    }
                }
            }

            oasm.AppendLine("@******************************************************@");
            oasm.AppendLine();
            oasm.AppendLine("\t.align\t2");
            oasm.AppendLine();
            oasm.AppendLine(song.Guid + ":");

            oasm.AppendLine("\t.byte\t" + numTracks + "\t@ NumTrks");
            oasm.AppendLine("\t.byte\t" + numBlocks + "\t@ NumBlks");
            oasm.AppendLine("\t.byte\t" + song.Guid + "_pri\t@ Priority");
            oasm.AppendLine("\t.byte\t" + song.Guid + "_rev\t@ Reverb");
            oasm.AppendLine();
            oasm.AppendLine("\t.word\t" + song.Guid + "_grp");
            oasm.AppendLine();

            for (int i = 0; i < numTracks; i++)
            {
                oasm.AppendLine("\t.word\t" + song.Guid + "_" + i);
            }

            oasm.AppendLine();
            oasm.AppendLine("\t.end");

            File.WriteAllText(destFile, oasm.ToString());
        }