BLACKED
This commit is contained in:
parent
03e51318b0
commit
b6c3c6a454
10 changed files with 819 additions and 654 deletions
69
adx/adx.py
69
adx/adx.py
|
|
@ -5,43 +5,46 @@ import traceback
|
|||
|
||||
from .adx_parser import adx_file
|
||||
|
||||
|
||||
def extract_loop_data_from_dir(dir_in, fout):
|
||||
if fout is None:
|
||||
fout = "BgmLoop.json"
|
||||
files = glob.glob(os.path.join(dir_in, "**/*.adx"), recursive=True)
|
||||
if len(files) == 0:
|
||||
raise FileNotFoundError("No valid files found in directory: " + dir_in)
|
||||
extract_loop_data_from_files(files, fout)
|
||||
if fout is None:
|
||||
fout = "BgmLoop.json"
|
||||
files = glob.glob(os.path.join(dir_in, "**/*.adx"), recursive=True)
|
||||
if len(files) == 0:
|
||||
raise FileNotFoundError("No valid files found in directory: " + dir_in)
|
||||
extract_loop_data_from_files(files, fout)
|
||||
|
||||
|
||||
def extract_loop_data_from_files(files_in, fout):
|
||||
if not files_in:
|
||||
raise FileNotFoundError("No input files found")
|
||||
collect = {}
|
||||
for x in files_in:
|
||||
res = extract_loop_data_from_file(x)
|
||||
if res is not None:
|
||||
collect[os.path.splitext(os.path.basename(x))[0]] = res
|
||||
with open(fout, 'w') as out:
|
||||
json.dump(collect, out, ensure_ascii=False, indent="\t", sort_keys=True)
|
||||
if not files_in:
|
||||
raise FileNotFoundError("No input files found")
|
||||
collect = {}
|
||||
for x in files_in:
|
||||
res = extract_loop_data_from_file(x)
|
||||
if res is not None:
|
||||
collect[os.path.splitext(os.path.basename(x))[0]] = res
|
||||
with open(fout, "w") as out:
|
||||
json.dump(collect, out, ensure_ascii=False, indent="\t", sort_keys=True)
|
||||
|
||||
|
||||
def extract_loop_data_from_file(file_in, fout=None):
|
||||
if not file_in.endswith(".adx"):
|
||||
raise ValueError("Input file not .adx")
|
||||
if not file_in.endswith(".adx"):
|
||||
raise ValueError("Input file not .adx")
|
||||
|
||||
try:
|
||||
with open(file_in, 'rb') as x:
|
||||
data = x.read(64)
|
||||
ADX = adx_file(data)
|
||||
if ADX.l_exists and ADX.is_valid:
|
||||
res = ADX.parse_loop_data()
|
||||
else:
|
||||
res = None
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
print("Error processing file: " + file_in)
|
||||
return None
|
||||
try:
|
||||
with open(file_in, "rb") as x:
|
||||
data = x.read(64)
|
||||
ADX = adx_file(data)
|
||||
if ADX.l_exists and ADX.is_valid:
|
||||
res = ADX.parse_loop_data()
|
||||
else:
|
||||
res = None
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
print("Error processing file: " + file_in)
|
||||
return None
|
||||
|
||||
if fout is not None and res is not None:
|
||||
with open(fout, 'w') as out:
|
||||
json.dump(res, out, ensure_ascii=False, indent="\t", sort_keys=True)
|
||||
return res
|
||||
if fout is not None and res is not None:
|
||||
with open(fout, "w") as out:
|
||||
json.dump(res, out, ensure_ascii=False, indent="\t", sort_keys=True)
|
||||
return res
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from math import modf #fuck me rounding is hard
|
||||
from math import modf # fuck me rounding is hard
|
||||
|
||||
# header map
|
||||
# https://wiki.multimedia.cx/index.php/CRI_ADX_file
|
||||
|
|
@ -13,16 +13,16 @@ DATA_OFF_MIN = 0x38
|
|||
|
||||
FORMAT_OFF = 0x04
|
||||
FORMAT_LEN = 1
|
||||
FORMAT = 3 # always 3 for adx apparently
|
||||
FORMAT = 3 # always 3 for adx apparently
|
||||
|
||||
LOOP_TYPE_OFF = 0x12
|
||||
LOOP_TYPE_LEN = 1
|
||||
LOOP_TYPE_SUP = [4] # supported loop styles
|
||||
LOOP_TYPE_SUP = [4] # supported loop styles
|
||||
|
||||
SRATE_OFF = 0x08
|
||||
SRATE_LEN = 4
|
||||
|
||||
SCOUNT_OFF = 0x0c
|
||||
SCOUNT_OFF = 0x0C
|
||||
SCOUNT_LEN = 4
|
||||
|
||||
CRYPT_OFF = 0x13
|
||||
|
|
@ -38,82 +38,90 @@ LOOP4_END_OFF = 0x30
|
|||
LOOP4_END_LEN = 4
|
||||
|
||||
|
||||
#class independent functions
|
||||
# class independent functions
|
||||
|
||||
|
||||
def dumb_round(number):
|
||||
dec = modf(number)[0]
|
||||
if (dec <= 0.5):
|
||||
return int(number)
|
||||
else:
|
||||
return int(number+1)
|
||||
dec = modf(number)[0]
|
||||
if dec <= 0.5:
|
||||
return int(number)
|
||||
else:
|
||||
return int(number + 1)
|
||||
|
||||
|
||||
class adx_file(object):
|
||||
magic = 0
|
||||
form = 0
|
||||
l_style = 0
|
||||
encrypted = 0
|
||||
sam_rate = 0
|
||||
sam_count = 0
|
||||
l_flag = 0
|
||||
l_start = 0
|
||||
l_end = 0
|
||||
l_exists = 0
|
||||
d_offset = 0
|
||||
is_valid = 0
|
||||
magic = 0
|
||||
form = 0
|
||||
l_style = 0
|
||||
encrypted = 0
|
||||
sam_rate = 0
|
||||
sam_count = 0
|
||||
l_flag = 0
|
||||
l_start = 0
|
||||
l_end = 0
|
||||
l_exists = 0
|
||||
d_offset = 0
|
||||
is_valid = 0
|
||||
|
||||
data = None
|
||||
data = None
|
||||
|
||||
def __init__(self, data):
|
||||
# first, validate
|
||||
self.data = data
|
||||
self.magic = self.get_val(MAGIC_OFF, MAGIC_LEN)
|
||||
self.form = self.get_val(FORMAT_OFF, FORMAT_LEN)
|
||||
self.l_style = self.get_val(LOOP_TYPE_OFF, LOOP_TYPE_LEN)
|
||||
self.encrypted = self.get_val(CRYPT_OFF, CRYPT_LEN)
|
||||
self.d_offset = self.get_val(DATA_OFF_OFF, DATA_OFF_LEN)
|
||||
if self.d_offset < DATA_OFF_MIN:
|
||||
return None
|
||||
self.l_exists = 1
|
||||
# now load things for math
|
||||
self.sam_rate = self.get_val(SRATE_OFF, SRATE_LEN)
|
||||
self.sam_count = self.get_val(SCOUNT_OFF, SCOUNT_LEN)
|
||||
self.validate()
|
||||
def __init__(self, data):
|
||||
# first, validate
|
||||
self.data = data
|
||||
self.magic = self.get_val(MAGIC_OFF, MAGIC_LEN)
|
||||
self.form = self.get_val(FORMAT_OFF, FORMAT_LEN)
|
||||
self.l_style = self.get_val(LOOP_TYPE_OFF, LOOP_TYPE_LEN)
|
||||
self.encrypted = self.get_val(CRYPT_OFF, CRYPT_LEN)
|
||||
self.d_offset = self.get_val(DATA_OFF_OFF, DATA_OFF_LEN)
|
||||
if self.d_offset < DATA_OFF_MIN:
|
||||
return None
|
||||
self.l_exists = 1
|
||||
# now load things for math
|
||||
self.sam_rate = self.get_val(SRATE_OFF, SRATE_LEN)
|
||||
self.sam_count = self.get_val(SCOUNT_OFF, SCOUNT_LEN)
|
||||
self.validate()
|
||||
|
||||
def get_val(self, offset, length):
|
||||
return int.from_bytes(self.data[offset:offset+length], byteorder='big', signed=False)
|
||||
def get_val(self, offset, length):
|
||||
return int.from_bytes(
|
||||
self.data[offset : offset + length], byteorder="big", signed=False
|
||||
)
|
||||
|
||||
def validate(self):
|
||||
if self.magic != MAGIC:
|
||||
raise ValueError("Invalid ADX File")
|
||||
if self.form != FORMAT:
|
||||
raise ValueError("Invalid ADX File")
|
||||
if self.encrypted:
|
||||
raise NotImplementedError("Encryption Not Supported")
|
||||
self.is_valid = 1
|
||||
def validate(self):
|
||||
if self.magic != MAGIC:
|
||||
raise ValueError("Invalid ADX File")
|
||||
if self.form != FORMAT:
|
||||
raise ValueError("Invalid ADX File")
|
||||
if self.encrypted:
|
||||
raise NotImplementedError("Encryption Not Supported")
|
||||
self.is_valid = 1
|
||||
|
||||
def parse_loop_data(self):
|
||||
if self.l_style == 4:
|
||||
self.l_flag = self.get_val(LOOP4_FLAG_OFF, LOOP4_FLAG_LEN)
|
||||
self.l_start = self.get_val(LOOP4_START_OFF, LOOP4_START_LEN)
|
||||
self.l_end = self.get_val(LOOP4_END_OFF, LOOP4_END_LEN)
|
||||
if not self.l_flag:
|
||||
return None
|
||||
if self.l_start == 0 and self.l_end == self.sam_count:
|
||||
return None
|
||||
if self.l_start > self.sam_count or self.l_end > self.sam_count:
|
||||
raise ValueError("Invalid Loop Data")
|
||||
return None
|
||||
if not self.l_style in LOOP_TYPE_SUP:
|
||||
raise NotImplementedError("Loop Style {} Not Implemented".format(str(self.l_style)))
|
||||
return None
|
||||
ret = {}
|
||||
ret['duration'] = self.sam_count / self.sam_rate
|
||||
ret['loop_start'] = {}
|
||||
ret['loop_start']['seconds'] = self.l_start / self.sam_rate
|
||||
ret['loop_start']['samples_native'] = self.l_start
|
||||
ret['loop_start']['samples_48k'] = dumb_round(self.l_start / self.sam_rate * 48000)
|
||||
ret['loop_end'] = {}
|
||||
ret['loop_end']['seconds'] = self.l_end / self.sam_rate
|
||||
ret['loop_end']['samples_native'] = self.l_end
|
||||
ret['loop_end']['samples_48k'] = dumb_round(self.l_end / self.sam_rate * 48000)
|
||||
return ret
|
||||
def parse_loop_data(self):
|
||||
if self.l_style == 4:
|
||||
self.l_flag = self.get_val(LOOP4_FLAG_OFF, LOOP4_FLAG_LEN)
|
||||
self.l_start = self.get_val(LOOP4_START_OFF, LOOP4_START_LEN)
|
||||
self.l_end = self.get_val(LOOP4_END_OFF, LOOP4_END_LEN)
|
||||
if not self.l_flag:
|
||||
return None
|
||||
if self.l_start == 0 and self.l_end == self.sam_count:
|
||||
return None
|
||||
if self.l_start > self.sam_count or self.l_end > self.sam_count:
|
||||
raise ValueError("Invalid Loop Data")
|
||||
return None
|
||||
if not self.l_style in LOOP_TYPE_SUP:
|
||||
raise NotImplementedError(
|
||||
"Loop Style {} Not Implemented".format(str(self.l_style))
|
||||
)
|
||||
return None
|
||||
ret = {}
|
||||
ret["duration"] = self.sam_count / self.sam_rate
|
||||
ret["loop_start"] = {}
|
||||
ret["loop_start"]["seconds"] = self.l_start / self.sam_rate
|
||||
ret["loop_start"]["samples_native"] = self.l_start
|
||||
ret["loop_start"]["samples_48k"] = dumb_round(
|
||||
self.l_start / self.sam_rate * 48000
|
||||
)
|
||||
ret["loop_end"] = {}
|
||||
ret["loop_end"]["seconds"] = self.l_end / self.sam_rate
|
||||
ret["loop_end"]["samples_native"] = self.l_end
|
||||
ret["loop_end"]["samples_48k"] = dumb_round(self.l_end / self.sam_rate * 48000)
|
||||
return ret
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue