Export Hoot memory dumps to VOPM instruments
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

214 líneas
6.1KB

  1. #!/usr/bin/python3
  2. import sys, getopt
  3. def Error(*args):
  4. print(sys.argv[0]+":", *args, file=sys.stderr)
  5. sys.exit(1)
  6. if len(sys.argv) > 1:
  7. Filename = sys.argv[1]
  8. Options, Args = getopt.getopt(sys.argv[1:], "bot:")
  9. def OptionExist(opt):
  10. global Options
  11. f = list(filter(lambda x: x[0] == opt, Options))
  12. return len(f) >= 1
  13. def GetOption(opt):
  14. global Options
  15. f = list(filter(lambda x: x[0] == opt, Options))
  16. if len(f) == 0: return None
  17. else: return f[0][1]
  18. if len(Args) >= 1:
  19. Filename = Args[0]
  20. else:
  21. Error("no input file")
  22. BinMode = OptionExist("-b")
  23. DataFile = open(Filename,"r" + ("b" if BinMode else "")) if Filename != "-" else sys.stdin
  24. # MiOPMdrv sound bank Paramer Ver2002.04.22
  25. # LFO: LFRQ AMD PMD WF NFRQ
  26. # @:[Num] [Name]
  27. # CH: PAN FL CON AMS PMS SLOT NE
  28. # [OPname]: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
  29. Data = [] if not BinMode else DataFile.read()
  30. OpNames = ["M1","C1","M2","C2"]
  31. OpIdx = [0,2,1,3]
  32. if not BinMode:
  33. for line in DataFile.readlines():
  34. for byte in line.strip().split(",")[:16]:
  35. Data.append(int(byte,16))
  36. def PrintChannel(pan, fl, con, ams, pms, slot, ne):
  37. print("CH:", pan, fl, con, ams, pms, slot, ne)
  38. def PrintOp(op, ar, d1r, d2r, rr, d1l, tl, ks, mul, dt1, dt2, amsen):
  39. print(OpNames[op] + ":", ar, d1r, d2r, rr, d1l, tl, ks, mul, dt1, dt2, amsen)
  40. def GetFlCon(b):
  41. return (b & 0b00111000) >> 3, (b & 0b00000111)
  42. def GetAMSPMS(b):
  43. return (b & 0b00110000) >> 4, (b & 0b00000111)
  44. def GetDT1Mul(b):
  45. return (b & 0b01110000) >> 4, (b & 0b00001111)
  46. def GetKSAR(b):
  47. return (b & 0b11000000) >> 6, (b & 0b00011111)
  48. def GetAmsenD1R(b):
  49. return (b & 0b10000000) >> 7, (b & 0b00011111)
  50. def GetDT2D2R(b):
  51. return (b & 0b11000000) >> 6, (b & 0b00011111)
  52. def GetD1LRR(b):
  53. return (b & 0b11110000) >> 4, (b & 0b00001111)
  54. class RecordGrabber:
  55. def __init__(self, fields, recordSize, **options):
  56. self.fields = fields
  57. self.recordSize = recordSize
  58. self.instStep = 1
  59. for k, v in options:
  60. setattr(self, k, v)
  61. def __call__(self,data):
  62. f = self.fields
  63. slot = 120
  64. pan = 64
  65. ne = 0
  66. for n in range(0, len(data) // self.recordSize):
  67. ofs = n * self.recordSize
  68. print("@:%d %s" % (n, ("Ins%d" % n) if "name" not in f else
  69. f["name"](data, ofs)))
  70. print("LFO: 0 0 0 0 0") # the DRY violations will end! ...soon
  71. get = lambda s: data[ofs + f[s]] if s in f else 0
  72. fl, con = GetFlCon(get("flcon"))
  73. ams, pms = GetAMSPMS(get("amspms"))
  74. PrintChannel(pan, fl, con, ams, pms, slot, ne)
  75. for op in range(4):
  76. getOp = lambda s: data[ofs + f[s] + OpIdx[op]] if s in f else 0
  77. dt1, mul = GetDT1Mul(getOp("dt1mul"))
  78. tl = getOp("tl")
  79. ks, ar = GetKSAR(getOp("ksar"))
  80. amsen, d1r = GetAmsenD1R(getOp("amsend1r"))
  81. dt2, d2r = GetDT2D2R(getOp("dt2d2r"))
  82. d1l, rr = GetD1LRR(getOp("d1lrr"))
  83. PrintOp(op, ar, d1r, d2r, rr, d1l, tl, ks, mul, dt1, dt2, amsen)
  84. def PrintOPM(data):
  85. ne = (data[0xf] & 0b10000000) >> 7
  86. slot = 120
  87. pan = 64
  88. for i in range(8):
  89. print("@:%d Ins%d" % (i, i))
  90. print("LFO: 0 0 0 0 0") # no way to get this data... at least for now
  91. meta = data[0x20 + i : 0x3f + i : 8]
  92. fl, con = GetFlCon(meta[0])
  93. pms, ams = GetAMSPMS(meta[3])
  94. PrintChannel(pan, fl, con, ams, pms, slot, ne)
  95. for op in range(4):
  96. get = lambda x: data[x + i + OpIdx[op]*8]
  97. dt1, mul = GetDT1Mul(get(0x40))
  98. tl = get(0x60)
  99. ks, ar = GetKSAR(get(0x80))
  100. amsen, d1r = GetAmsenD1R(get(0xa0))
  101. dt2, d2r = GetDT2D2R(get(0xc0))
  102. d1l, rr = GetD1LRR(get(0xe0))
  103. PrintOp(op, ar, d1r, d2r, rr, d1l, tl, ks, mul, dt1, dt2, amsen)
  104. print()
  105. def PrintOPNBasic(data, opna = False):
  106. slot = 120
  107. pan = 64
  108. ne = 0 # either i'm blind or opn has no noise enable bit (not that i care either way)
  109. # SR in opn parlance is equivalent to D2R in opm, thanks yamaha
  110. # likewise, SL -> D1L and DR -> D1R
  111. ofs = 0x100 if opna else 0
  112. for i in range(3):
  113. n = i + (3 if opna else 0)
  114. print("@:%d Ins%d" % (n, n))
  115. print("LFO: 0 0 0 0 0") # no way to get this data... at least for now
  116. fl, con = GetFlCon(data[ofs + 0xb0 + i])
  117. ams, pms = GetAMSPMS(data[ofs + 0xb4 + i])
  118. PrintChannel(pan, fl, con, ams, pms, slot, ne)
  119. for op in range(4):
  120. get = lambda x: data[ofs + x + i + OpIdx[op]*4]
  121. dt1, mul = GetDT1Mul(get(0x30))
  122. tl = get(0x40)
  123. ks, ar = GetKSAR(get(0x50))
  124. amsen, d1r = GetAmsenD1R(get(0x60))
  125. dt2, d2r = GetDT2D2R(get(0x70))
  126. d1l, rr = GetD1LRR(get(0x80))
  127. PrintOp(op, ar, d1r, d2r, rr, d1l, tl, ks, mul, dt1, dt2, amsen)
  128. def PrintOPN(data):
  129. PrintOPNBasic(data)
  130. def PrintOPNA(data):
  131. PrintOPNBasic(data)
  132. PrintOPNBasic(data, True)
  133. TypeFuncs = {
  134. "opn": PrintOPN,
  135. "opna": PrintOPNA,
  136. "opm": PrintOPM,
  137. "raw": RecordGrabber({
  138. "flcon": 0x18,
  139. "amspms": 0x19,
  140. "dt1mul": 0x0,
  141. "tl": 0x04,
  142. "ksar": 0x08,
  143. "amsend1r": 0x0c,
  144. "dt2d2r": 0x10,
  145. "d1lrr": 0x14
  146. }, 0x20),
  147. "solfeace": RecordGrabber({
  148. "flcon": 0x00,
  149. "dt1mul": 0x02,
  150. "tl": 0x06,
  151. "ksar": 0x0a,
  152. "amsend1r": 0x0e,
  153. "dt2d2r": 0x12,
  154. "d1lrr": 0x16,
  155. "name": lambda data, ofs: data[ofs + 0x1a : ofs + 0x20].decode("shift-jis")
  156. }, 0x20)
  157. }
  158. Type = GetOption("-t")
  159. if Type==None:
  160. Error("no chip type specified")
  161. if Type not in TypeFuncs:
  162. Error(Type+":","unknown chip type")
  163. print("// Exported by hootvopm : https://git.lain.church/whut/hootvopm")
  164. print("// Chip type:",Type)
  165. TypeFuncs[Type.lower()](Data)