#!/usr/bin/env python3
# DX7IIFD .Ixx fileformat
# Offset    Size    Data
# 0x0000    1       0xAA
# 0x0001    3720    [0x00, 0x00, 0xff, 0xff] * 930
# 0x0e89    2       0x00, 0x00
# 0x0e8b    85      SYSTEM(0-19) + SYSTEM(37) + SYSTEM(38-101)
# 0x0ee0    256     MCT User 1
# 0x0fe0    256     MCT User 2
# 0x10e0    1632    PMEM p01-p32
# 0x1740    288     AMEM(26-34) v01-v32
# 0x1860    288     AMEM(26-34) v33-v64
# 0x1980    832     AMEM(0-25) v01-v32
# 0x1cc0    832     AMEM(0-25) v33-v64
# 0x2000    4096    VMEM v01-v32
# 0x3000    4096    VMEM v33-v64
# ==============================
# 0x4000    16384   Total

import os
import sys
from glob import glob
from argparse import ArgumentParser
from array import array
try:
    range = xrange
except NameError:
    pass


VERSION = "20191023"

HEAD = [ 0xaa ] + 930*[0x00, 0x00, 0xff, 0xff] + [0x00, 0x00] 

SYSTEM = [0, 1, 0, 0, 1, 12, 13, 14, 15, 0, 1, 1, 0, 0, 0, 1, 0, 2, 3, 2, 64]
for i in range(64):
    SYSTEM.append(i)

MCT1 = [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x13, 0x01, 0x69, 0x02, 0x3f, 0x03, 0x14, 0x03, 0x6b, 0x04, 0x41,
        0x05, 0x17, 0x05, 0x6e, 0x06, 0x44, 0x07, 0x1a, 0x07, 0x71, 0x08, 0x46, 0x09, 0x1c, 0x09, 0x73, 
        0x0a, 0x48, 0x0b, 0x1e, 0x0b, 0x74, 0x0c, 0x4a, 0x0d, 0x1f, 0x0d, 0x76, 0x0e, 0x4b, 0x0f, 0x20, 
        0x0f, 0x77, 0x10, 0x4c, 0x11, 0x22, 0x11, 0x78, 0x12, 0x4d, 0x13, 0x23, 0x13, 0x7a, 0x14, 0x4f, 
        0x15, 0x24, 0x15, 0x7b, 0x16, 0x50, 0x17, 0x25, 0x17, 0x7c, 0x18, 0x51, 0x19, 0x27, 0x19, 0x7e, 
        0x1a, 0x52, 0x1b, 0x28, 0x1b, 0x7e, 0x1c, 0x54, 0x1d, 0x29, 0x1d, 0x7e, 0x1e, 0x54, 0x1f, 0x2b, 
        0x1f, 0x7e, 0x20, 0x54, 0x21, 0x2a, 0x22, 0x01, 0x22, 0x54, 0x23, 0x2a, 0x24, 0x00, 0x24, 0x56, 
        0x25, 0x2a, 0x25, 0x7f, 0x26, 0x56, 0x27, 0x2c, 0x28, 0x00, 0x28, 0x55, 0x29, 0x2c, 0x2a, 0x02, 
        0x2a, 0x56, 0x2b, 0x2c, 0x2c, 0x01, 0x2c, 0x58, 0x2d, 0x2b, 0x2e, 0x00, 0x2e, 0x57, 0x2f, 0x2e, 
        0x30, 0x02, 0x30, 0x57, 0x31, 0x2d, 0x32, 0x04, 0x32, 0x57, 0x33, 0x2d, 0x34, 0x02, 0x34, 0x59, 
        0x35, 0x2d, 0x36, 0x02, 0x36, 0x58, 0x37, 0x2e, 0x38, 0x04, 0x38, 0x59, 0x39, 0x2f, 0x3a, 0x06, 
        0x3a, 0x5a, 0x3b, 0x2f, 0x3c, 0x06, 0x3c, 0x5b, 0x3d, 0x31, 0x3e, 0x05, 0x3e, 0x5c, 0x3f, 0x32, 
        0x40, 0x08, 0x40, 0x5e, 0x41, 0x32, 0x42, 0x09, 0x42, 0x5e, 0x43, 0x33, 0x44, 0x09, 0x44, 0x5f, 
        0x45, 0x34, 0x46, 0x0b, 0x46, 0x60, 0x47, 0x35, 0x48, 0x0b, 0x48, 0x62, 0x49, 0x36, 0x4a, 0x0d, 
        0x4a, 0x62, 0x4b, 0x37, 0x4c, 0x0e, 0x4c, 0x63, 0x4d, 0x39, 0x4e, 0x0f, 0x4e, 0x65, 0x4f, 0x3b, 
        0x50, 0x12, 0x50, 0x68, 0x51, 0x3c, 0x52, 0x13, 0x52, 0x69, 0x53, 0x3f, 0x54, 0x17]

MCT2 = [ 0x07, 0x2a, 0x00, 0x00, 0x00, 0x55, 0x01, 0x2a, 0x02, 0x00, 0x02, 0x55, 0x03, 0x2a, 0x04, 0x00, 0x04, 0x55,
        0x05, 0x2a, 0x06, 0x00, 0x06, 0x55, 0x07, 0x2a, 0x08, 0x00, 0x08, 0x55, 0x09, 0x2a, 0x0a, 0x00, 
        0x0a, 0x55, 0x0b, 0x2a, 0x0c, 0x00, 0x0c, 0x55, 0x0d, 0x2a, 0x0e, 0x00, 0x0e, 0x55, 0x0f, 0x2a, 
        0x10, 0x00, 0x10, 0x55, 0x11, 0x2a, 0x12, 0x00, 0x12, 0x55, 0x13, 0x2a, 0x14, 0x00, 0x14, 0x55, 
        0x15, 0x2a, 0x16, 0x00, 0x16, 0x55, 0x17, 0x2a, 0x18, 0x00, 0x18, 0x55, 0x19, 0x2a, 0x1a, 0x00, 
        0x1a, 0x55, 0x1b, 0x2a, 0x1c, 0x00, 0x1c, 0x55, 0x1d, 0x2a, 0x1e, 0x00, 0x1e, 0x55, 0x1f, 0x2a, 
        0x20, 0x00, 0x20, 0x55, 0x21, 0x2a, 0x22, 0x00, 0x22, 0x55, 0x23, 0x2a, 0x24, 0x00, 0x24, 0x55, 
        0x25, 0x2a, 0x26, 0x00, 0x26, 0x55, 0x27, 0x2a, 0x28, 0x00, 0x28, 0x55, 0x29, 0x2a, 0x2a, 0x00, 
        0x2a, 0x55, 0x2b, 0x2a, 0x2c, 0x00, 0x2c, 0x55, 0x2d, 0x2a, 0x2e, 0x00, 0x2e, 0x55, 0x2f, 0x2a, 
        0x30, 0x00, 0x30, 0x55, 0x31, 0x2a, 0x32, 0x00, 0x32, 0x55, 0x33, 0x2a, 0x34, 0x00, 0x34, 0x55, 
        0x35, 0x2a, 0x36, 0x00, 0x36, 0x55, 0x37, 0x2a, 0x38, 0x00, 0x38, 0x55, 0x39, 0x2a, 0x3a, 0x00, 
        0x3a, 0x55, 0x3b, 0x2a, 0x3c, 0x00, 0x3c, 0x55, 0x3d, 0x2a, 0x3e, 0x00, 0x3e, 0x55, 0x3f, 0x2a, 
        0x40, 0x00, 0x40, 0x55, 0x41, 0x2a, 0x42, 0x00, 0x42, 0x55, 0x43, 0x2a, 0x44, 0x00, 0x44, 0x55, 
        0x45, 0x2a, 0x46, 0x00, 0x46, 0x55, 0x47, 0x2a, 0x48, 0x00, 0x48, 0x55, 0x49, 0x2a, 0x4a, 0x00, 
        0x4a, 0x55, 0x4b, 0x2a, 0x4c, 0x00, 0x4c, 0x55, 0x4d, 0x2a, 0x4e, 0x00, 0x4e, 0x55, 0x4f, 0x2a, 
        0x50, 0x00, 0x50, 0x55, 0x51, 0x2a, 0x52, 0x00, 0x52, 0x55, 0x53, 0x2a, 0x54, 0x00]

PMEM = [1, 0, 0, 0, 0, 0, 0, 60, 0, 3, 
        1, 3, 0, 24, 24, 50, 99, 0, 0, 0, 
        1, 0, 0,
        99, 99, 99, 99, 50, 50, 50, 50]
for k in "INIT PERF           ":
    PMEM.append(ord(k))

AMEM1 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
        0x00, 0x00, 0x00, 0x32, 0x00, 0x00] 
AMEM2 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

VMEM = [0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x27, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x02,
        0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x27, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 
        0x02, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x27, 0x00, 0x00, 0x00, 0x38, 0x00, 
        0x00, 0x02, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x27, 0x00, 0x00, 0x00, 0x38, 
        0x00, 0x00, 0x02, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x27, 0x00, 0x00, 0x00, 
        0x38, 0x00, 0x00, 0x02, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x27, 0x00, 0x00, 
        0x00, 0x38, 0x00, 0x63, 0x02, 0x00, 0x63, 0x63, 0x63, 0x63, 0x32, 0x32, 0x32, 0x32, 0x00, 0x08, 
        0x23, 0x00, 0x00, 0x00, 0x31, 0x18, 0x49, 0x4e, 0x49, 0x54, 0x20, 0x56, 0x4f, 0x49, 0x43, 0x45]

#inititialize FD content
FD = HEAD + SYSTEM + MCT1 + MCT2 + 32*PMEM + 64*AMEM2 + 64*AMEM1 + 64*VMEM

def syx2fd(syx):
    vmemcounter = 0
    amemcounter = 0
    mctcounter = 0
    for i in range(len(syx)-16):
        if syx[i:i+2] == [0xf0, 0x43]:
            if syx[i+3:i+7] == [0x19, 0x4d, 0x00, 0xf7]:
                amemcounter = 0
                vmemcounter = 0
            if syx[i+3:i+7] == [0x19, 0x4d, 0x01, 0xf7]:
                amemcounter = 1
                vmemcounter = 1
            
            if syx[i+3:i+6] == [0x06, 0x08, 0x60]:
                if amemcounter == 0:
                    print("AMEM1")
                    FD[0x1980:0x1980+832] = syx[i+6:i+6+832]
                    FD[0x1740:0x1740+288] = syx[i+6+832:i+6+832+288]
                    amemcounter = 1
                elif amemcounter == 1:
                    print("AMEM2")
                    FD[0x1cc0:0x1cc0+832] = syx[i+6:i+6+832]
                    FD[0x1860:0x1860+288] = syx[i+6+832:i+6+832+288]
                    amemcounter = 0
            elif syx[i+3:i+6] == [0x09, 0x20, 0x00]:
                if vmemcounter == 0:
                    print("VMEM1")
                    FD[0x2000:0x3000] = syx[i+6:i+6+4096]
                    vmemcounter = 1
                elif vmemcounter == 1:
                    print("VMEM2")
                    FD[0x3000:0x4000] = syx[i+6:i+6+4096]
                    vmemcounter = 0
            elif syx[i+3] == 0x7e:
                LM = ""
                for k in range(6,16):
                    LM += chr(syx[i+k])
                if LM == "LM  8973S ":
                    print("SYSTEM")
                    FD[0xe8b:0xee0] = syx[i+16:i+16+85]
                elif LM == "LM  8973PM":
                    print("PMEM")
                    FD[0x10e0:0x1740] = syx[i+16:i+16+1632]
                elif LM == "LM  MCRYM"+chr(0):
                    print("MCT1")
                    FD[0xee0:0xfe0] = syx[i+16:i+16+256]
                elif LM == "LM  MCRYM"+chr(1):
                    print("MCT2")
                    FD[0xfe0:0x10e0] = syx[i+16:i+16+256]
    
    # set Fractional Scaling Mode = Normal => disable cartridge dependency
    for i in range(32):
        FD[0x1980+26*i] = 0 #Scaling Mode = Normal
        FD[0x1cc0+26*i] = 0 #Scaling Mode = Normal

    return FD

if __name__ == '__main__':
    parser = ArgumentParser(description = "Convert DX7/DX7II .syx files(s) to .I## floppy file", epilog="http://dxconvert.martintarenskeen.nl")  
    parser.add_argument('-v', '--version', action = 'version', version = VERSION)
    parser.add_argument('-o', '--outfile', default="OUT.I01", help = "Save as OUTFILE (*.Ixx)")
    parser.add_argument('infile', nargs = '+', help = 'Read data from INFILE(s)')
    args = parser.parse_args()

    infiles = args.infile
    outfile = args.outfile
    outfile_ = os.path.splitext(outfile)[0]
    ext = os.path.splitext(outfile)[1]
    if ext == "":
        ext = ".I01"
    n = 0
    while os.path.exists(outfile):
        n += 1
        ext = ".I{:02}".format(n)
        outfile = outfile_ + ext
    
    syx = array('B')
    print("Reading File(s): ")
    for infilez in infiles:
        for infile in glob(infilez):
            print(infile)
            size = os.path.getsize(infile)
            with open(infile, 'rb') as f:
                syx.fromfile(f, size)

    fd = syx2fd(syx.tolist())
    FD = array("B", fd)

    with open(outfile, "wb") as f:
        FD.tofile(f)
    print("Converted to: {}".format(outfile))
    sys.exit(0)

