Exemplo n.º 1
0
 def save(self, filename=None, compress=False):
     if self.file_platform not in XNB_PLATFORMS:
         raise ReaderError("bad platform: '{!r}'".format(self.file_platform))
     if self.file_version not in XNB_VERSIONS:
         raise ReaderError("bad version: {}".format(self.file_version))
     attribs = 0
     if self.file_version >= VERSION_40:
         if self.graphics_profile not in XNB_PROFILES:
             raise ReaderError("bad profile: {}".format(self.graphics_profile))
         attribs |= self.graphics_profile & _PROFILE_MASK
     do_compress = False
     if self.file_version >= VERSION_30:
         if compress:
             do_compress = True
             attribs |= _COMPRESS_MASK
     stream = BinaryStream()
     if do_compress:
         raise ReaderError("Recompression not supported")
     else:
         data = self.getvalue()
         size = len(data) + stream.calc_size(_XNB_HEADER)
     stream.pack(_XNB_HEADER, XNB_SIGNATURE, self.file_platform, self.file_version, attribs, size)
     stream.write(data)
     if filename is not None:
         filename = os.path.normpath(filename)
         dirname = os.path.dirname(filename)
         if not os.path.isdir(dirname):
             os.makedirs(dirname)
         if not filename.endswith(XNB_EXTENSION):
             filename += XNB_EXTENSION
         stream.write_file(filename)
     else:
         return stream.getvalue()
Exemplo n.º 2
0
 def write(self, filename):
     h_s = BinaryStream()
     h_s.pack(self._waveformatex, self.h_format_tag, self.h_channels,
              self.h_samples_per_sec, self.h_avg_bytes_per_sec,
              self.h_block_align, self.h_bits_per_sample)
     if self.h_size is not None:
         h_s.write_uint16(self.h_size)
         if self.h_format_tag == WAVE_FORMAT_XMA2:
             # hack so mono sounds end up center rather than left
             if self.h_channels == 1 and self.hx_channel_mask == 1:
                 hx_channel_mask = 0
             else:
                 hx_channel_mask = self.hx_channel_mask
             h_s.pack(self._waveformat_xma2, self.hx_num_streams,
                      hx_channel_mask, self.hx_samples_encoded,
                      self.hx_bytes_per_block, self.hx_play_begin,
                      self.hx_play_length, self.hx_loop_begin,
                      self.hx_loop_length, self.hx_loop_count,
                      self.hx_encoder_version, self.hx_block_count)
         elif self.h_format_tag == WAVE_FORMAT_EXTENSIBLE:
             h_s.pack(self._waveformat_extensible,
                      self.he_valid_bits_per_sample, self.he_channel_mask,
                      self.he_subformat.bytes_le)
             if self.he_remainder:
                 h_s.write(self.he_remainder)
         if self.h_remainder:
             h_s.write(self.h_remainder)
     header_raw = h_s.getvalue()
     if self.dpds_raw:
         dpds_size = len(self.dpds_raw)
     else:
         dpds_size = None
     if self.seek_raw:
         seek_size = len(self.seek_raw)
     else:
         seek_size = None
     o_s = BinaryStream()
     if self.h_format_tag == WAVE_FORMAT_WMAUDIO2 or self.h_format_tag == WAVE_FORMAT_WMAUDIO3:
         riff_type = b'XWMA'
     else:
         riff_type = b'WAVE'
     self.write_header(o_s, riff_type, len(header_raw), len(self.data_raw),
                       dpds_size, seek_size)
     self.write_chunk(o_s, b'fmt ', header_raw)
     if self.dpds_raw:
         self.write_chunk(o_s, b'dpds', self.dpds_raw)
     if self.seek_raw:
         self.write_chunk(o_s, b'seek', self.seek_raw)
     self.write_chunk(o_s, b'data', self.data_raw)
     if self.h_format_tag == WAVE_FORMAT_XMA2:
         full_filename = filename + '.xma'
     elif self.h_format_tag == WAVE_FORMAT_WMAUDIO2 or self.h_format_tag == WAVE_FORMAT_WMAUDIO2:
         full_filename = filename + '.xwma'
     else:
         full_filename = filename + '.wav'
     o_s.write_file(full_filename)
