Example #1
0
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)