mirror of
https://github.com/cainan-c/TaikoPythonTools.git
synced 2024-11-30 18:24:33 +01:00
272 lines
10 KiB
Python
272 lines
10 KiB
Python
import sys
|
|
import os
|
|
import struct
|
|
import random
|
|
|
|
def generate_random_uint16_hex():
|
|
return format(random.randint(0, 65535), '04X')
|
|
|
|
def load_template_config():
|
|
# Load template configurations from config.toml (if needed in the future)
|
|
# This function can be expanded to load more template configurations if necessary
|
|
# For now, we don't need to use this function directly for selecting templates
|
|
return {}
|
|
|
|
def select_template_name(game, output_file):
|
|
# Determine the appropriate template name based on the game and the length of the output file name
|
|
base_filename = os.path.splitext(output_file)[0]
|
|
length = len(base_filename)
|
|
|
|
if game == "nijiiro":
|
|
if length == 8:
|
|
return "song_ABC"
|
|
elif length == 9:
|
|
return "song_ABCD"
|
|
elif length == 10:
|
|
return "song_ABCDE"
|
|
elif length == 11:
|
|
return "song_ABCDEF"
|
|
elif length == 12:
|
|
return "song_ABCDEFG"
|
|
elif length == 13:
|
|
return "song_ABCDEFGH"
|
|
elif game == "ps4":
|
|
if length == 8:
|
|
return "song_ABC"
|
|
elif length == 9:
|
|
return "song_ABCD"
|
|
elif length == 10:
|
|
return "song_ABCDE"
|
|
elif length == 11:
|
|
return "song_ABCDEF"
|
|
elif game == "ns1":
|
|
if length == 8:
|
|
return "song_ABC"
|
|
elif length == 9:
|
|
return "song_ABCD"
|
|
elif length == 10:
|
|
return "song_ABCDE"
|
|
elif length == 11:
|
|
return "song_ABCDEF"
|
|
pass
|
|
elif game == "wiiu3":
|
|
if length == 8:
|
|
return "song_ABC"
|
|
elif length == 9:
|
|
return "song_ABCD"
|
|
elif length == 10:
|
|
return "song_ABCDE"
|
|
elif length == 11:
|
|
return "song_ABCDEF"
|
|
pass
|
|
|
|
raise ValueError("Unsupported game or output file name length.")
|
|
|
|
def modify_nus3bank_template(game, template_name, audio_file, preview_point, output_file):
|
|
# Define game-specific template configurations
|
|
game_templates = {
|
|
"nijiiro": {
|
|
"template_folder": "nijiiro",
|
|
"templates": {
|
|
"song_ABC": {
|
|
"unique_id_offset": 176,
|
|
"audio_size_offsets": [76, 1568, 1852],
|
|
"preview_point_offset": 1724,
|
|
"song_placeholder": "song_ABC",
|
|
"template_file": "song_ABC.nus3bank"
|
|
},
|
|
"song_ABCD": {
|
|
"unique_id_offset": 176,
|
|
"audio_size_offsets": [76, 1568, 1852],
|
|
"preview_point_offset": 1724,
|
|
"song_placeholder": "song_ABCD",
|
|
"template_file": "song_ABCD.nus3bank"
|
|
},
|
|
"song_ABCDE": {
|
|
"unique_id_offset": 176,
|
|
"audio_size_offsets": [76, 1568, 1852],
|
|
"preview_point_offset": 1724,
|
|
"song_placeholder": "song_ABCDE",
|
|
"template_file": "song_ABCDE.nus3bank"
|
|
},
|
|
"song_ABCDEF": {
|
|
"unique_id_offset": 180,
|
|
"audio_size_offsets": [76, 1576, 1868],
|
|
"preview_point_offset": 1732,
|
|
"song_placeholder": "song_ABCDEF",
|
|
"template_file": "song_ABCDEF.nus3bank"
|
|
},
|
|
"song_ABCDEFG": {
|
|
"unique_id_offset": 180,
|
|
"audio_size_offsets": [76, 1672, 1964],
|
|
"preview_point_offset": 1824,
|
|
"song_placeholder": "song_ABCDEFG",
|
|
"template_file": "song_ABCDEFG.nus3bank"
|
|
},
|
|
"song_ABCDEFGH": {
|
|
"unique_id_offset": 180,
|
|
"audio_size_offsets": [76, 1576, 1868],
|
|
"preview_point_offset": 1732,
|
|
"song_placeholder": "song_ABCDEFGH",
|
|
"template_file": "song_ABCDEFGH.nus3bank"
|
|
},
|
|
}
|
|
},
|
|
"ns1": {
|
|
"template_folder": "ns1",
|
|
"templates": {
|
|
"song_ABC": {
|
|
"audio_size_offsets": [76, 5200, 5420],
|
|
"preview_point_offset": 5324,
|
|
"song_placeholder": "SONG_ABC",
|
|
"template_file": "SONG_ABC.nus3bank"
|
|
},
|
|
"song_ABCD": {
|
|
"audio_size_offsets": [76, 5200, 5420],
|
|
"preview_point_offset": 5324,
|
|
"song_placeholder": "SONG_ABCD",
|
|
"template_file": "SONG_ABCD.nus3bank"
|
|
},
|
|
"song_ABCDE": {
|
|
"audio_size_offsets": [76, 5200, 5404],
|
|
"preview_point_offset": 5320,
|
|
"song_placeholder": "SONG_ABCDE",
|
|
"template_file": "SONG_ABCDE.nus3bank"
|
|
},
|
|
"song_ABCDEF": {
|
|
"audio_size_offsets": [76, 5208, 5420],
|
|
"preview_point_offset": 5324,
|
|
"song_placeholder": "SONG_ABCDEF",
|
|
"template_file": "SONG_ABCDEF.nus3bank"
|
|
}
|
|
}
|
|
},
|
|
"ps4": {
|
|
"template_folder": "ps4",
|
|
"templates": {
|
|
"song_ABC": {
|
|
"audio_size_offsets": [76, 3220, 3436],
|
|
"preview_point_offset": 3344,
|
|
"song_placeholder": "SONG_ABC",
|
|
"template_file": "SONG_ABC.nus3bank"
|
|
},
|
|
"song_ABCD": {
|
|
"audio_size_offsets": [76, 3220, 3436],
|
|
"preview_point_offset": 3344,
|
|
"song_placeholder": "SONG_ABCD",
|
|
"template_file": "SONG_ABCD.nus3bank"
|
|
},
|
|
"song_ABCDE": {
|
|
"audio_size_offsets": [76, 3220, 3436],
|
|
"preview_point_offset": 3344,
|
|
"song_placeholder": "SONG_ABCDE",
|
|
"template_file": "SONG_ABCDE.nus3bank"
|
|
},
|
|
"song_ABCDEF": {
|
|
"audio_size_offsets": [76, 3228, 3452],
|
|
"preview_point_offset": 3352,
|
|
"song_placeholder": "SONG_ABCDEF",
|
|
"template_file": "SONG_ABCDEF.nus3bank"
|
|
}
|
|
}
|
|
},
|
|
"wiiu3": {
|
|
"template_folder": "wiiu3",
|
|
"templates": {
|
|
"song_ABC": {
|
|
"audio_size_offsets": [76, 3420, 3612],
|
|
"preview_point_offset": 3540,
|
|
"song_placeholder": "SONG_ABC",
|
|
"template_file": "SONG_ABC.nus3bank"
|
|
},
|
|
"song_ABCD": {
|
|
"audio_size_offsets": [76, 3420, 3612],
|
|
"preview_point_offset": 3540,
|
|
"song_placeholder": "SONG_ABCD",
|
|
"template_file": "SONG_ABCD.nus3bank"
|
|
},
|
|
"song_ABCDE": {
|
|
"audio_size_offsets": [76, 3420, 3612],
|
|
"preview_point_offset": 3540,
|
|
"song_placeholder": "SONG_ABCDE",
|
|
"template_file": "SONG_ABCDE.nus3bank"
|
|
},
|
|
"song_ABCDEF": {
|
|
"audio_size_offsets": [76, 3428, 3612],
|
|
"preview_point_offset": 3548,
|
|
"song_placeholder": "SONG_ABCDEF",
|
|
"template_file": "SONG_ABCDEF.nus3bank"
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
if game not in game_templates:
|
|
raise ValueError("Unsupported game.")
|
|
|
|
templates_config = game_templates[game]
|
|
|
|
if template_name not in templates_config["templates"]:
|
|
raise ValueError(f"Unsupported template for {game}.")
|
|
|
|
template_config = templates_config["templates"][template_name]
|
|
template_folder = templates_config["template_folder"]
|
|
|
|
# Read template nus3bank file from the specified game's template folder
|
|
template_file = os.path.join("templates", template_folder, template_config['template_file'])
|
|
with open(template_file, 'rb') as f:
|
|
template_data = bytearray(f.read())
|
|
|
|
# Set unique ID if it exists in the template configuration
|
|
if 'unique_id_offset' in template_config:
|
|
# Generate random UInt16 hex for unique ID
|
|
unique_id_hex = generate_random_uint16_hex()
|
|
# Set unique ID in the template data at the specified offset
|
|
template_data[template_config['unique_id_offset']:template_config['unique_id_offset']+2] = bytes.fromhex(unique_id_hex)
|
|
|
|
# Get size of the audio file in bytes
|
|
audio_size = os.path.getsize(audio_file)
|
|
|
|
# Convert audio size to UInt32 bytes in little-endian format
|
|
size_bytes = audio_size.to_bytes(4, 'little')
|
|
|
|
# Set audio size in the template data at the specified offsets
|
|
for offset in template_config['audio_size_offsets']:
|
|
template_data[offset:offset+4] = size_bytes
|
|
|
|
# Convert preview point (milliseconds) to UInt32 bytes in little-endian format
|
|
preview_point_ms = int(preview_point)
|
|
preview_point_bytes = preview_point_ms.to_bytes(4, 'little')
|
|
|
|
# Set preview point in the template data at the specified offset
|
|
template_data[template_config['preview_point_offset']:template_config['preview_point_offset']+4] = preview_point_bytes
|
|
|
|
# Replace song name placeholder with the output file name in bytes
|
|
output_file_bytes = output_file.encode('utf-8')
|
|
template_data = template_data.replace(template_config['song_placeholder'].encode('utf-8'), output_file_bytes.replace(b'.nus3bank', b''))
|
|
|
|
# Append the audio file contents to the modified template data
|
|
with open(audio_file, 'rb') as audio:
|
|
template_data += audio.read()
|
|
|
|
# Write the modified data to the output file
|
|
with open(output_file, 'wb') as out:
|
|
out.write(template_data)
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) != 5:
|
|
print("Usage: nus3.py <game> <audio_file> <preview_point> <output_file>")
|
|
sys.exit(1)
|
|
|
|
game = sys.argv[1]
|
|
audio_file = sys.argv[2]
|
|
preview_point = sys.argv[3]
|
|
output_file = sys.argv[4]
|
|
|
|
try:
|
|
template_name = select_template_name(game, output_file)
|
|
modify_nus3bank_template(game, template_name, audio_file, preview_point, output_file)
|
|
print(f"Created {output_file} successfully.")
|
|
except ValueError as e:
|
|
print(f"Error: {e}")
|
|
sys.exit(1) |