Exemplo n.º 3
0
 def write(self, filename):
     h_s = BinaryStream()
     h_s.pack(self._waveformatex, self.h_format_tag, self.h_channels, self.h_samples_per_sec,
              self.h_avg_bytes_per_sec, self.h_block_align, self.h_bits_per_sample)
     if self.h_size is not None:
         h_s.write_uint16(self.h_size)
         if self.h_format_tag == WAVE_FORMAT_XMA2:
             # hack so mono sounds end up center rather than left
             if self.h_channels == 1 and self.hx_channel_mask == 1:
                 hx_channel_mask = 0
             else:
                 hx_channel_mask = self.hx_channel_mask
             h_s.pack(self._waveformat_xma2, self.hx_num_streams, hx_channel_mask, self.hx_samples_encoded,
                      self.hx_bytes_per_block, self.hx_play_begin, self.hx_play_length, self.hx_loop_begin,
                      self.hx_loop_length, self.hx_loop_count, self.hx_encoder_version, self.hx_block_count)
         elif self.h_format_tag == WAVE_FORMAT_EXTENSIBLE:
             h_s.pack(self._waveformat_extensible, self.he_valid_bits_per_sample, self.he_channel_mask,
                      self.he_subformat.bytes_le)
             if self.he_remainder:
                 h_s.write(self.he_remainder)
         if self.h_remainder:
             h_s.write(self.h_remainder)
     header_raw = h_s.getvalue()
     if self.dpds_raw:
         dpds_size = len(self.dpds_raw)
     else:
         dpds_size = None
     if self.seek_raw:
         seek_size = len(self.seek_raw)
     else:
         seek_size = None
     o_s = BinaryStream()
     if self.h_format_tag == WAVE_FORMAT_WMAUDIO2 or self.h_format_tag == WAVE_FORMAT_WMAUDIO3:
         riff_type = b'XWMA'
     else:
         riff_type = b'WAVE'
     self.write_header(o_s, riff_type, len(header_raw), len(self.data_raw), dpds_size, seek_size)
     self.write_chunk(o_s, b'fmt ', header_raw)
     if self.dpds_raw:
         self.write_chunk(o_s, b'dpds', self.dpds_raw)
     if self.seek_raw:
         self.write_chunk(o_s, b'seek', self.seek_raw)
     self.write_chunk(o_s, b'data', self.data_raw)
     if self.h_format_tag == WAVE_FORMAT_XMA2:
         full_filename = filename + '.xma'
     elif self.h_format_tag == WAVE_FORMAT_WMAUDIO2 or self.h_format_tag == WAVE_FORMAT_WMAUDIO2:
         full_filename = filename + '.xwma'
     else:
         full_filename = filename + '.wav'
     o_s.write_file(full_filename)
Exemplo n.º 4
0
 def save(self, filename=None, compress=False):
     if self.file_platform not in XNB_PLATFORMS:
         raise ReaderError("bad platform: '{!r}'".format(
             self.file_platform))
     if self.file_version not in XNB_VERSIONS:
         raise ReaderError("bad version: {}".format(self.file_version))
     attribs = 0
     if self.file_version >= VERSION_40:
         if self.graphics_profile not in XNB_PROFILES:
             raise ReaderError("bad profile: {}".format(
                 self.graphics_profile))
         attribs |= self.graphics_profile & _PROFILE_MASK
     do_compress = False
     if self.file_version >= VERSION_30:
         if compress:
             do_compress = True
             attribs |= _COMPRESS_MASK
     stream = BinaryStream()
     if do_compress:
         raise ReaderError("Recompression not supported")
     else:
         data = self.getvalue()
         size = len(data) + stream.calc_size(_XNB_HEADER)
     stream.pack(_XNB_HEADER, XNB_SIGNATURE, self.file_platform,
                 self.file_version, attribs, size)
     stream.write(data)
     if filename is not None:
         filename = os.path.normpath(filename)
         dirname = os.path.dirname(filename)
         if not os.path.isdir(dirname):
             os.makedirs(dirname)
         if not filename.endswith(XNB_EXTENSION):
             filename += XNB_EXTENSION
         stream.write_file(filename)
     else:
         return stream.getvalue()
