Advertisement
Nicknine

EA MPF to TXT

Sep 2nd, 2022 (edited)
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.35 KB | None | 0 0
  1. import os
  2. import struct
  3. import ctypes as ct
  4. import sys
  5. import glob
  6.  
  7. def unpackLE(typ,data): return struct.unpack("<"+typ,data)
  8. def unpackBE(typ,data): return struct.unpack(">"+typ,data)
  9.  
  10. def convert(fname):
  11.     f=open(fname,"rb")
  12.     f2=open(fname[:-4]+".txt","w")
  13.     magic=f.read(0x04)
  14.     if magic==b"xDFP":
  15.         unpacker=unpackLE
  16.         struct=ct.LittleEndianStructure
  17.         union=ct.LittleEndianUnion
  18.     elif magic==b"PFDx":
  19.         unpacker=unpackBE
  20.         struct=ct.BigEndianStructure
  21.         union=ct.BigEndianUnion
  22.     else:
  23.         raise ValueError("Bad header magic")
  24.  
  25.     f.seek(0x00)
  26.  
  27.     # Read header.
  28.     class PATHFINDHEADER(struct):
  29.         _fields_ = [
  30.             ("id",ct.c_int32),
  31.             ("majorRev",ct.c_uint8),
  32.             ("minorRev",ct.c_uint8),
  33.             ("release",ct.c_uint8),
  34.             ("prerelease",ct.c_uint8),
  35.             ("saveIncrement",ct.c_uint16),
  36.             ("generateID",ct.c_uint16),
  37.             ("projectID",ct.c_uint8),
  38.             ("numtracks",ct.c_uint8),
  39.             ("numsections",ct.c_uint8),
  40.             ("numevents",ct.c_uint8),
  41.             ("numrouters",ct.c_uint8),
  42.             ("numnamedvars",ct.c_uint8),
  43.             ("numnodes",ct.c_uint16),
  44.             ("nodeoffsets",ct.c_uint32),
  45.             ("nodedata",ct.c_uint32),
  46.             ("eventoffsets",ct.c_uint32),
  47.             ("eventdata",ct.c_uint32),
  48.             ("namedvars",ct.c_uint32),
  49.             ("noderouters",ct.c_uint32),
  50.             ("trackoffsets",ct.c_uint32),
  51.             ("trackinfos",ct.c_uint32),
  52.             ("sampleoffsets",ct.c_uint32),
  53.             ("mapfilelen",ct.c_uint32),
  54.             ("v40reserve",ct.c_uint32*3)
  55.         ]
  56.  
  57.     hdr=PATHFINDHEADER()
  58.     f.readinto(hdr)
  59.     if hdr.majorRev!=5:
  60.         raise ValueError("Unsupported MPF version")
  61.  
  62.     namedvars=list()
  63.  
  64.     # Read named vars.
  65.     class PATHNAMEDVAR(struct):
  66.         _fields_ = [
  67.             ("name",ct.c_char*16),
  68.             ("value",ct.c_int32)
  69.         ]
  70.  
  71.     f.seek(hdr.namedvars)
  72.     for i in range(hdr.numnamedvars):
  73.         var=PATHNAMEDVAR()
  74.         f.readinto(var)
  75.         namedvars.append((var.name.decode(),var.value))
  76.  
  77.     # Read nodes.
  78.     class PATHNODEBEATS(struct):
  79.         _fields_ = [
  80.             ("forcesynch",ct.c_uint32,1),
  81.             ("playbeats",ct.c_uint32,1)
  82.         ]
  83.  
  84.     class PATHNODEEVENT(struct):
  85.         _fields_ = [
  86.             ("eventID",ct.c_uint32,24)
  87.         ]
  88.  
  89.     class PATHNODECHANNEL(struct):
  90.         _fields_ = [
  91.             ("eventID",ct.c_uint32,24),
  92.             ("channelset",ct.c_uint32,4)
  93.         ]
  94.  
  95.     class PATHNODEEXTRA(union):
  96.         _fields_ = [
  97.             ("beat",PATHNODEBEATS),
  98.             ("sendevent",PATHNODEEVENT),
  99.             ("channelbranch",PATHNODECHANNEL)
  100.         ]
  101.  
  102.     class PATHFINDNODE(struct):
  103.         _fields_ = [
  104.             ("index",ct.c_int32,16),
  105.             ("trackID",ct.c_uint32,5),
  106.             ("sectionID",ct.c_uint32,6),
  107.             ("repeat",ct.c_int32,5),
  108.             ("routerID",ct.c_uint32,12),
  109.             ("numbranches",ct.c_uint32,5),
  110.             ("controller",ct.c_uint32,3),
  111.             ("beats",ct.c_uint32,4),
  112.             ("bars",ct.c_uint32,8),
  113.             ("partID",ct.c_uint32,16),
  114.             ("synchevery",ct.c_uint32,4),
  115.             ("synchoffset",ct.c_uint32,4),
  116.             ("notes",ct.c_uint32,4),
  117.             ("synch",ct.c_uint32,2),
  118.             ("channelbranching",ct.c_uint32,1),
  119.             ("unused",ct.c_uint32,1),
  120.             #("extra",PATHNODEEXTRA)
  121.         ]
  122.  
  123.     class PATHFINDBRANCH(struct):
  124.         _fields_ = [
  125.             ("controlmin",ct.c_int8),
  126.             ("controlmax",ct.c_int8),
  127.             ("dstnode",ct.c_uint16)
  128.         ]
  129.  
  130.     f2.write("#"+"-"*72+"\n")
  131.     f2.write("# Nodes\n")
  132.     f2.write("#"+"-"*72+"\n")
  133.    
  134.     f.seek(hdr.nodeoffsets)
  135.     nodeOffsets=list()
  136.     for i in range(hdr.numnodes):
  137.         offset=unpacker("H",f.read(0x02))[0]
  138.         offset*=0x04
  139.         nodeOffsets.append(offset)
  140.  
  141.     for i in range(hdr.numnodes):
  142.         offset=nodeOffsets[i]
  143.         f.seek(offset)
  144.        
  145.         f2.write("Node %d # 0x%08x\n" % (i,offset))
  146.         f2.write("{\n")
  147.        
  148.         node=PATHFINDNODE()
  149.         f.readinto(node)
  150.         extra=PATHNODEEXTRA()
  151.         f.readinto(extra)
  152.        
  153.         f2.write("\tWave %d\n" % node.index)
  154.         f2.write("\tTrack %d\n" % node.trackID)
  155.         f2.write("\tSection %d\n" % node.sectionID)
  156.         f2.write("\tPart %d\n" % node.partID)
  157.         f2.write("\tRouter %d\n" % (node.routerID-1))
  158.         f2.write("\tController %s\n" % ("Normal" if node.controller==0 else "Random"))
  159.         #f2.write("\tController %d\n" % node.controller)
  160.         #f2.write("\tBeats %d\n" % node.beats)
  161.         #f2.write("\tBars %d\n" % node.bars)
  162.         if node.index==-1:
  163.             f2.write("\tRepeat %d\n" % (node.repeat))
  164.         if node.index==-3:
  165.             sendevent=extra.sendevent
  166.             f2.write("\tEvent 0x%08x\n" % (sendevent.eventID))
  167.         else:
  168.             pass
  169.         f2.write("\tBranches\n")
  170.         f2.write("\t{\n")
  171.         for i in range(node.numbranches):
  172.             branch=PATHFINDBRANCH()
  173.             f.readinto(branch)
  174.             f2.write("\t\tControl %d-%d -> %d\n" % (branch.controlmin,branch.controlmax,branch.dstnode))
  175.         f2.write("\t}\n")
  176.         f2.write("}\n")
  177.  
  178.     # Read events.
  179.     class PATHEVENT(struct):
  180.         _fields_ = [
  181.             ("queued",ct.c_uint32),
  182.             ("expiry",ct.c_uint32),
  183.             ("lastact",ct.c_uint32),
  184.             ("eventID",ct.c_uint32,24),
  185.             ("numactions",ct.c_uint32,8),
  186.             ("currentaction",ct.c_uint32,8),
  187.             ("voices",ct.c_uint32,4),
  188.             ("priority",ct.c_int32,4),
  189.             ("bumplower",ct.c_uint32,1),
  190.             ("beingFiltered",ct.c_uint32,1),
  191.             ("project",ct.c_int32,3),
  192.             ("unused",ct.c_int32,11)
  193.         ]
  194.  
  195.     class PATHACTCONDITION(struct):
  196.         _fields_ = [
  197.             ("value",ct.c_int32,16),
  198.             ("compareValue",ct.c_int32,16)
  199.         ]
  200.  
  201.     class PATHACTBRANCHTO(struct):
  202.         _fields_ = [
  203.             ("node",ct.c_int32,16),
  204.             ("ofsection",ct.c_int32,8),
  205.             ("immediate",ct.c_int32,1)
  206.         ]
  207.  
  208.     class PATHACTSETVALUE(struct):
  209.         _fields_ = [
  210.             ("towhat",ct.c_int32,16),
  211.             ("setwhat",ct.c_uint32,8)
  212.         ]
  213.  
  214.     class PATHACTEVENT(struct):
  215.         _fields_ = [
  216.             ("eventID",ct.c_uint32,24)
  217.         ]
  218.  
  219.     class PATHACTCALC(struct):
  220.         _fields_ = [
  221.             ("value",ct.c_uint32,8),
  222.             ("op",ct.c_uint32,8),
  223.             ("by",ct.c_int32,16)
  224.         ]
  225.  
  226.     class PATHACTWAITTIME(struct):
  227.         _fields_ = [
  228.             ("millisecs",ct.c_int32,16),
  229.             ("lowest",ct.c_int32,16)
  230.         ]
  231.  
  232.     class PATHACT(union):
  233.         _fields_ = [
  234.             ("only",PATHACTCONDITION),
  235.             ("waittime",PATHACTWAITTIME),
  236.             ("branch",PATHACTBRANCHTO),
  237.             ("setval",PATHACTSETVALUE),
  238.             ("event",PATHACTEVENT),
  239.             ("calc",PATHACTCALC),
  240.         ]
  241.  
  242.     class PATHACTION(struct):
  243.         _fields_ = [
  244.             ("track",ct.c_int32),
  245.             ("sectionID",ct.c_int32,8),
  246.             ("type",ct.c_uint32,7),
  247.             ("done",ct.c_uint32,1),
  248.             ("leftvaluetype",ct.c_uint32,2),
  249.             ("rightvaluetype",ct.c_uint32,2),
  250.             ("assess",ct.c_uint32,3),
  251.             ("comparison",ct.c_uint32,3),
  252.             ("indent",ct.c_uint32,3),
  253.             ("unused",ct.c_uint32,3),
  254.             #("act",PATHACT)
  255.         ]
  256.  
  257.     specialTypes = [
  258.         "SPECIALVALUE_BAD",
  259.         "CONTROLLER",
  260.         "CURRENTNODE",
  261.         "CURRENTPART",
  262.         "CURRENTSECTION",
  263.         "EVENTEXPIRY",
  264.         "EVENTPRIORITY",
  265.         "FXBUS",
  266.         "FXDRYLEVEL",
  267.         "FXSENDLEVEL",
  268.         "MAINVOICE",
  269.         "NEXTNODE",
  270.         "NOBRANCHING",
  271.         "NODEDURATION",
  272.         "PAUSE",
  273.         "PITCHMULT",
  274.         "PLAYINGNODE",
  275.         "PLAYSTATUS",
  276.         "RANDOMSHORT",
  277.         "TIMENOW",
  278.         "TIMETONEXTBEAT",
  279.         "TIMETONEXTBAR",
  280.         "TIMETONEXTNODE",
  281.         "VOLUME",
  282.         "TIMESTRETCH",
  283.         "BARDURATION",
  284.         "BEATDURATION",
  285.         "CURRENTCHANNELSET",
  286.         "PLAYINGCHANNELSET",
  287.     ]
  288.  
  289.     def actValToString(val,typ):
  290.         if typ==1:
  291.             return specialTypes[val]
  292.         elif typ==2:
  293.             return "vars[\"%s\"]" % (namedvars[val][0])
  294.         elif typ==3:
  295.             return val
  296.         raise Exception("Bad value type %d in event" % (typ))
  297.  
  298.     f2.write("\n")
  299.     f2.write("#"+"-"*72+"\n")
  300.     f2.write("# Events\n")
  301.     f2.write("#"+"-"*72+"\n")
  302.    
  303.     f.seek(hdr.eventoffsets)
  304.     eventOffsets=list()
  305.  
  306.     for i in range(hdr.numevents):
  307.         offset=unpacker("H",f.read(0x02))[0]
  308.         offset*=0x04
  309.         eventOffsets.append(offset)
  310.  
  311.     for i in range(hdr.numevents):
  312.         offset=eventOffsets[i]
  313.         f.seek(offset)
  314.        
  315.         event=PATHEVENT()
  316.         f.readinto(event)
  317.  
  318.         f2.write("Event 0x%08x # 0x%08x\n" % (event.eventID,offset))
  319.         #f2.write("Event %d # 0x%08x\n" % (event.eventID,offset))
  320.         f2.write("{\n")
  321.  
  322.         f2.write("\tActions\n")
  323.         f2.write("\t{\n")
  324.         indent=0
  325.         for i in range(event.numactions):
  326.             action=PATHACTION()
  327.             f.readinto(action)
  328.             act=PATHACT()
  329.             f.readinto(act)
  330.            
  331.             if action.type==1 and action.assess>1:
  332.                 indent-=1
  333.             f2.write("\t"*indent)
  334.            
  335.             if action.type==1:
  336.                 assessments = [
  337.                     None,
  338.                     "If",
  339.                     "Elif",
  340.                     "Else",
  341.                     "Endif"
  342.                 ]
  343.                 signs = [
  344.                     None,
  345.                     "==",
  346.                     "!=",
  347.                     ">",
  348.                     "<",
  349.                     ">=",
  350.                     "<="
  351.                 ]
  352.                 if action.assess in [1,2]:
  353.                     f2.write("\t\t%s %s %s %s\n" %
  354.                              (assessments[action.assess],
  355.                               actValToString(act.only.value,action.leftvaluetype),
  356.                               signs[action.comparison],
  357.                               actValToString(act.only.compareValue,action.rightvaluetype)))
  358.                 else:
  359.                     f2.write("\t\t%s\n" % (assessments[action.assess]))
  360.             elif action.type==2:
  361.                 f2.write("\t\tWait %d\n" % (act.waittime.millisecs))
  362.             elif action.type==4:
  363.                 f2.write("\t\tBranch %s (%s)" %
  364.                          (actValToString(act.branch.node,action.leftvaluetype),act.branch.ofsection))
  365.                 if act.branch.immediate:
  366.                     f2.write(" Immediate")
  367.                 f2.write("\n")
  368.             elif action.type==8:
  369.                 f2.write("\t\tSet %s = %s\n" %
  370.                          (actValToString(act.setval.setwhat,action.leftvaluetype),
  371.                           actValToString(act.setval.towhat,action.rightvaluetype)))
  372.             elif action.type==9:
  373.                 f2.write("\t\tEvent 0x%08x\n" % (act.event.eventID))
  374.             elif action.type==14:
  375.                 signs = [
  376.                     None,
  377.                     "+",
  378.                     "-",
  379.                     "*",
  380.                     "/",
  381.                     "%"
  382.                 ]
  383.                 f2.write("\t\tCalc %s %s %s\n" %
  384.                          (actValToString(act.calc.value,action.leftvaluetype),
  385.                           signs[act.calc.op],
  386.                           actValToString(act.calc.by,action.rightvaluetype)))
  387.             else:
  388.                 f2.write("\t\tAction %d\n" % (action.type))
  389.  
  390.             if action.type==1 and action.assess<4:
  391.                 indent+=1
  392.                
  393.         f2.write("\t}\n")
  394.         f2.write("}\n")
  395.  
  396.     f2.write("#"+"-"*72+"\n")
  397.     f2.write("# Named vars\n")
  398.     f2.write("#"+"-"*72+"\n")
  399.  
  400.     for i in range(hdr.numnamedvars):
  401.         var,val=namedvars[i]
  402.         f2.write("Var %d\n" % i)
  403.         f2.write("{\n")
  404.         f2.write("\t%s = %d\n" % (var,val))
  405.         f2.write("}\n")
  406.  
  407.     f2.write("#"+"-"*72+"\n")
  408.     f2.write("# Routers\n")
  409.     f2.write("#"+"-"*72+"\n")
  410.  
  411.     f.seek(hdr.noderouters)
  412.     routerOffsets=list()
  413.     for i in range(hdr.numrouters+1):
  414.         offset=unpacker("I",f.read(0x04))[0] * 0x04
  415.         routerOffsets.append(offset)
  416.  
  417.     for i in range(hdr.numrouters):
  418.         offset=routerOffsets[i]
  419.         nextOffset=routerOffsets[i+1]
  420.         f.seek(offset)
  421.         f2.write("Router %d\n" % i)
  422.         f2.write("{\n")
  423.         while f.tell()!=nextOffset:
  424.             router=unpacker("I",f.read(0x04))[0]
  425.             node1=router>>16
  426.             node2=router&0xFFFF
  427.             f2.write("\t%d -> %d\n" % (node1,node2))
  428.         f2.write("}\n")
  429.  
  430.     f.close()
  431.     f2.close()
  432.  
  433. if __name__ == "__main__":
  434.     if len(sys.argv)<2:
  435.         print("Usage: ea_mpftotext.py <files> (wildcards accepted)")
  436.         sys.exit()
  437.  
  438.     for arg in sys.argv[1:]:
  439.         files=glob.glob(arg)
  440.  
  441.         for fname in files:
  442.             if not fname.upper().endswith(".MPF"):
  443.                 continue
  444.  
  445.             if not os.path.isfile(fname):
  446.                 continue
  447.  
  448.             convert(fname)
  449.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement