Skip to content

Instantly share code, notes, and snippets.

@dogtopus
Created April 3, 2021 05:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dogtopus/b2598a5c2adaa4c34ad19d7927795c17 to your computer and use it in GitHub Desktop.
Save dogtopus/b2598a5c2adaa4c34ad19d7927795c17 to your computer and use it in GitHub Desktop.
Old Taiko no Tatsujin iOS song pack tool
#!/usr/bin/env python2
import yaml
import struct
import os
SUFFIX = (
'.m4a',
'_e.sht',
'_n.sht',
'_h.sht',
'_m.sht',
'.ipk',
'.lm'
)
ALTFN_KEY = (
'sound',
'easy',
'normal',
'hard',
'oni',
'texture',
'animation'
)
GENRES = (
'jpop',
'anime',
'variety',
'classic',
'original',
'download',
'game',
'folk',
'vocaloid'
)
def dat_unpack(datfile, dest_dir):
song_id = os.path.basename(datfile).split('.')[0]
datinfo = {'level':[0, 0, 0, 0], 'song_id':song_id}
fd_dat = open(datfile, 'rb')
(datinfo['version'],
datinfo['genre'],
datinfo['u1'],
datinfo['level'][0],
datinfo['level'][1],
datinfo['level'][2],
datinfo['level'][3]) = struct.unpack('<I2H4b', fd_dat.read(12))
offsets = struct.unpack('<16I4x', fd_dat.read(68))
fd_dat.seek(offsets[0])
datinfo['song_name'] = unicode(fd_dat.read(offsets[1] - 1).decode('utf8'))
for i in range(2, len(offsets), 2):
if offsets[i+1] != 0:
fd_subfile = open('%s/%s%s' % (dest_dir, song_id, SUFFIX[i/2-1]), 'wb')
fd_dat.seek(offsets[i])
fd_subfile.write(fd_dat.read((offsets[i+1])))
fd_subfile.close()
if GENRES[datinfo['genre']]:
datinfo['genre'] = GENRES[datinfo['genre']]
fd_config = open('%s/config.yml' % (dest_dir), 'w')
yaml.dump(datinfo, fd_config, allow_unicode = True)
fd_config.close()
fd_dat.close()
def dat_pack(src_dir, datfile):
fd_config = open('%s/config.yml' % (src_dir), 'r')
datinfo = yaml.load(fd_config)
fd_config.close()
try:
altfn = datinfo['files']
except KeyError:
altfn = None
if type(datinfo['genre']) == str:
datinfo['genre'] = GENRES.index(datinfo['genre'])
header = ''
header += struct.pack('<I2H4b',
datinfo['version'],
datinfo['genre'],
datinfo['u1'],
datinfo['level'][0],
datinfo['level'][1],
datinfo['level'][2],
datinfo['level'][3])
offsets = []
offset = 80
sn = datinfo['song_name'].encode('utf-8') + "\0"
sn_len = len(sn)
offsets.append(offset)
offsets.append(sn_len)
offset += sn_len
if altfn:
flist = []#altfn[i] for i in ALTFN_KEY]
for i in ALTFN_KEY:
try:
flist.append(altfn[i])
except KeyError:
flist.append(None)
else:
flist = [("%s%s" % (datinfo['song_id'], i)) for i in SUFFIX]
fdlist = []
for fn in flist:
try:
if fn:
f_len = os.path.getsize("%s/%s" % (src_dir, fn))
fdlist.append(open("%s/%s" % (src_dir, fn), 'rb'))
else:
f_len = 0
fdlist.append(None)
except:
print "Cannot read %s, skipping" % (fn)
f_len = 0
fdlist.append(None)
offsets.append(offset)
offsets.append(f_len)
offset += f_len
header += struct.pack('<16I4x', *offsets)
fd_dat = open(datfile, 'wb')
fd_dat.write(header)
fd_dat.write(sn)
for fd in fdlist:
if fd:
for chunk in iter(lambda: fd.read(65535), ''):
fd_dat.write(chunk)
fd.close()
fd_dat.close()
if __name__ == '__main__':
import sys
try:
p, s, d = sys.argv[1:4]
except:
p = ''
if p == '-e':
dat_unpack(s, d)
elif p == '-b':
dat_pack(s, d)
else:
print 'Usage: datutil [-e|-b] <src> <dest>'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment