def parse_wav(input_filename, output_filename, loop_start=None, loop_end=None, channels=2, rate=48000): input_filename = audio.get_processed_wav(input_filename, channels=channels, rate=rate, bits=16) if not input_filename: return rate, data, bits, loops = wavfile.read(input_filename, readloops=True) channels = 1 if len(data.shape) == 1 else data.shape[1] if len(loops) > 0: if len(loops) > 1: print("Found %d loops, only reading first loop" % len(loops)) loop_start, loop_end = loops[0] else: loop_start = 0 loop_end = 0 output = adpcmwave.encode_data(data, channels) with open(output_filename, "wb") as outfile: outfile.write("BMP\0".encode('ascii')) outfile.write(struct.pack(">I", len(output))) outfile.write(struct.pack(">I", loop_start)) outfile.write(struct.pack(">I", loop_end)) outfile.write(struct.pack("<H", channels)) outfile.write(struct.pack("<H", bits)) outfile.write(struct.pack(">I", rate)) outfile.write(bytearray([0] * 8)) outfile.write(output)
def write_vas3(input_foldername, output_filename, metadata=None): if not input_foldername: input_foldername = "" if not output_filename: output_filename = "" if not metadata: metadata = json.load( open(os.path.join(input_foldername, "metadata.json"), "r")) with open(output_filename, "wb") as outfile: version = 2 gdx_size = GDX_SIZES[ metadata['type']] if metadata['type'] in GDX_SIZES else 0x14 gdx_start = 0x40 gdx_entry_start = gdx_start + gdx_size data_start = gdx_start + gdx_size + (len(metadata['entries']) * 0x40) data_start_padding = 16 - (data_start % 16) if data_start_padding != 16: data_start += data_start_padding outfile.write("VA3W".encode('ascii')) outfile.write(struct.pack("<B", 1)) outfile.write(struct.pack("<B", 0)) outfile.write(struct.pack("<B", 0)) outfile.write(struct.pack( "<B", version)) # TODO: Add support for saving old archives? outfile.write(struct.pack("<I", len(metadata['entries']))) outfile.write(struct.pack( "<I", gdx_size)) # Change depending on archive version outfile.write(struct.pack("<I", gdx_start)) outfile.write(struct.pack("<I", gdx_entry_start)) outfile.write(struct.pack("<I", data_start)) if outfile.tell() < gdx_start: outfile.write(bytearray([0] * (gdx_start - outfile.tell()))) # Padding outfile.write(metadata['type'].encode('ascii')) outfile.write(struct.pack("<H", metadata['defaults']['default_hihat'])) outfile.write(struct.pack("<H", metadata['defaults']['default_snare'])) outfile.write(struct.pack("<H", metadata['defaults']['default_bass'])) outfile.write( struct.pack("<H", metadata['defaults']['default_hightom'])) outfile.write(struct.pack("<H", metadata['defaults']['default_lowtom'])) outfile.write( struct.pack("<H", metadata['defaults']['default_rightcymbal'])) if metadata['type'] == "GDXH": outfile.write(struct.pack("<B", metadata['gdx_type_unk1'])) outfile.write(struct.pack("<B", metadata['gdx_volume_flag'])) elif metadata['type'] == "GDXG": outfile.write( struct.pack("<H", metadata['defaults']['default_leftcymbal'])) outfile.write( struct.pack("<H", metadata['defaults']['default_floortom'])) outfile.write( struct.pack("<H", metadata['defaults']['default_leftpedal'])) else: print("Unknown type %s" % metadata['type']) exit(1) if outfile.tell() < gdx_entry_start: outfile.write(bytearray( [0] * (gdx_entry_start - outfile.tell()))) # Padding defaults = [metadata['defaults'][x] for x in metadata['defaults']] data_section = bytearray() for entry in metadata['entries']: filename = entry['filename'] if "NoFilename" in entry['flags']: filename = "%04x" % entry['sound_id'] if not os.path.exists(os.path.join(input_foldername, filename)): # Lame way to check if it has an extension for ext in ['wav', 'ogg', 'mp3']: new_filename = "{}.{}".format(filename, ext).replace("\\", "/") if os.path.exists( os.path.join(input_foldername, new_filename)): filename = new_filename break # Build full path filename = os.path.join( input_foldername, os.path.normpath(filename.replace("\\", "/"))) filename = helper.getCaseInsensitivePath(filename) if not os.path.exists(filename): print("Could not find %s" % filename) continue # Set entry filename to just the filename without extension or path entry['filename'] = os.path.splitext(os.path.basename(filename))[0] if 'flags' not in entry: entry['flags'] = [] if 'extra' not in entry: entry['extra'] = 255 # Normal? # try: # rate, raw_data, bits = wavfile.read(filename) # except: # Try using pysoundfile if wavfile failed # If this code works well enough, I can probably get rid of # wavfile for the was3tool since looping isn't required # TODO: Replace this with code to detect if it's a WAV, 16bit, mono, and 48000 and if so, use wavfile instead #print(filename) filename = audio.get_processed_wav(filename, channels=1, rate=48000, bits=16) rate, raw_data, bits = wavfile.read(filename) channels = 1 if len(raw_data.shape) == 1 else raw_data.shape[1] encoded_data = adpcmwave.encode_data(raw_data, channels) sound_flag = 0 for flag in entry['flags']: if flag in FLAG_MAP: sound_flag |= FLAG_MAP[flag] elif type(flag) == int: sound_flag |= flag else: print( "Don't know how to handle flag {}, ignoring...".format( flag)) if version >= 2: if entry['sound_id'] in defaults: sound_flag |= 0x04 elif len(defaults) > 0: # Is this right? sound_flag |= 0x02 # Not a default? volume = entry['volume'] if version < 2: volume = VOLUME_TABLE.index( min(VOLUME_TABLE, key=lambda x: abs(x - entry['volume']))) outfile.write(struct.pack("<I", len(data_section))) outfile.write(struct.pack("<I", len(encoded_data))) outfile.write(struct.pack("<H", channels)) outfile.write(struct.pack("<H", 0x10)) # Will this ever not be 16 bit? outfile.write(struct.pack("<I", rate)) outfile.write(struct.pack( "<I", 0)) # This should always be 0 for v2 I think? outfile.write(struct.pack( "<I", 0)) # This should always be 0 for v2 I think? outfile.write(struct.pack("<B", volume)) outfile.write(struct.pack("<B", entry['pan'])) outfile.write(struct.pack("<H", entry['sound_id'])) outfile.write(struct.pack("<H", sound_flag)) outfile.write(struct.pack("<H", entry['extra'])) filename_bytes = entry['filename'].encode('ascii') outfile.write(filename_bytes[:0x20]) if len(filename_bytes) < 0x20: outfile.write(bytearray([0] * (0x20 - len(filename_bytes)))) data_section += encoded_data padding = 0x10 - (len(data_section) % 0x10) if padding != 0x10: data_section += bytearray([0] * padding) if outfile.tell() < data_start: outfile.write(bytearray([0] * (data_start - outfile.tell()))) # Padding outfile.write(data_section)