def get_base_audio(input_foldername, bgm_filename, chart_data, no_bgm): if no_bgm: # Find last timestamp last_timestamp = int(sorted(chart_data['timestamp'].keys(), key=lambda x: int(x))[-1]) # TODO: Find a better way to calculate the ending of the audio # Convert last timestamp into a duration and add 2 seconds in # case the final notes ring out for long duration = ((last_timestamp) / 0x12c) + 2 # Create silent audio file output_audio = pydub.AudioSegment.silent(duration=duration * 1000) else: filename = os.path.join(input_foldername, bgm_filename) filename = helper.getCaseInsensitivePath(filename) output_audio = audio.get_audio_file(filename) return output_audio
def decode_at3(input, sample_rate, channels): data = bytearray(open(input, "rb").read()) wav_header = bytearray() wav_header += bytearray("RIFF", "ascii") wav_header += int.to_bytes(len(data) + 0x3c, length=4, byteorder="little") wav_header += bytearray("WAVE", "ascii") wav_header += bytearray("fmt ", "ascii") wav_header += int.to_bytes(0x20, length=4, byteorder="little") format_id = 0x270 byte_rate = 0x4099 block_align = 0x180 bits_per_sample = 0 wav_header += int.to_bytes(format_id, length=2, byteorder="little") wav_header += int.to_bytes(channels, length=2, byteorder="little") wav_header += int.to_bytes(sample_rate, length=4, byteorder="little") wav_header += int.to_bytes(byte_rate, length=4, byteorder="little") wav_header += int.to_bytes(block_align, length=2, byteorder="little") wav_header += int.to_bytes(bits_per_sample, length=2, byteorder="little") wav_header += int.to_bytes(0x0e, length=2, byteorder="little") wav_header += int.to_bytes(0x01, length=2, byteorder="little") wav_header += int.to_bytes(0x1000, length=2, byteorder="little") wav_header += int.to_bytes(0x00, length=2, byteorder="little") wav_header += int.to_bytes(0x00, length=4, byteorder="little") wav_header += int.to_bytes(0x01, length=4, byteorder="little") wav_header += bytearray("data", "ascii") wav_header += int.to_bytes(len(data), length=4, byteorder="little") wav_header += data tmp_filename = tmpfile.mkstemp(suffix=".at3") with open(tmp_filename, "wb") as outfile: outfile.write(wav_header) sound = audio.get_audio_file(tmp_filename) tmpfile.tmpcleanup() return sound
def create_wav_from_chart(chart_data, input_foldername, sound_metadata, output_filename, bgm_filename="bgm.wav", tags=None, no_bgm=False, ext="mp3", quality="320k", volume_part=100, volume_bgm=100, volume_auto=100, ignore_auto=False): output_audio = get_base_audio(input_foldername, bgm_filename, chart_data, no_bgm) output_audio = make_silent(output_audio) if volume_bgm != 100: volume_bgm_db = percentage_to_db(volume_bgm) if not volume_bgm_db: output_audio = make_silent(output_audio) elif volume_bgm_db != 0: output_audio += volume_bgm_db sound_files = {} for timestamp_key in sorted(chart_data['timestamp'].keys(), key=lambda x: int(x)): for cd in chart_data['timestamp'][timestamp_key]: if cd['name'] != "note": continue if ignore_auto and (cd['data'].get('auto_volume', 0) != 0 or cd['data'].get('auto_note', 0) != 0): continue if 'volume' not in cd['data']: cd['data']['volume'] = 127 is_auto = cd['data'].get( 'auto_volume') == 1 and cd['data'].get('auto_note') != 0 if is_auto: # Change 2/3 later if other games use different ratios cd['data']['volume'] = int( round(cd['data']['volume'] * (2 / 3))) if 'pan' not in cd['data']: cd['data']['pan'] = 64 volume = 127 # 100% volume pan = 64 # Center wav_filename = "%04x.wav" % int(cd['data']['sound_id']) sound_key = "%04d_%03d_%03d" % (cd['data']['sound_id'], cd['data']['volume'], cd['data']['pan']) if sound_metadata and 'entries' in sound_metadata: for sound_entry in sound_metadata['entries']: if int(sound_entry['sound_id']) == int( cd['data']['sound_id']): volume = sound_entry.get('volume', volume) pan = sound_entry.get('pan', pan) if 'flags' not in sound_entry or "NoFilename" not in sound_entry[ 'flags']: wav_filename = sound_entry['filename'] break if sound_key not in sound_files: if cd['data'].get('volume'): volume = (cd['data']['volume'] / 127) * (volume / 127) * 127 if cd['data'].get('pan'): pan = (cd['data']['pan'] - ((128 - pan) / 2)) / (128 / 2) else: pan = (pan - (128 / 2)) / (128 / 2) wav_filename = find_sound_filename( helper.getCaseInsensitivePath( os.path.join(input_foldername, wav_filename))) if os.path.exists(wav_filename): keysound = audio.get_audio_file(wav_filename) keysound = keysound.pan(pan) db = percentage_to_db((volume / 127) * 100) keysound += db if is_auto: volume_key = volume_auto else: volume_key = volume_part if volume_key != 100: volume_db = percentage_to_db(volume_key) if not volume_db: keysound = make_silent(keysound) elif volume_db != 0: keysound += volume_db sound_files[sound_key] = keysound else: print("Couldn't find file: %s" % wav_filename) if sound_key in sound_files: position = int(timestamp_key) / 0x12c #print("Overlaying sound at %f" % position) output_audio = output_audio.overlay(sound_files[sound_key], position=position * 1000) return output_audio
def generate_wav_from_json(params, generate_output_filename=True): input_json = params.get('input') input_foldername = params.get('sound_folder') output_filename = params.get('output') if not params.get('render_ext'): ext = os.path.splitext(output_filename)[-1] ext = ext.replace('.', '').strip() if not ext: ext = "mp3" params['render_ext'] = ext if not input_json: raise Exception("Couldn't find input data") json_data = json.loads(input_json) selected_difficulty = get_selected_difficulty(json_data, params) if not selected_difficulty: raise Exception("Couldn't find selected difficulty") bgms = [] bgm_filename = None for chart_data in json_data['charts']: # Skip metadata charts and stuff not specified by the user if chart_data['header']['is_metadata'] != 0: continue if chart_data['header']['difficulty'] != selected_difficulty: continue game_type = ['drum', 'guitar', 'bass'][chart_data['header']['game_type']] if game_type not in params['parts']: continue if generate_output_filename: output_filename = get_output_filename(json_data, chart_data, params) else: output_filename = params['output'] tags = get_tags(json_data, chart_data) if not bgm_filename: bgm_filename = get_bgm_filename(json_data, chart_data, input_foldername) sound_metadata_type = ['drum', 'guitar', 'guitar'][chart_data['header']['game_type']] json_sound_metadata = get_sound_metadata(params, json_data, input_foldername, sound_metadata_type) if not json_sound_metadata: raise Exception("Couldn't find sound metadata") print("Exporting %s..." % output_filename) bgms.append( create_wav_from_chart( chart_data, input_foldername, json_sound_metadata, output_filename, bgm_filename, tags=tags, no_bgm=params.get('render_no_bgm', False), ext=params.get('render_ext', "mp3"), quality=params.get('render_quality', '320k'), volume_part=params.get('render_volume', 100), volume_bgm=params.get('render_volume_bgm', 100), volume_auto=params.get('render_volume_auto', 100), ignore_auto=params.get('render_ignore_auto', False))) if not bgm_filename: return print("Saving to %s..." % output_filename) if not params.get('render_no_bgm', False): output_audio = audio.get_audio_file(bgm_filename) else: if len(bgms) == 0: return output_audio = bgms[0] bgms = bgms[1:] for bgm in bgms: output_audio = output_audio.overlay(bgm) output_audio.export(params['output'], format=params.get('render_ext', "mp3"), tags={}, bitrate=params.get('render_quality', '320k'))
def fixup_dtx(filename, input_folder, output_folder, no_convert, resources): output_lines = [] difficulty = None has_drum = False has_guitar = False has_bass = False print(filename) for line in open(filename, encoding='shift-jis'): line_orig = line.strip() line = line_orig.upper() # Get DTX filename from line if not line.startswith('#'): output_lines.append(line_orig) continue line = line[1:] while line[0] not in [':', ' ']: line = line[1:] cmd = line_orig[1:len(line_orig) - len(line)].strip().upper() line = line.strip() value = line_orig[-len(line):].strip() while value and value[0] in [':', ' ']: value = value[1:] head = line_orig[:-len(line)] if cmd == "COMMENT": difficulty = value continue elif cmd == "DLEVEL": has_drum = True output_lines.append(line_orig) elif cmd == "GLEVEL": has_guitar = True output_lines.append(line_orig) elif cmd == "BLEVEL": has_bass = True output_lines.append(line_orig) elif cmd in ["PREIMAGE", "PREVIEW"]: idx = 2 ext = os.path.splitext(value)[1] convert_audio = False if ext == ".wav" and not no_convert: convert_audio = True # Convert to .ogg instead ext = ".ogg" target_filename = "pre%s" % (ext) while target_filename in reverse_filename_lookup and reverse_filename_lookup[ target_filename] != value: target_filename = "pre%d%s" % (idx, ext) idx += 1 full_input_path = os.path.join(input_folder, value) if not os.path.exists( full_input_path) and resources and os.path.exists( resources): full_input_path = os.path.join(resources, value) full_target_path = os.path.join(output_folder, target_filename) if convert_audio: if not os.path.exists(full_target_path): if os.path.exists(full_input_path): print(full_input_path) orig_audio = audio.get_audio_file(full_input_path) orig_audio.export(full_target_path) print(target_filename) else: print("Couldn't find", full_input_path) else: if os.path.exists(full_input_path): shutil.copyfile(full_input_path, full_target_path) else: print("Couldn't find", full_input_path) add_filename(value, target_filename) output_lines.append(head + target_filename) elif cmd.startswith("WAV") or cmd.startswith("AVI"): idx = 0 ext = os.path.splitext(value)[1] convert_audio = False if ext == ".wav" and not no_convert: convert_audio = True # Convert to .ogg instead ext = ".ogg" target_filename = "%04d%s" % (idx, ext) while target_filename in reverse_filename_lookup and reverse_filename_lookup[ target_filename] != value: target_filename = "%04d%s" % (idx, ext) idx += 1 full_input_path = os.path.join(input_folder, value) full_target_path = os.path.join(output_folder, target_filename) if convert_audio: if not os.path.exists(full_target_path): if os.path.exists(full_input_path): print(full_input_path) orig_audio = audio.get_audio_file(full_input_path) orig_audio.export(full_target_path) print(target_filename) else: print("Couldn't find", full_input_path) else: if os.path.exists(full_input_path): shutil.copyfile(full_input_path, full_target_path) else: print("Couldn't find", full_input_path) add_filename(value, target_filename) output_lines.append(head + target_filename) else: output_lines.append(line_orig) prefix = None if difficulty: prefix = { "BASIC": "bsc", "ADVANCED": "adv", "EXTREME": "ext", "MASTER": "mst", }[difficulty.upper()] if not prefix: print("Couldn't figure out what to prefix this file", filename) exit(1) output_filename = "_".join( list( filter(None, [ prefix, *[ "drum" if has_drum else None, "guitar" if has_guitar else None, "bass" if has_bass else None ] ]))) + ".dtx" if not output_filename: print("Couldn't figure out what to name this file", filename) exit(1) open(os.path.join(output_folder, output_filename), "w", encoding='shift-jis').write("\n".join(output_lines)) return output_filename