Exemplo n.º 5
0
    def __init__(self, data=None, filename=None, audio_engine=None):
        self.audio_engine = audio_engine

        # open in little endian initially
        stream = BinaryStream(data=data, filename=filename)
        del data

        # check sig to find actual endianess
        h_sig = stream.peek(len(WB_L_SIGNATURE))
        if h_sig == WB_L_SIGNATURE:
            big_endian = False
        elif h_sig == WB_B_SIGNATURE:
            big_endian = True
        else:
            raise ValueError("bad sig: {!r}".format(h_sig))

        # switch stream to correct endianess
        stream.set_endian(big_endian)
        (h_sig, self.h_version, self.h_header_version) = stream.unpack(_WB_HEADER)
        regions = {k: XWBRegion._make(stream.unpack(_WB_REGION)) for k in _REGIONS}  # pylint: disable-msg=W0212

        # check if we have a valid BANKDATA region and parse it
        bankdata_size = stream.calc_size(_WB_DATA)
        if regions['BANKDATA'].length != bankdata_size:
            raise ReaderError("Invalid BANKDATA size: {} != {}".format(regions['BANKDATA'].length, bankdata_size))
        stream.seek(regions['BANKDATA'].offset)
        (self.flags, h_entry_count, h_bank_name_raw, h_entry_metadata_element_size, h_entry_name_element_size,
         self.alignment, h_compact_format, buildtime_raw_low, buildtime_raw_high) = stream.unpack(_WB_DATA)
        self.bank_name = h_bank_name_raw.rstrip(b'\x00').decode('iso8859-1')
        del h_bank_name_raw
        self.buildtime = filetime_to_datetime(buildtime_raw_low, buildtime_raw_high)

        if self.flags & ~(WB_TYPE_MASK | WB_FLAGS_MASK):
            raise ReaderError("Unknown flags in WAVEBANK")

        # check what type of ENTRYMETADATA we have and parse it
        if self.has_compact:
            raise ReaderError("Compact format not supported")
        bankentry_size = stream.calc_size(_WB_ENTRY)
        if bankentry_size != h_entry_metadata_element_size:
            raise ReaderError("Unknown EntryMetaDataElementSize: {} != {}".format(bankentry_size,
                                                                                  h_entry_metadata_element_size))
        if regions['ENTRYMETADATA'].length != bankentry_size * h_entry_count:
            raise ReaderError("Invalid ENTRYMETADATA size: {} != {}".format(regions['ENTRYMETADATA'].length,
                                                                            bankentry_size * h_entry_count))
        stream.seek(regions['ENTRYMETADATA'].offset)
        entry_metadata = [XWBEntry._make(stream.unpack(_WB_ENTRY))  # pylint: disable-msg=W0212,E1101
                          for _ in range(h_entry_count)]

        # read ENTRYNAMES if present
        entry_names = []
        if self.has_entry_names and regions['ENTRYNAMES'].offset and regions['ENTRYNAMES'].length:
            if regions['ENTRYNAMES'].length != h_entry_name_element_size * h_entry_count:
                raise ReaderError("Invalid ENTRYNAMES region size: {} != {}".format(
                    regions['ENTRYNAMES'].length, h_entry_name_element_size * h_entry_count))
            stream.seek(regions['ENTRYNAMES'].offset)
            entry_names = [stream.read(h_entry_name_element_size).rstrip(b'\x00').decode('iso8859-1')
                           for _ in range(h_entry_count)]

        # read SEEKTABLES if present
        entry_seektables = []
        if self.has_seek_tables and regions['SEEKTABLES'].offset and regions['SEEKTABLES'].length:
            stream.seek(regions['SEEKTABLES'].offset)
            seek_offsets = []
            for _ in range(h_entry_count):
                seek_offsets.append(stream.read_int32())
            seek_data_offset = stream.tell()
            for cur_offset in seek_offsets:
                if cur_offset >= 0:
                    stream.seek(seek_data_offset + cur_offset)
                    packet_count = stream.read_uint32()
                    cur_seek_data = BinaryStream()
                    for _ in range(packet_count):
                        cur_seek_data.write_uint32(stream.read_uint32())
                    entry_seektables.append(cur_seek_data.getvalue())
                else:
                    entry_seektables.append(None)

        self.entries = []
        for i, cur_meta in enumerate(entry_metadata):
            c_entry_flags = cur_meta.flags_duration & WB_ENTRY_FLAGS_MASK
            c_duration = (cur_meta.flags_duration & WB_ENTRY_DURATION_MASK) >> 4
            c_format_tag = cur_meta.format & WB_FORMAT_TAG_MASK
            c_channels = (cur_meta.format & WB_FORMAT_CHANNELS) >> 2
            c_samples_per_sec = (cur_meta.format & WB_FORMAT_SAMPLES_PER_SEC) >> 5
            c_block_align = (cur_meta.format & WB_FORMAT_BLOCK_ALIGN) >> 23
            c_bits_per_sample = (cur_meta.format & WB_FORMAT_BITS_PER_SAMPLE) >> 31
            entry_name = None
            if entry_names:
                entry_name = entry_names[i]
            entry_dpds = None
            entry_seek = None
            extra_header = bytes()
            # build format specific header and seek data
            if c_format_tag == WB_FORMAT_TAG_PCM:
                c_format_tag = WAVE_FORMAT_PCM
                if c_bits_per_sample == 1:
                    c_bits_per_sample = 16
                else:
                    c_bits_per_sample = 8
                c_avg_bytes_per_sec = c_samples_per_sec * c_block_align
            elif c_format_tag == WB_FORMAT_TAG_ADPCM:
                c_format_tag = WAVE_FORMAT_ADPCM
                c_bits_per_sample = 4
                c_block_align = (c_block_align + ADPCM_BLOCK_ALIGN_OFFSET) * c_channels
                cx_samples_per_block = ((c_block_align - (7 * c_channels)) * 8) // (c_bits_per_sample * c_channels) + 2
                c_avg_bytes_per_sec = (c_samples_per_sec // cx_samples_per_block) * c_block_align
                cx_num_coef = len(ADPCM_COEF)
                extra_header = _ADPCM_WAVEFORMAT.pack(cx_samples_per_block, cx_num_coef)
                for coef in ADPCM_COEF:
                    extra_header += _ADPCM_WAVEFORMAT_COEF.pack(coef[0], coef[1])
            elif c_format_tag == WB_FORMAT_TAG_WMA:
                if c_bits_per_sample == 1:
                    c_format_tag = WAVE_FORMAT_WMAUDIO3
                else:
                    c_format_tag = WAVE_FORMAT_WMAUDIO2
                c_bits_per_sample = 16
                c_avg_bytes_per_sec = WMA_AVG_BYTES_PER_SEC[c_block_align >> 5]
                c_block_align = WMA_BLOCK_ALIGN[c_block_align & 0x1f]
                if entry_seektables:
                    entry_dpds = entry_seektables[i]
                else:
                    raise ReaderError("No SEEKTABLES found for xWMA format")
            elif c_format_tag == WB_FORMAT_TAG_XMA:
                # lots of placeholders in here but seems to decode ok
                c_format_tag = WAVE_FORMAT_XMA2
                c_bits_per_sample = 16
                c_avg_bytes_per_sec = 0
                cx_num_streams = 1
                if c_channels == 2:
                    cx_channel_mask = 3
                else:
                    cx_channel_mask = 0
                cx_samples_encoded = 0
                cx_bytes_per_block = 0
                cx_play_begin = 0
                cx_play_length = 0
                cx_loop_begin = 0
                cx_loop_length = 0
                cx_loop_count = 0
                cx_encoder_version = 4
                cx_block_count = 1
                extra_header = _XMA_WAVEFORMAT.pack(cx_num_streams, cx_channel_mask, cx_samples_encoded,
                                                    cx_bytes_per_block, cx_play_begin, cx_play_length, cx_loop_begin,
                                                    cx_loop_length, cx_loop_count, cx_encoder_version, cx_block_count)
                if entry_seektables:
                    entry_seek = entry_seektables[i]
                else:
                    raise ReaderError("No SEEKTABLES found for XMA2 format")
            else:
                raise ReaderError("Unhandled entry format: {}".format(c_format_tag))
            cx_size = len(extra_header)
            entry_header = _WAVEFORMATEX.pack(c_format_tag, c_channels, c_samples_per_sec, c_avg_bytes_per_sec,
                                              c_block_align, c_bits_per_sample, cx_size)
            entry_header += extra_header
            # read entry wave data
            stream.seek(regions['ENTRYWAVEDATA'].offset + cur_meta.play_offset)
            # manually swap PCM data if needed
            entry_data = stream.read(cur_meta.play_length)
            if big_endian and c_format_tag == WAVE_FORMAT_PCM and c_bits_per_sample == 16:
                entry_data = bytearray(entry_data)
                entry_data[1::2], entry_data[0::2] = entry_data[0::2], entry_data[1::2]
            self.entries.append(Entry(entry_name, entry_header, entry_data, entry_dpds, entry_seek))
Exemplo n.º 6
0
    def __init__(self, data=None, filename=None, audio_engine=None):
        self.audio_engine = audio_engine

        # open in little endian initially
        stream = BinaryStream(data=data, filename=filename)
        del data

        # check sig to find actual endianess
        h_sig = stream.peek(len(WB_L_SIGNATURE))
        if h_sig == WB_L_SIGNATURE:
            big_endian = False
        elif h_sig == WB_B_SIGNATURE:
            big_endian = True
        else:
            raise ValueError("bad sig: {!r}".format(h_sig))

        # switch stream to correct endianess
        stream.set_endian(big_endian)
        (h_sig, self.h_version,
         self.h_header_version) = stream.unpack(_WB_HEADER)
        regions = {
            k: XWBRegion._make(stream.unpack(_WB_REGION))
            for k in _REGIONS
        }  # pylint: disable-msg=W0212

        # check if we have a valid BANKDATA region and parse it
        bankdata_size = stream.calc_size(_WB_DATA)
        if regions['BANKDATA'].length != bankdata_size:
            raise ReaderError("Invalid BANKDATA size: {} != {}".format(
                regions['BANKDATA'].length, bankdata_size))
        stream.seek(regions['BANKDATA'].offset)
        (self.flags, h_entry_count, h_bank_name_raw,
         h_entry_metadata_element_size, h_entry_name_element_size,
         self.alignment, h_compact_format, buildtime_raw_low,
         buildtime_raw_high) = stream.unpack(_WB_DATA)
        self.bank_name = h_bank_name_raw.rstrip(b'\x00').decode('iso8859-1')
        del h_bank_name_raw
        self.buildtime = filetime_to_datetime(buildtime_raw_low,
                                              buildtime_raw_high)

        if self.flags & ~(WB_TYPE_MASK | WB_FLAGS_MASK):
            raise ReaderError("Unknown flags in WAVEBANK")

        # check what type of ENTRYMETADATA we have and parse it
        if self.has_compact:
            raise ReaderError("Compact format not supported")
        bankentry_size = stream.calc_size(_WB_ENTRY)
        if bankentry_size != h_entry_metadata_element_size:
            raise ReaderError(
                "Unknown EntryMetaDataElementSize: {} != {}".format(
                    bankentry_size, h_entry_metadata_element_size))
        if regions['ENTRYMETADATA'].length != bankentry_size * h_entry_count:
            raise ReaderError("Invalid ENTRYMETADATA size: {} != {}".format(
                regions['ENTRYMETADATA'].length,
                bankentry_size * h_entry_count))
        stream.seek(regions['ENTRYMETADATA'].offset)
        entry_metadata = [
            XWBEntry._make(
                stream.unpack(_WB_ENTRY))  # pylint: disable-msg=W0212,E1101
            for _ in range(h_entry_count)
        ]

        # read ENTRYNAMES if present
        entry_names = []
        if self.has_entry_names and regions['ENTRYNAMES'].offset and regions[
                'ENTRYNAMES'].length:
            if regions[
                    'ENTRYNAMES'].length != h_entry_name_element_size * h_entry_count:
                raise ReaderError(
                    "Invalid ENTRYNAMES region size: {} != {}".format(
                        regions['ENTRYNAMES'].length,
                        h_entry_name_element_size * h_entry_count))
            stream.seek(regions['ENTRYNAMES'].offset)
            entry_names = [
                stream.read(h_entry_name_element_size).rstrip(b'\x00').decode(
                    'iso8859-1') for _ in range(h_entry_count)
            ]

        # read SEEKTABLES if present
        entry_seektables = []
        if self.has_seek_tables and regions['SEEKTABLES'].offset and regions[
                'SEEKTABLES'].length:
            stream.seek(regions['SEEKTABLES'].offset)
            seek_offsets = []
            for _ in range(h_entry_count):
                seek_offsets.append(stream.read_int32())
            seek_data_offset = stream.tell()
            for cur_offset in seek_offsets:
                if cur_offset >= 0:
                    stream.seek(seek_data_offset + cur_offset)
                    packet_count = stream.read_uint32()
                    cur_seek_data = BinaryStream()
                    for _ in range(packet_count):
                        cur_seek_data.write_uint32(stream.read_uint32())
                    entry_seektables.append(cur_seek_data.getvalue())
                else:
                    entry_seektables.append(None)

        self.entries = []
        for i, cur_meta in enumerate(entry_metadata):
            c_entry_flags = cur_meta.flags_duration & WB_ENTRY_FLAGS_MASK
            c_duration = (cur_meta.flags_duration
                          & WB_ENTRY_DURATION_MASK) >> 4
            c_format_tag = cur_meta.format & WB_FORMAT_TAG_MASK
            c_channels = (cur_meta.format & WB_FORMAT_CHANNELS) >> 2
            c_samples_per_sec = (cur_meta.format
                                 & WB_FORMAT_SAMPLES_PER_SEC) >> 5
            c_block_align = (cur_meta.format & WB_FORMAT_BLOCK_ALIGN) >> 23
            c_bits_per_sample = (cur_meta.format
                                 & WB_FORMAT_BITS_PER_SAMPLE) >> 31
            entry_name = None
            if entry_names:
                entry_name = entry_names[i]
            entry_dpds = None
            entry_seek = None
            extra_header = bytes()
            # build format specific header and seek data
            if c_format_tag == WB_FORMAT_TAG_PCM:
                c_format_tag = WAVE_FORMAT_PCM
                if c_bits_per_sample == 1:
                    c_bits_per_sample = 16
                else:
                    c_bits_per_sample = 8
                c_avg_bytes_per_sec = c_samples_per_sec * c_block_align
            elif c_format_tag == WB_FORMAT_TAG_ADPCM:
                c_format_tag = WAVE_FORMAT_ADPCM
                c_bits_per_sample = 4
                c_block_align = (c_block_align +
                                 ADPCM_BLOCK_ALIGN_OFFSET) * c_channels
                cx_samples_per_block = (
                    (c_block_align - (7 * c_channels)) *
                    8) // (c_bits_per_sample * c_channels) + 2
                c_avg_bytes_per_sec = (c_samples_per_sec //
                                       cx_samples_per_block) * c_block_align
                cx_num_coef = len(ADPCM_COEF)
                extra_header = _ADPCM_WAVEFORMAT.pack(cx_samples_per_block,
                                                      cx_num_coef)
                for coef in ADPCM_COEF:
                    extra_header += _ADPCM_WAVEFORMAT_COEF.pack(
                        coef[0], coef[1])
            elif c_format_tag == WB_FORMAT_TAG_WMA:
                if c_bits_per_sample == 1:
                    c_format_tag = WAVE_FORMAT_WMAUDIO3
                else:
                    c_format_tag = WAVE_FORMAT_WMAUDIO2
                c_bits_per_sample = 16
                c_avg_bytes_per_sec = WMA_AVG_BYTES_PER_SEC[c_block_align >> 5]
                c_block_align = WMA_BLOCK_ALIGN[c_block_align & 0x1f]
                if entry_seektables:
                    entry_dpds = entry_seektables[i]
                else:
                    raise ReaderError("No SEEKTABLES found for xWMA format")
            elif c_format_tag == WB_FORMAT_TAG_XMA:
                # lots of placeholders in here but seems to decode ok
                c_format_tag = WAVE_FORMAT_XMA2
                c_bits_per_sample = 16
                c_avg_bytes_per_sec = 0
                cx_num_streams = 1
                if c_channels == 2:
                    cx_channel_mask = 3
                else:
                    cx_channel_mask = 0
                cx_samples_encoded = 0
                cx_bytes_per_block = 0
                cx_play_begin = 0
                cx_play_length = 0
                cx_loop_begin = 0
                cx_loop_length = 0
                cx_loop_count = 0
                cx_encoder_version = 4
                cx_block_count = 1
                extra_header = _XMA_WAVEFORMAT.pack(
                    cx_num_streams, cx_channel_mask, cx_samples_encoded,
                    cx_bytes_per_block, cx_play_begin, cx_play_length,
                    cx_loop_begin, cx_loop_length, cx_loop_count,
                    cx_encoder_version, cx_block_count)
                if entry_seektables:
                    entry_seek = entry_seektables[i]
                else:
                    raise ReaderError("No SEEKTABLES found for XMA2 format")
            else:
                raise ReaderError(
                    "Unhandled entry format: {}".format(c_format_tag))
            cx_size = len(extra_header)
            entry_header = _WAVEFORMATEX.pack(c_format_tag, c_channels,
                                              c_samples_per_sec,
                                              c_avg_bytes_per_sec,
                                              c_block_align, c_bits_per_sample,
                                              cx_size)
            entry_header += extra_header
            # read entry wave data
            stream.seek(regions['ENTRYWAVEDATA'].offset + cur_meta.play_offset)
            # manually swap PCM data if needed
            entry_data = stream.read(cur_meta.play_length)
            if big_endian and c_format_tag == WAVE_FORMAT_PCM and c_bits_per_sample == 16:
                entry_data = bytearray(entry_data)
                entry_data[1::2], entry_data[0::2] = entry_data[
                    0::2], entry_data[1::2]
            self.entries.append(
                Entry(entry_name, entry_header, entry_data, entry_dpds,
                      entry_seek))