def tags(file, order):
            while True:
                reader = BitstreamReader(file, order)
                # read all the tags in an IFD
                tag_count = reader.read(16)
                sub_reader = reader.substream(tag_count * 12)
                next_ifd = reader.read(32)

                for i in range(tag_count):
                    (tag_code, tag_datatype,
                     tag_value_count) = sub_reader.parse("16u 16u 32u")
                    if tag_datatype == 1:  # BYTE type
                        tag_struct = "8u" * tag_value_count
                    elif tag_datatype == 3:  # SHORT type
                        tag_struct = "16u" * tag_value_count
                    elif tag_datatype == 4:  # LONG type
                        tag_struct = "32u" * tag_value_count
                    else:  # all other types
                        tag_struct = "4b"
                    if format_size(tag_struct) <= 32:
                        yield (tag_code, sub_reader.parse(tag_struct))
                        sub_reader.skip(32 - format_size(tag_struct))
                    else:
                        offset = sub_reader.read(32)
                        file.seek(offset, 0)
                        yield (tag_code,
                               BitstreamReader(file, order).parse(tag_struct))

                if next_ifd != 0:
                    file.seek(next_ifd, 0)
                else:
                    break
Beispiel #2
0
        def tags(file, order):
            while True:
                reader = BitstreamReader(file, order)
                # read all the tags in an IFD
                tag_count = reader.read(16)
                sub_reader = reader.substream(tag_count * 12)
                next_ifd = reader.read(32)

                for i in range(tag_count):
                    (tag_code,
                     tag_datatype,
                     tag_value_count) = sub_reader.parse("16u 16u 32u")
                    if tag_datatype == 1:    # BYTE type
                        tag_struct = "8u" * tag_value_count
                    elif tag_datatype == 3:  # SHORT type
                        tag_struct = "16u" * tag_value_count
                    elif tag_datatype == 4:  # LONG type
                        tag_struct = "32u" * tag_value_count
                    else:                      # all other types
                        tag_struct = "4b"
                    if format_size(tag_struct) <= 32:
                        yield (tag_code, sub_reader.parse(tag_struct))
                        sub_reader.skip(32 - format_size(tag_struct))
                    else:
                        offset = sub_reader.read(32)
                        file.seek(offset, 0)
                        yield (tag_code,
                               BitstreamReader(file, order).parse(tag_struct))

                if next_ifd != 0:
                    file.seek(next_ifd, 0)
                else:
                    break
class WavPackDecoder:
    def __init__(self, filename):
        self.reader = BitstreamReader(open(filename, "rb"), 1)

        #read initial block to populate
        #sample_rate, bits_per_sample, channels, and channel_mask
        self.reader.mark()
        block_header = Block_Header.read(self.reader)
        sub_blocks_size = block_header.block_size - 24
        sub_blocks_data = self.reader.substream(sub_blocks_size)
        if (block_header.sample_rate != 15):
            self.sample_rate = [6000,  8000,  9600,  11025, 12000,
                                16000, 22050, 24000, 32000, 44100,
                                48000, 64000, 88200, 96000,
                                192000][block_header.sample_rate]
        else:
            sub_blocks_data.mark()
            try:
                for sub_block in sub_blocks(sub_blocks_data, sub_blocks_size):
                    if ((sub_block.metadata_function == 7) and
                        (sub_block.nondecoder_data == 1)):
                        self.sample_rate = sub_block.data.read(
                            sub_block.data_size() * 8)
                        break
                else:
                    raise ValueError("invalid sample rate")
            finally:
                sub_blocks_data.rewind()
                sub_blocks_data.unmark()

        self.bits_per_sample = [8, 16, 24, 32][block_header.bits_per_sample]

        if (block_header.initial_block and block_header.final_block):
            if ((block_header.mono_output == 0) or
                (block_header.false_stereo == 1)):
                self.channels = 2
                self.channel_mask = 0x3
            else:
                self.channels = 1
                self.channel_mask = 0x4
        else:
            #look for channel mask sub block
            sub_blocks_data.mark()
            for sub_block in sub_blocks(sub_blocks_data, sub_blocks_size):
                if ((sub_block.metadata_function == 13) and
                    (sub_block.nondecoder_data == 0)):
                    self.channels = sub_block.data.read(8)
                    self.channel_mask = sub_block.data.read(
                        (sub_block.data_size() - 1) * 8)
                    break
            else:
                #FIXME - handle case of no channel mask sub block
                raise NotImplementedError()
            sub_blocks_data.rewind()
            sub_blocks_data.unmark()

        self.reader.rewind()
        self.reader.unmark()

        self.pcm_finished = False
        self.md5_checked = False
        self.md5sum = md5()

    def read(self, bytes):
        if (self.pcm_finished):
            if (not self.md5_checked):
                self.reader.mark()
                try:
                    try:
                        header = Block_Header.read(self.reader)
                        sub_blocks_size = header.block_size - 24
                        sub_blocks_data = self.reader.substream(sub_blocks_size)
                        for sub_block in sub_blocks(sub_blocks_data,
                                                    sub_blocks_size):
                            if ((sub_block.metadata_function == 6) and
                                (sub_block.nondecoder_data == 1)):
                                if (sub_block.data.read_bytes(16) !=
                                    self.md5sum.digest()):
                                    raise ValueError("invalid stream MD5 sum")
                    except (IOError, ValueError):
                        #no error if a block isn't found
                        pass
                finally:
                    self.reader.rewind()
                    self.reader.unmark()
            return from_list([], self.channels, self.bits_per_sample, True)

        channels = []

        while (True):  #in place of a do-while loop
            try:
                block_header = Block_Header.read(self.reader)
            except (ValueError, IOError):
                self.pcm_finished = True
                return from_list([], self.channels, self.bits_per_sample, True)
            sub_blocks_size = block_header.block_size - 24
            sub_blocks_data = self.reader.substream(sub_blocks_size)
            channels.extend(read_block(block_header,
                                       sub_blocks_size,
                                       sub_blocks_data))

            if (block_header.final_block == 1):
                break

        if ((block_header.block_index + block_header.block_samples) >=
            block_header.total_samples):
            self.pcm_finished = True

        #combine channels of audio data into single block
        block = from_channels([from_list(ch, 1, self.bits_per_sample, True)
                               for ch in channels])

        #update MD5 sum
        self.md5sum.update(block.to_bytes(False, self.bits_per_sample > 8))

        #return single block of audio data
        return block

    def close(self):
        self.reader.close()
Beispiel #4
0
class FlacDecoder:
    CHANNEL_COUNT = [1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2,
                     None, None, None, None, None]

    (SUBFRAME_CONSTANT,
     SUBFRAME_VERBATIM,
     SUBFRAME_FIXED,
     SUBFRAME_LPC) = range(4)

    def __init__(self, filename, channel_mask):
        self.reader = BitstreamReader(open(filename, "rb"), 0)

        if (self.reader.read_bytes(4) != 'fLaC'):
            raise ValueError("invalid FLAC file")

        self.current_md5sum = md5()

        #locate the STREAMINFO,
        #which is sometimes needed to handle non-subset streams
        for (block_id,
             block_size,
             block_reader) in self.metadata_blocks(self.reader):
            if (block_id == 0):
                #read STREAMINFO
                self.minimum_block_size = block_reader.read(16)
                self.maximum_block_size = block_reader.read(16)
                self.minimum_frame_size = block_reader.read(24)
                self.maximum_frame_size = block_reader.read(24)
                self.sample_rate = block_reader.read(20)
                self.channels = block_reader.read(3) + 1
                self.channel_mask = channel_mask
                self.bits_per_sample = block_reader.read(5) + 1
                self.total_frames = block_reader.read64(36)
                self.md5sum = block_reader.read_bytes(16)

                #these are frame header lookup tables
                #which vary slightly depending on STREAMINFO's values
                self.BLOCK_SIZE = [self.maximum_block_size,
                                   192,  576,  1152,
                                   2304, 4608,  None,  None,
                                   256,  512,  1024,  2048,
                                   4096, 8192, 16384, 32768]
                self.SAMPLE_RATE = [self.sample_rate,
                                    88200, 176400, 192000,
                                    8000,  16000,  22050, 24000,
                                    32000,  44100,  48000, 96000,
                                    None,   None,   None,  None]
                self.BITS_PER_SAMPLE = [self.bits_per_sample,
                                        8, 12, None, 16, 20, 24, None]

    def metadata_blocks(self, reader):
        """yields a (block_id, block_size, block_reader) tuple
        per metadata block where block_reader is a BitstreamReader substream"""

        (last_block, block_id, block_size) = self.reader.parse("1u 7u 24u")
        while (last_block == 0):
            yield (block_id, block_size, self.reader.substream(block_size))
            (last_block, block_id, block_size) = self.reader.parse("1u 7u 24u")
        else:
            yield (block_id, block_size, self.reader.substream(block_size))

    def read(self, pcm_frames):
        #if the stream is exhausted,
        #verify its MD5 sum and return an empty pcm.FrameList object
        if (self.total_frames < 1):
            if (self.md5sum == self.current_md5sum.digest()):
                return from_list([], self.channels, self.bits_per_sample, True)
            else:
                raise ValueError("MD5 checksum mismatch")

        crc16 = CRC16()
        self.reader.add_callback(crc16.update)

        #fetch the decoding parameters from the frame header
        (block_size,
         channel_assignment,
         bits_per_sample) = self.read_frame_header()
        channel_count = self.CHANNEL_COUNT[channel_assignment]
        if (channel_count is None):
            raise ValueError("invalid channel assignment")

        #channel data will be a list of signed sample lists, one per channel
        #such as  [[1, 2, 3, ...], [4, 5, 6, ...]]  for a 2 channel stream
        channel_data = []

        for channel_number in xrange(channel_count):
            if ((channel_assignment == 0x8) and (channel_number == 1)):
                #for left-difference assignment
                #the difference channel has 1 additional bit
                channel_data.append(self.read_subframe(block_size,
                                                       bits_per_sample + 1))
            elif ((channel_assignment == 0x9) and (channel_number == 0)):
                #for difference-right assignment
                #the difference channel has 1 additional bit
                channel_data.append(self.read_subframe(block_size,
                                                       bits_per_sample + 1))
            elif ((channel_assignment == 0xA) and (channel_number == 1)):
                #for mid-side assignment
                #the side channel has 1 additional bit
                channel_data.append(self.read_subframe(block_size,
                                                       bits_per_sample + 1))
            else:
                #otherwise, use the frame's bits-per-sample value
                channel_data.append(self.read_subframe(block_size,
                                                       bits_per_sample))

        #one all the subframes have been decoded,
        #reconstruct them depending on the channel assignment
        if (channel_assignment == 0x8):
            #left-difference
            samples = []
            for (left, difference) in zip(*channel_data):
                samples.append(left)
                samples.append(left - difference)
        elif (channel_assignment == 0x9):
            #difference-right
            samples = []
            for (difference, right) in zip(*channel_data):
                samples.append(difference + right)
                samples.append(right)
        elif (channel_assignment == 0xA):
            #mid-side
            samples = []
            for (mid, side) in zip(*channel_data):
                samples.append((((mid * 2) + (side % 2)) + side) / 2)
                samples.append((((mid * 2) + (side % 2)) - side) / 2)
        else:
            #independent
            samples = [0] * block_size * channel_count
            for (i, channel) in enumerate(channel_data):
                samples[i::channel_count] = channel

        self.reader.byte_align()

        #read and verify the frame's trailing CRC-16 footer
        self.reader.read(16)
        self.reader.pop_callback()
        if (int(crc16) != 0):
            raise ValueError("CRC16 mismatch in frame footer")

        #deduct the amount of PCM frames from the remaining amount
        self.total_frames -= block_size

        #build a pcm.FrameList object from the combined samples
        framelist = from_list(samples, channel_count, bits_per_sample, True)

        #update the running MD5 sum calculation with the frame's data
        self.current_md5sum.update(framelist.to_bytes(0, 1))

        #and finally return the frame data
        return framelist

    def read_frame_header(self):
        crc8 = CRC8()
        self.reader.add_callback(crc8.update)

        #read the 32-bit FLAC frame header
        sync_code = self.reader.read(14)
        if (sync_code != 0x3FFE):
            raise ValueError("invalid sync code")

        self.reader.skip(1)
        blocking_strategy = self.reader.read(1)
        block_size_bits = self.reader.read(4)
        sample_rate_bits = self.reader.read(4)
        channel_assignment = self.reader.read(4)
        bits_per_sample_bits = self.reader.read(3)
        self.reader.skip(1)

        #the frame number is a UTF-8 encoded value
        #which takes a variable number of whole bytes
        frame_number = self.read_utf8()

        #unpack the 4 bit block size field
        #which is the total PCM frames in the FLAC frame
        #and may require up to 16 more bits if the frame is usually-sized
        #(which typically happens at the end of the stream)
        if (block_size_bits == 0x6):
            block_size = self.reader.read(8) + 1
        elif (block_size_bits == 0x7):
            block_size = self.reader.read(16) + 1
        else:
            block_size = self.BLOCK_SIZE[block_size_bits]

        #unpack the 4 bit sample rate field
        #which is used for playback, but not needed for decoding
        #and may require up to 16 more bits
        #if the stream has a particularly unusual sample rate
        if (sample_rate_bits == 0xC):
            sample_rate = self.reader.read(8) * 1000
        elif (sample_rate_bits == 0xD):
            sample_rate = self.reader.read(16)
        elif (sample_rate_bits == 0xE):
            sample_rate = self.reader.read(16) * 10
        elif (sample_rate_bits == 0xF):
            raise ValueError("invalid sample rate")
        else:
            sample_rate = self.SAMPLE_RATE[sample_rate_bits]

        #unpack the 3 bit bits-per-sample field
        #this never requires additional bits
        if ((bits_per_sample_bits == 0x3) or (bits_per_sample_bits == 0x7)):
            raise ValueError("invalid bits per sample")
        else:
            bits_per_sample = self.BITS_PER_SAMPLE[bits_per_sample_bits]

        #read and verify frame's CRC-8 value
        self.reader.read(8)
        self.reader.pop_callback()
        if (int(crc8) != 0):
            raise ValueError("CRC8 mismatch in frame header")

        return (block_size, channel_assignment, bits_per_sample)

    def read_subframe_header(self):
        """returns a tuple of (subframe_type, subframe_order, wasted_bps)"""

        self.reader.skip(1)
        subframe_type = self.reader.read(6)
        if (self.reader.read(1) == 1):
            wasted_bps = self.reader.unary(1) + 1
        else:
            wasted_bps = 0

        #extract "order" value from 6 bit subframe type, if necessary
        if (subframe_type == 0):
            return (self.SUBFRAME_CONSTANT, None, wasted_bps)
        elif (subframe_type == 1):
            return (self.SUBFRAME_VERBATIM, None, wasted_bps)
        elif ((subframe_type & 0x38) == 0x08):
            return (self.SUBFRAME_FIXED, subframe_type & 0x07, wasted_bps)
        elif ((subframe_type & 0x20) == 0x20):
            return (self.SUBFRAME_LPC, (subframe_type & 0x1F) + 1, wasted_bps)
        else:
            raise ValueError("invalid subframe type")

    def read_subframe(self, block_size, bits_per_sample):
        (subframe_type,
         subframe_order,
         wasted_bps) = self.read_subframe_header()

        #read a list of signed sample values
        #depending on the subframe type, block size,
        #adjusted bits per sample and optional subframe order
        if (subframe_type == self.SUBFRAME_CONSTANT):
            subframe_samples = self.read_constant_subframe(
                block_size, bits_per_sample - wasted_bps)
        elif (subframe_type == self.SUBFRAME_VERBATIM):
            subframe_samples = self.read_verbatim_subframe(
                block_size, bits_per_sample - wasted_bps)
        elif (subframe_type == self.SUBFRAME_FIXED):
            subframe_samples = self.read_fixed_subframe(
                block_size, bits_per_sample - wasted_bps, subframe_order)
        else:
            subframe_samples = self.read_lpc_subframe(
                block_size, bits_per_sample - wasted_bps, subframe_order)

        #account for wasted bits-per-sample, if necessary
        if (wasted_bps):
            return [sample << wasted_bps for sample in subframe_samples]
        else:
            return subframe_samples

    def read_constant_subframe(self, block_size, bits_per_sample):
        sample = self.reader.read_signed(bits_per_sample)
        return [sample] * block_size

    def read_verbatim_subframe(self, block_size, bits_per_sample):
        return [self.reader.read_signed(bits_per_sample)
                for x in xrange(block_size)]

    def read_fixed_subframe(self, block_size, bits_per_sample, order):
        #"order" number of warm-up samples
        samples = [self.reader.read_signed(bits_per_sample)
                   for i in xrange(order)]

        #"block_size" - "order" number of residual values
        residuals = self.read_residual(block_size, order)

        #which are applied to the warm-up samples
        #depending on the FIXED subframe order
        #and results in "block_size" number of total samples
        if (order == 0):
            return residuals
        elif (order == 1):
            for residual in residuals:
                samples.append(
                    samples[-1] +
                    residual)
            return samples
        elif (order == 2):
            for residual in residuals:
                samples.append(
                    (2 * samples[-1]) -
                    samples[-2] +
                    residual)
            return samples
        elif (order == 3):
            for residual in residuals:
                samples.append(
                    (3 * samples[-1]) -
                    (3 * samples[-2]) +
                    samples[-3] +
                    residual)
            return samples
        elif (order == 4):
            for residual in residuals:
                samples.append(
                    (4 * samples[-1]) -
                    (6 * samples[-2]) +
                    (4 * samples[-3]) -
                    samples[-4] +
                    residual)
            return samples
        else:
            raise ValueError("unsupported FIXED subframe order")

    def read_lpc_subframe(self, block_size, bits_per_sample, order):
        #"order" number of warm-up samples
        samples = [self.reader.read_signed(bits_per_sample)
                   for i in xrange(order)]

        #the size of each QLP coefficient, in bits
        qlp_precision = self.reader.read(4)

        #the amount of right shift to apply
        #during LPC calculation
        #(though this is a signed value, negative shifts are noops
        # in the reference FLAC decoder)
        qlp_shift_needed = max(self.reader.read_signed(5), 0)

        #"order" number of signed QLP coefficients
        qlp_coeffs = [self.reader.read_signed(qlp_precision + 1)
                      for i in xrange(order)]
        #QLP coefficients are applied in reverse order
        qlp_coeffs.reverse()

        #"block_size" - "order" number of residual values
        residuals = self.read_residual(block_size, order)

        #which are applied to the running LPC calculation
        for residual in residuals:
            samples.append((sum([coeff * sample for (coeff, sample) in
                                 zip(qlp_coeffs, samples[-order:])]) >>
                            qlp_shift_needed) + residual)

        return samples

    def read_residual(self, block_size, order):
        residuals = []

        coding_method = self.reader.read(2)
        partition_order = self.reader.read(4)

        #each parititon contains  block_size / 2 ** partition_order
        #number of residuals
        for partition_number in xrange(2 ** partition_order):
            if (partition_number == 0):
                #except for the first partition
                #which contains "order" less than the rest
                residuals.extend(
                    self.read_residual_partition(
                        coding_method,
                        (block_size / 2 ** partition_order) - order))
            else:
                residuals.extend(
                    self.read_residual_partition(
                        coding_method,
                        block_size / 2 ** partition_order))

        return residuals

    def read_residual_partition(self, coding_method, residual_count):
        if (coding_method == 0):
            #the Rice parameters determines the number of
            #least-significant bits to read for each residual
            rice_parameter = self.reader.read(4)
            if (rice_parameter == 0xF):
                escape_code = self.reader.read(5)
                return [self.reader.read_signed(escape_code)
                        for i in xrange(residual_count)]
        elif (coding_method == 1):
            #24 bps streams may use a 5-bit Rice parameter
            #for better compression
            rice_parameter = self.reader.read(5)
            if (rice_parameter == 0x1F):
                escape_code = self.reader.read(5)
                return [self.reader.read_signed(escape_code)
                        for i in xrange(residual_count)]
        else:
            raise ValueError("invalid Rice coding parameter")

        #a list of signed residual values
        partition_residuals = []

        for i in xrange(residual_count):
            msb = self.reader.unary(1)              # most-significant bits
            lsb = self.reader.read(rice_parameter)  # least-significant bits
            value = (msb << rice_parameter) | lsb   # combined into a value
            if (value & 1):   # whose least-significant bit is the sign value
                partition_residuals.append(-(value >> 1) - 1)
            else:
                partition_residuals.append(value >> 1)

        return partition_residuals

    def read_utf8(self):
        total_bytes = self.reader.unary(0)
        value = self.reader.read(7 - total_bytes)
        while (total_bytes > 1):
            value = ((value << 6) | self.reader.parse("2p 6u")[0])
            total_bytes -= 1
        return value

    def close(self):
        self.reader.close()
Beispiel #5
0
    def __init__(self, filename):
        """filename is a plain string"""

        from audiotools.bitstream import BitstreamReader
        from audiotools import ChannelMask
        from io import BytesIO

        WaveContainer.__init__(self, filename)
        try:
            f = open(filename, 'rb')
        except IOError as msg:
            raise InvalidShorten(str(msg))

        reader = BitstreamReader(f, 0)
        try:
            if (reader.parse("4b 8u") != ["ajkg", 2]):
                raise InvalidShorten("invalid Shorten header")
        except IOError:
            raise InvalidShorten("invalid Shorten header")

        def read_unsigned(r, c):
            MSB = r.unary(1)
            LSB = r.read(c)
            return MSB * 2 ** c + LSB

        def read_long(r):
            return read_unsigned(r, read_unsigned(r, 2))

        # populate channels and bits_per_sample from Shorten header
        (file_type,
         self.__channels__,
         block_length,
         max_LPC,
         number_of_means,
         bytes_to_skip) = [read_long(reader) for i in range(6)]

        if ((1 <= file_type) and (file_type <= 2)):
            self.__bits_per_sample__ = 8
        elif ((3 <= file_type) and (file_type <= 6)):
            self.__bits_per_sample__ = 16
        else:
            # FIXME
            raise InvalidShorten("unsupported Shorten file type")

        # setup some default dummy metadata
        self.__sample_rate__ = 44100
        if (self.__channels__ == 1):
            self.__channel_mask__ = ChannelMask(0x4)
        elif (self.__channels__ == 2):
            self.__channel_mask__ = ChannelMask(0x3)
        else:
            self.__channel_mask__ = ChannelMask(0)
        self.__total_frames__ = 0

        # populate sample_rate and total_frames from first VERBATIM command
        command = read_unsigned(reader, 2)
        if (command == 9):
            verbatim_bytes = "".join([chr(read_unsigned(reader, 8) & 0xFF)
                                      for i in range(read_unsigned(reader,
                                                                   5))])
            try:
                wave = BitstreamReader(BytesIO(verbatim_bytes), 1)
                header = wave.read_bytes(12)
                if (header.startswith("RIFF") and header.endswith("WAVE")):
                    # got RIFF/WAVE header, so parse wave blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size >= 8):
                        (chunk_id, chunk_size) = wave.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == 'fmt '):
                            from audiotools.wav import parse_fmt

                            (channels,
                             self.__sample_rate__,
                             bits_per_sample,
                             self.__channel_mask__) = parse_fmt(
                                wave.substream(chunk_size))
                        elif (chunk_id == 'data'):
                            self.__total_frames__ = \
                                (chunk_size //
                                 (self.__channels__ *
                                  (self.__bits_per_sample__ // 8)))
                        else:
                            if (chunk_size % 2):
                                wave.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                wave.read_bytes(chunk_size)
                                total_size -= chunk_size
            except (IOError, ValueError):
                pass

            try:
                aiff = BitstreamReader(BytesIO(verbatim_bytes), 0)
                header = aiff.read_bytes(12)
                if (header.startswith("FORM") and header.endswith("AIFF")):
                    # got FORM/AIFF header, so parse aiff blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size >= 8):
                        (chunk_id, chunk_size) = aiff.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == 'COMM'):
                            from audiotools.aiff import parse_comm

                            (channels,
                             total_sample_frames,
                             bits_per_sample,
                             self.__sample_rate__,
                             self.__channel_mask__) = parse_comm(
                                aiff.substream(chunk_size))
                        elif (chunk_id == 'SSND'):
                            # subtract 8 bytes for "offset" and "block size"
                            self.__total_frames__ = \
                                ((chunk_size - 8) //
                                 (self.__channels__ *
                                  (self.__bits_per_sample__ // 8)))
                        else:
                            if (chunk_size % 2):
                                aiff.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                aiff.read_bytes(chunk_size)
                                total_size -= chunk_size
            except IOError:
                pass
Beispiel #6
0
class TTADecoder(object):
    def __init__(self, filename):
        self.reader = BitstreamReader(open(filename, "rb"), True)
        crc = CRC32()
        self.reader.add_callback(crc.update)

        # read the header
        (signature, format_, self.channels, self.bits_per_sample,
         self.sample_rate,
         self.total_pcm_frames) = self.reader.parse("4b 16u 16u 16u 32u 32u")

        self.reader.pop_callback()
        header_crc = self.reader.read(32)
        if (int(crc) != header_crc):
            raise ValueError("CRC32 mismatch in header (0x%8.8X != 0x%8.8X)" %
                             (header_crc, int(crc)))

        self.channel_mask = {1: 0x4, 2: 0x3}.get(self.channels, 0)

        total_tta_frames = div_ceil(self.total_pcm_frames * 245,
                                    self.sample_rate * 256)

        self.pcm_frames_per_tta_frame = (self.sample_rate * 256) // 245

        # read the seektable
        crc = CRC32()
        self.reader.add_callback(crc.update)
        self.frame_sizes = [
            self.reader.read(32) for i in range(total_tta_frames)
        ]
        self.reader.pop_callback()
        seektable_crc = self.reader.read(32)
        if (int(crc) != seektable_crc):
            raise ValueError(
                "CRC32 mismatch in seektable (0x%8.8X != 0x%8.8X)" %
                (header_crc, int(crc)))

        self.current_tta_frame = 0

    def read(self, pcm_frames):
        if (self.total_pcm_frames == 0):
            return FrameList("", self.channels, self.bits_per_sample, True,
                             True)

        pcm_frames = min(self.pcm_frames_per_tta_frame, self.total_pcm_frames)

        frame_reader = self.reader.substream(
            self.frame_sizes[self.current_tta_frame])
        crc = CRC32()
        frame_reader.add_callback(crc.update)

        self.total_pcm_frames -= pcm_frames
        self.current_tta_frame += 1

        # setup Rice parameters for each channel
        k0 = [10] * self.channels
        k1 = [10] * self.channels
        sum0 = [2**14] * self.channels
        sum1 = [2**14] * self.channels

        # list of unfiltered output for each channel
        unfiltered = [[] for i in range(self.channels)]

        for f in range(pcm_frames):
            correlated = []

            for (c, ch_output) in enumerate(unfiltered):
                # read most-significant bits
                MSB = frame_reader.unary(0)
                if (MSB == 0):
                    # read least-significant bits
                    unsigned = frame_reader.read(k0[c])
                else:
                    # read least-significant bits
                    LSB = frame_reader.read(k1[c])
                    unshifted = ((MSB - 1) << k1[c]) + LSB
                    unsigned = unshifted + (1 << k0[c])

                    # adjust sum1 and k1
                    sum1[c] += (unshifted - (sum1[c] >> 4))
                    if (sum1[c] < (2**(k1[c] + 4))):
                        k1[c] = max(k1[c] - 1, 0)
                    elif (sum1[c] > (2**(k1[c] + 5))):
                        k1[c] += 1

                # adjust sum0 and k0
                sum0[c] += (unsigned - (sum0[c] >> 4))
                if (sum0[c] < (2**(k0[c] + 4))):
                    k0[c] = max(k0[c] - 1, 0)
                elif (sum0[c] > (2**(k0[c] + 5))):
                    k0[c] += 1

                # apply sign bit
                if ((unsigned % 2) == 1):
                    # positive
                    ch_output.append((unsigned + 1) // 2)
                else:
                    # negative
                    ch_output.append(-(unsigned // 2))

        # check frame's trailing CRC32 now that reading is finished
        frame_reader.byte_align()
        frame_reader.pop_callback()
        frame_crc = frame_reader.read(32)
        if (int(crc) != frame_crc):
            raise ValueError("CRC32 mismatch in frame (0x%8.8X != 0x%8.8X)" %
                             (frame_crc, int(crc)))

        # run hybrid filter on each channel
        filtered = []
        for unfiltered_ch in unfiltered:
            filtered.append(tta_filter(self.bits_per_sample, unfiltered_ch))

        # run fixed order prediction on each channel
        predicted = []
        for filtered_ch in filtered:
            predicted.append(fixed_predictor(self.bits_per_sample,
                                             filtered_ch))

        if (self.channels == 1):
            # send channel as-is
            return from_list(predicted[0], 1, self.bits_per_sample, True)
        else:
            # decorrelate channels
            decorrelated = decorrelate(predicted)

            # return all channels as single FrameList
            return from_channels([
                from_list(decorrelated_ch, 1, self.bits_per_sample, True)
                for decorrelated_ch in decorrelated
            ])

    def close(self):
        # FIXME
        pass
Beispiel #7
0
    def read_metadata(self):
        from io import BytesIO

        command = self.unsigned(2)
        if command == 9:
            # got verbatim, so read data
            verbatim_bytes = ints_to_bytes([self.unsigned(8) & 0xFF
                                            for i in range(self.unsigned(5))])

            try:
                wave = BitstreamReader(BytesIO(verbatim_bytes), True)
                header = wave.read_bytes(12)
                if header.startswith(b"RIFF") and header.endswith(b"WAVE"):
                    # got RIFF/WAVE header, so parse wave blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while total_size > 0:
                        (chunk_id, chunk_size) = wave.parse("4b 32u")
                        total_size -= 8
                        if chunk_id == b'fmt ':
                            (channels,
                             self.sample_rate,
                             bits_per_sample,
                             channel_mask) = parse_fmt(
                                wave.substream(chunk_size))
                            self.channel_mask = int(channel_mask)
                            return
                        else:
                            if chunk_size % 2:
                                wave.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                wave.read_bytes(chunk_size)
                                total_size -= chunk_size
                    else:
                        # no fmt chunk, so use default metadata
                        pass
            except (IOError, ValueError):
                pass

            try:
                aiff = BitstreamReader(BytesIO(verbatim_bytes), False)
                header = aiff.read_bytes(12)
                if header.startswith(b"FORM") and header.endswith(b"AIFF"):
                    # got FORM/AIFF header, so parse aiff blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while total_size > 0:
                        (chunk_id, chunk_size) = aiff.parse("4b 32u")
                        total_size -= 8
                        if chunk_id == b'COMM':
                            (channels,
                             total_sample_frames,
                             bits_per_sample,
                             self.sample_rate,
                             channel_mask) = parse_comm(
                                aiff.substream(chunk_size))
                            self.channel_mask = int(channel_mask)
                            return
                        else:
                            if chunk_size % 2:
                                aiff.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                aiff.read_bytes(chunk_size)
                                total_size -= chunk_size
                    else:
                        # no COMM chunk, so use default metadata
                        pass
            except IOError:
                pass

        # got something else, so invent some PCM parameters
        self.sample_rate = 44100
        if self.channels == 1:
            self.channel_mask = 0x4
        elif self.channels == 2:
            self.channel_mask = 0x3
        else:
            self.channel_mask = 0
Beispiel #8
0
    def __init__(self, filename):
        """filename is a plain string"""

        from audiotools.bitstream import BitstreamReader
        from audiotools import ChannelMask
        from io import BytesIO

        WaveContainer.__init__(self, filename)
        try:
            f = open(filename, 'rb')
        except IOError as msg:
            raise InvalidShorten(str(msg))

        reader = BitstreamReader(f, 0)
        try:
            if (reader.parse("4b 8u") != ["ajkg", 2]):
                raise InvalidShorten("invalid Shorten header")
        except IOError:
            raise InvalidShorten("invalid Shorten header")

        def read_unsigned(r, c):
            MSB = r.unary(1)
            LSB = r.read(c)
            return MSB * 2**c + LSB

        def read_long(r):
            return read_unsigned(r, read_unsigned(r, 2))

        # populate channels and bits_per_sample from Shorten header
        (file_type, self.__channels__, block_length, max_LPC, number_of_means,
         bytes_to_skip) = [read_long(reader) for i in range(6)]

        if ((1 <= file_type) and (file_type <= 2)):
            self.__bits_per_sample__ = 8
        elif ((3 <= file_type) and (file_type <= 6)):
            self.__bits_per_sample__ = 16
        else:
            # FIXME
            raise InvalidShorten("unsupported Shorten file type")

        # setup some default dummy metadata
        self.__sample_rate__ = 44100
        if (self.__channels__ == 1):
            self.__channel_mask__ = ChannelMask(0x4)
        elif (self.__channels__ == 2):
            self.__channel_mask__ = ChannelMask(0x3)
        else:
            self.__channel_mask__ = ChannelMask(0)
        self.__total_frames__ = 0

        # populate sample_rate and total_frames from first VERBATIM command
        command = read_unsigned(reader, 2)
        if (command == 9):
            verbatim_bytes = "".join([
                chr(read_unsigned(reader, 8) & 0xFF)
                for i in range(read_unsigned(reader, 5))
            ])
            try:
                wave = BitstreamReader(BytesIO(verbatim_bytes), 1)
                header = wave.read_bytes(12)
                if (header.startswith("RIFF") and header.endswith("WAVE")):
                    # got RIFF/WAVE header, so parse wave blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size >= 8):
                        (chunk_id, chunk_size) = wave.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == 'fmt '):
                            from audiotools.wav import parse_fmt

                            (channels, self.__sample_rate__, bits_per_sample,
                             self.__channel_mask__) = parse_fmt(
                                 wave.substream(chunk_size))
                        elif (chunk_id == 'data'):
                            self.__total_frames__ = \
                                (chunk_size //
                                 (self.__channels__ *
                                  (self.__bits_per_sample__ // 8)))
                        else:
                            if (chunk_size % 2):
                                wave.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                wave.read_bytes(chunk_size)
                                total_size -= chunk_size
            except (IOError, ValueError):
                pass

            try:
                aiff = BitstreamReader(BytesIO(verbatim_bytes), 0)
                header = aiff.read_bytes(12)
                if (header.startswith("FORM") and header.endswith("AIFF")):
                    # got FORM/AIFF header, so parse aiff blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size >= 8):
                        (chunk_id, chunk_size) = aiff.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == 'COMM'):
                            from audiotools.aiff import parse_comm

                            (channels, total_sample_frames, bits_per_sample,
                             self.__sample_rate__,
                             self.__channel_mask__) = parse_comm(
                                 aiff.substream(chunk_size))
                        elif (chunk_id == 'SSND'):
                            # subtract 8 bytes for "offset" and "block size"
                            self.__total_frames__ = \
                                ((chunk_size - 8) //
                                 (self.__channels__ *
                                  (self.__bits_per_sample__ // 8)))
                        else:
                            if (chunk_size % 2):
                                aiff.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                aiff.read_bytes(chunk_size)
                                total_size -= chunk_size
            except IOError:
                pass
Beispiel #9
0
class TTADecoder:
    def __init__(self, filename):
        self.reader = BitstreamReader(open(filename, "rb"), True)
        crc = CRC32()
        self.reader.add_callback(crc.update)

        #read the header
        (signature,
         format_,
         self.channels,
         self.bits_per_sample,
         self.sample_rate,
         self.total_pcm_frames) = self.reader.parse(
            "4b 16u 16u 16u 32u 32u")

        self.reader.pop_callback()
        header_crc = self.reader.read(32)
        if (int(crc) != header_crc):
            raise ValueError(
                "CRC32 mismatch in header (0x%8.8X != 0x%8.8X)" %
                (header_crc, int(crc)))

        self.channel_mask = {1:0x4, 2:0x3}.get(self.channels, 0)

        total_tta_frames = div_ceil(self.total_pcm_frames * 245,
                                    self.sample_rate * 256)

        self.pcm_frames_per_tta_frame = (self.sample_rate * 256) / 245

        #read the seektable
        crc = CRC32()
        self.reader.add_callback(crc.update)
        self.frame_sizes = [self.reader.read(32) for i in
                            xrange(total_tta_frames)]
        self.reader.pop_callback()
        seektable_crc = self.reader.read(32)
        if (int(crc) != seektable_crc):
            raise ValueError(
                "CRC32 mismatch in seektable (0x%8.8X != 0x%8.8X)" %
                (header_crc, int(crc)))

        self.current_tta_frame = 0

    def read(self, pcm_frames):
        if (self.total_pcm_frames == 0):
            return FrameList("",
                             self.channels,
                             self.bits_per_sample,
                             True,
                             True)

        pcm_frames = min(self.pcm_frames_per_tta_frame, self.total_pcm_frames)

        frame_reader = self.reader.substream(
            self.frame_sizes[self.current_tta_frame])
        crc = CRC32()
        frame_reader.add_callback(crc.update)

        self.total_pcm_frames -= pcm_frames
        self.current_tta_frame += 1

        #setup Rice parameters for each channel
        k0 = [10] * self.channels
        k1 = [10] * self.channels
        sum0 = [2 ** 14] * self.channels
        sum1 = [2 ** 14] * self.channels

        #list of unfiltered output for each channel
        unfiltered = [[] for i in xrange(self.channels)]

        for f in xrange(pcm_frames):
            correlated = []

            for (c, ch_output) in enumerate(unfiltered):
                #read most-significant bits
                MSB = frame_reader.unary(0)
                if (MSB == 0):
                    #read least-significant bits
                    unsigned = frame_reader.read(k0[c])
                else:
                    #read least-significant bits
                    LSB = frame_reader.read(k1[c])
                    unshifted = ((MSB - 1) << k1[c]) + LSB
                    unsigned = unshifted + (1 << k0[c])

                    #adjust sum1 and k1
                    sum1[c] += (unshifted - (sum1[c] >> 4))
                    if (sum1[c] < (2 ** (k1[c] + 4))):
                        k1[c] = max(k1[c] - 1, 0)
                    elif (sum1[c] > (2 ** (k1[c] + 5))):
                        k1[c] += 1

                #adjust sum0 and k0
                sum0[c] += (unsigned - (sum0[c] >> 4))
                if (sum0[c] < (2 ** (k0[c] + 4))):
                    k0[c] = max(k0[c] - 1, 0)
                elif (sum0[c] > (2 ** (k0[c] + 5))):
                    k0[c] += 1

                #apply sign bit
                if ((unsigned % 2) == 1):
                    #positive
                    ch_output.append((unsigned + 1) / 2)
                else:
                    #negative
                    ch_output.append(-(unsigned / 2))

        #check frame's trailing CRC32 now that reading is finished
        frame_reader.byte_align()
        frame_reader.pop_callback()
        frame_crc = frame_reader.read(32)
        if (int(crc) != frame_crc):
            raise ValueError("CRC32 mismatch in frame (0x%8.8X != 0x%8.8X)" %
                             (frame_crc, int(crc)))

        #run hybrid filter on each channel
        filtered = []
        for unfiltered_ch in unfiltered:
            filtered.append(
                tta_filter(self.bits_per_sample, unfiltered_ch))

        #run fixed order prediction on each channel
        predicted = []
        for filtered_ch in filtered:
            predicted.append(
                fixed_predictor(self.bits_per_sample, filtered_ch))

        if (self.channels == 1):
            #send channel as-is
            return from_list(predicted[0],
                             1,
                             self.bits_per_sample,
                             True)
        else:
            #decorrelate channels
            decorrelated = decorrelate(predicted)

            #return all channels as single FrameList
            return from_channels([from_list(decorrelated_ch,
                                            1,
                                            self.bits_per_sample,
                                            True)
                                  for decorrelated_ch in decorrelated])

    def close(self):
        #FIXME
        pass
Beispiel #10
0
class FlacDecoder(object):
    CHANNEL_COUNT = [
        1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2, None, None, None, None, None
    ]

    (SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED,
     SUBFRAME_LPC) = range(4)

    def __init__(self, filename, channel_mask):
        self.reader = BitstreamReader(open(filename, "rb"), False)

        if (self.reader.read_bytes(4) != b'fLaC'):
            raise ValueError("invalid FLAC file")

        self.current_md5sum = md5()

        # locate the STREAMINFO,
        # which is sometimes needed to handle non-subset streams
        for (block_id, block_size,
             block_reader) in self.metadata_blocks(self.reader):
            if (block_id == 0):
                # read STREAMINFO
                self.minimum_block_size = block_reader.read(16)
                self.maximum_block_size = block_reader.read(16)
                self.minimum_frame_size = block_reader.read(24)
                self.maximum_frame_size = block_reader.read(24)
                self.sample_rate = block_reader.read(20)
                self.channels = block_reader.read(3) + 1
                self.channel_mask = channel_mask
                self.bits_per_sample = block_reader.read(5) + 1
                self.total_frames = block_reader.read(36)
                self.md5sum = block_reader.read_bytes(16)

                # these are frame header lookup tables
                # which vary slightly depending on STREAMINFO's values
                self.BLOCK_SIZE = [
                    self.maximum_block_size, 192, 576, 1152, 2304, 4608, None,
                    None, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
                ]
                self.SAMPLE_RATE = [
                    self.sample_rate, 88200, 176400, 192000, 8000, 16000,
                    22050, 24000, 32000, 44100, 48000, 96000, None, None, None,
                    None
                ]
                self.BITS_PER_SAMPLE = [
                    self.bits_per_sample, 8, 12, None, 16, 20, 24, None
                ]

    def metadata_blocks(self, reader):
        """yields a (block_id, block_size, block_reader) tuple
        per metadata block where block_reader is a BitstreamReader substream"""

        (last_block, block_id, block_size) = self.reader.parse("1u 7u 24u")
        while (last_block == 0):
            yield (block_id, block_size, self.reader.substream(block_size))
            (last_block, block_id, block_size) = self.reader.parse("1u 7u 24u")
        else:
            yield (block_id, block_size, self.reader.substream(block_size))

    def read(self, pcm_frames):
        # if the stream is exhausted,
        # verify its MD5 sum and return an empty pcm.FrameList object
        if (self.total_frames < 1):
            if (self.md5sum == self.current_md5sum.digest()):
                return empty_framelist(self.channels, self.bits_per_sample)
            else:
                raise ValueError("MD5 checksum mismatch")

        crc16 = CRC16()
        self.reader.add_callback(crc16.update)

        # fetch the decoding parameters from the frame header
        (block_size, channel_assignment,
         bits_per_sample) = self.read_frame_header()
        channel_count = self.CHANNEL_COUNT[channel_assignment]
        if (channel_count is None):
            raise ValueError("invalid channel assignment")

        # channel data will be a list of signed sample lists, one per channel
        # such as  [[1, 2, 3, ...], [4, 5, 6, ...]]  for a 2 channel stream
        channel_data = []

        for channel_number in range(channel_count):
            if ((channel_assignment == 0x8) and (channel_number == 1)):
                # for left-difference assignment
                # the difference channel has 1 additional bit
                channel_data.append(
                    self.read_subframe(block_size, bits_per_sample + 1))
            elif ((channel_assignment == 0x9) and (channel_number == 0)):
                # for difference-right assignment
                # the difference channel has 1 additional bit
                channel_data.append(
                    self.read_subframe(block_size, bits_per_sample + 1))
            elif ((channel_assignment == 0xA) and (channel_number == 1)):
                # for average-difference assignment
                # the difference channel has 1 additional bit
                channel_data.append(
                    self.read_subframe(block_size, bits_per_sample + 1))
            else:
                # otherwise, use the frame's bits-per-sample value
                channel_data.append(
                    self.read_subframe(block_size, bits_per_sample))

        # one all the subframes have been decoded,
        # reconstruct them depending on the channel assignment
        if (channel_assignment == 0x8):
            # left-difference
            samples = []
            for (left, difference) in zip(*channel_data):
                samples.append(left)
                samples.append(left - difference)
        elif (channel_assignment == 0x9):
            # difference-right
            samples = []
            for (difference, right) in zip(*channel_data):
                samples.append(difference + right)
                samples.append(right)
        elif (channel_assignment == 0xA):
            # mid-side
            samples = []
            for (mid, side) in zip(*channel_data):
                samples.append((((mid * 2) + (side % 2)) + side) // 2)
                samples.append((((mid * 2) + (side % 2)) - side) // 2)
        else:
            # independent
            samples = [0] * block_size * channel_count
            for (i, channel) in enumerate(channel_data):
                samples[i::channel_count] = channel

        self.reader.byte_align()

        # read and verify the frame's trailing CRC-16 footer
        self.reader.read(16)
        self.reader.pop_callback()
        if (int(crc16) != 0):
            raise ValueError("CRC16 mismatch in frame footer")

        # deduct the amount of PCM frames from the remaining amount
        self.total_frames -= block_size

        # build a pcm.FrameList object from the combined samples
        framelist = from_list(samples, channel_count, bits_per_sample, True)

        # update the running MD5 sum calculation with the frame's data
        self.current_md5sum.update(framelist.to_bytes(0, 1))

        # and finally return the frame data
        return framelist

    def read_frame_header(self):
        crc8 = CRC8()
        self.reader.add_callback(crc8.update)

        # read the 32-bit FLAC frame header
        sync_code = self.reader.read(14)
        if (sync_code != 0x3FFE):
            raise ValueError("invalid sync code")

        self.reader.skip(1)
        blocking_strategy = self.reader.read(1)
        block_size_bits = self.reader.read(4)
        sample_rate_bits = self.reader.read(4)
        channel_assignment = self.reader.read(4)
        bits_per_sample_bits = self.reader.read(3)
        self.reader.skip(1)

        # the frame number is a UTF-8 encoded value
        # which takes a variable number of whole bytes
        frame_number = self.read_utf8()

        # unpack the 4 bit block size field
        # which is the total PCM frames in the FLAC frame
        # and may require up to 16 more bits if the frame is usually-sized
        # (which typically happens at the end of the stream)
        if (block_size_bits == 0x6):
            block_size = self.reader.read(8) + 1
        elif (block_size_bits == 0x7):
            block_size = self.reader.read(16) + 1
        else:
            block_size = self.BLOCK_SIZE[block_size_bits]

        # unpack the 4 bit sample rate field
        # which is used for playback, but not needed for decoding
        # and may require up to 16 more bits
        # if the stream has a particularly unusual sample rate
        if (sample_rate_bits == 0xC):
            sample_rate = self.reader.read(8) * 1000
        elif (sample_rate_bits == 0xD):
            sample_rate = self.reader.read(16)
        elif (sample_rate_bits == 0xE):
            sample_rate = self.reader.read(16) * 10
        elif (sample_rate_bits == 0xF):
            raise ValueError("invalid sample rate")
        else:
            sample_rate = self.SAMPLE_RATE[sample_rate_bits]

        # unpack the 3 bit bits-per-sample field
        # this never requires additional bits
        if ((bits_per_sample_bits == 0x3) or (bits_per_sample_bits == 0x7)):
            raise ValueError("invalid bits per sample")
        else:
            bits_per_sample = self.BITS_PER_SAMPLE[bits_per_sample_bits]

        # read and verify frame's CRC-8 value
        self.reader.read(8)
        self.reader.pop_callback()
        if (int(crc8) != 0):
            raise ValueError("CRC8 mismatch in frame header")

        return (block_size, channel_assignment, bits_per_sample)

    def read_subframe_header(self):
        """returns a tuple of (subframe_type, subframe_order, wasted_bps)"""

        self.reader.skip(1)
        subframe_type = self.reader.read(6)
        if (self.reader.read(1) == 1):
            wasted_bps = self.reader.unary(1) + 1
        else:
            wasted_bps = 0

        # extract "order" value from 6 bit subframe type, if necessary
        if (subframe_type == 0):
            return (self.SUBFRAME_CONSTANT, None, wasted_bps)
        elif (subframe_type == 1):
            return (self.SUBFRAME_VERBATIM, None, wasted_bps)
        elif ((subframe_type & 0x38) == 0x08):
            return (self.SUBFRAME_FIXED, subframe_type & 0x07, wasted_bps)
        elif ((subframe_type & 0x20) == 0x20):
            return (self.SUBFRAME_LPC, (subframe_type & 0x1F) + 1, wasted_bps)
        else:
            raise ValueError("invalid subframe type")

    def read_subframe(self, block_size, bits_per_sample):
        (subframe_type, subframe_order,
         wasted_bps) = self.read_subframe_header()

        # read a list of signed sample values
        # depending on the subframe type, block size,
        # adjusted bits per sample and optional subframe order
        if (subframe_type == self.SUBFRAME_CONSTANT):
            subframe_samples = self.read_constant_subframe(
                block_size, bits_per_sample - wasted_bps)
        elif (subframe_type == self.SUBFRAME_VERBATIM):
            subframe_samples = self.read_verbatim_subframe(
                block_size, bits_per_sample - wasted_bps)
        elif (subframe_type == self.SUBFRAME_FIXED):
            subframe_samples = self.read_fixed_subframe(
                block_size, bits_per_sample - wasted_bps, subframe_order)
        else:
            subframe_samples = self.read_lpc_subframe(
                block_size, bits_per_sample - wasted_bps, subframe_order)

        # account for wasted bits-per-sample, if necessary
        if (wasted_bps):
            return [sample << wasted_bps for sample in subframe_samples]
        else:
            return subframe_samples

    def read_constant_subframe(self, block_size, bits_per_sample):
        sample = self.reader.read_signed(bits_per_sample)
        return [sample] * block_size

    def read_verbatim_subframe(self, block_size, bits_per_sample):
        return [
            self.reader.read_signed(bits_per_sample) for x in range(block_size)
        ]

    def read_fixed_subframe(self, block_size, bits_per_sample, order):
        # "order" number of warm-up samples
        samples = [
            self.reader.read_signed(bits_per_sample) for i in range(order)
        ]

        # "block_size" - "order" number of residual values
        residuals = self.read_residual(block_size, order)

        # which are applied to the warm-up samples
        # depending on the FIXED subframe order
        # and results in "block_size" number of total samples
        if (order == 0):
            return residuals
        elif (order == 1):
            for residual in residuals:
                samples.append(samples[-1] + residual)
            return samples
        elif (order == 2):
            for residual in residuals:
                samples.append((2 * samples[-1]) - samples[-2] + residual)
            return samples
        elif (order == 3):
            for residual in residuals:
                samples.append((3 * samples[-1]) - (3 * samples[-2]) +
                               samples[-3] + residual)
            return samples
        elif (order == 4):
            for residual in residuals:
                samples.append((4 * samples[-1]) - (6 * samples[-2]) +
                               (4 * samples[-3]) - samples[-4] + residual)
            return samples
        else:
            raise ValueError("unsupported FIXED subframe order")

    def read_lpc_subframe(self, block_size, bits_per_sample, order):
        # "order" number of warm-up samples
        samples = [
            self.reader.read_signed(bits_per_sample) for i in range(order)
        ]

        # the size of each QLP coefficient, in bits
        qlp_precision = self.reader.read(4)

        # the amount of right shift to apply
        # during LPC calculation
        # (though this is a signed value, negative shifts are noops
        # in the reference FLAC decoder)
        qlp_shift_needed = max(self.reader.read_signed(5), 0)

        # "order" number of signed QLP coefficients
        qlp_coeffs = [
            self.reader.read_signed(qlp_precision + 1) for i in range(order)
        ]
        # QLP coefficients are applied in reverse order
        qlp_coeffs.reverse()

        # "block_size" - "order" number of residual values
        residuals = self.read_residual(block_size, order)

        # which are applied to the running LPC calculation
        for residual in residuals:
            samples.append((sum([
                coeff * sample
                for (coeff, sample) in zip(qlp_coeffs, samples[-order:])
            ]) >> qlp_shift_needed) + residual)

        return samples

    def read_residual(self, block_size, order):
        residuals = []

        coding_method = self.reader.read(2)
        partition_order = self.reader.read(4)

        # each parititon contains  block_size / 2 ** partition_order
        # number of residuals
        for partition_number in range(2**partition_order):
            if (partition_number == 0):
                # except for the first partition
                # which contains "order" less than the rest
                residuals.extend(
                    self.read_residual_partition(
                        coding_method,
                        (block_size // 2**partition_order) - order))
            else:
                residuals.extend(
                    self.read_residual_partition(
                        coding_method, block_size // 2**partition_order))

        return residuals

    def read_residual_partition(self, coding_method, residual_count):
        if (coding_method == 0):
            # the Rice parameters determines the number of
            # least-significant bits to read for each residual
            rice_parameter = self.reader.read(4)
            if (rice_parameter == 0xF):
                escape_code = self.reader.read(5)
                return [
                    self.reader.read_signed(escape_code)
                    for i in range(residual_count)
                ]
        elif (coding_method == 1):
            # 24 bps streams may use a 5-bit Rice parameter
            # for better compression
            rice_parameter = self.reader.read(5)
            if (rice_parameter == 0x1F):
                escape_code = self.reader.read(5)
                return [
                    self.reader.read_signed(escape_code)
                    for i in range(residual_count)
                ]
        else:
            raise ValueError("invalid Rice coding parameter")

        # a list of signed residual values
        partition_residuals = []

        for i in range(residual_count):
            msb = self.reader.unary(1)  # most-significant bits
            lsb = self.reader.read(rice_parameter)  # least-significant bits
            value = (msb << rice_parameter) | lsb  # combined into a value
            if (value & 1):  # whose least-significant bit is the sign value
                partition_residuals.append(-(value >> 1) - 1)
            else:
                partition_residuals.append(value >> 1)

        return partition_residuals

    def read_utf8(self):
        total_bytes = self.reader.unary(0)
        value = self.reader.read(7 - total_bytes)
        while (total_bytes > 1):
            value = ((value << 6) | self.reader.parse("2p 6u")[0])
            total_bytes -= 1
        return value

    def close(self):
        self.reader.close()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()
Beispiel #11
0
    def read_metadata(self):
        from io import BytesIO

        command = self.unsigned(2)
        if (command == 9):
            # got verbatim, so read data
            verbatim_bytes = ints_to_bytes(
                [self.unsigned(8) & 0xFF for i in range(self.unsigned(5))])

            try:
                wave = BitstreamReader(BytesIO(verbatim_bytes), True)
                header = wave.read_bytes(12)
                if (header.startswith(b"RIFF") and header.endswith(b"WAVE")):
                    # got RIFF/WAVE header, so parse wave blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size > 0):
                        (chunk_id, chunk_size) = wave.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == b'fmt '):
                            (channels, self.sample_rate, bits_per_sample,
                             channel_mask) = parse_fmt(
                                 wave.substream(chunk_size))
                            self.channel_mask = int(channel_mask)
                            return
                        else:
                            if (chunk_size % 2):
                                wave.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                wave.read_bytes(chunk_size)
                                total_size -= chunk_size
                    else:
                        # no fmt chunk, so use default metadata
                        pass
            except (IOError, ValueError):
                pass

            try:
                aiff = BitstreamReader(BytesIO(verbatim_bytes), False)
                header = aiff.read_bytes(12)
                if (header.startswith(b"FORM") and header.endswith(b"AIFF")):
                    # got FORM/AIFF header, so parse aiff blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size > 0):
                        (chunk_id, chunk_size) = aiff.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == b'COMM'):
                            (channels, total_sample_frames, bits_per_sample,
                             self.sample_rate, channel_mask) = parse_comm(
                                 aiff.substream(chunk_size))
                            self.channel_mask = int(channel_mask)
                            return
                        else:
                            if (chunk_size % 2):
                                aiff.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                aiff.read_bytes(chunk_size)
                                total_size -= chunk_size
                    else:
                        # no COMM chunk, so use default metadata
                        pass
            except IOError:
                pass

        # got something else, so invent some PCM parameters
        self.sample_rate = 44100
        if (self.channels == 1):
            self.channel_mask = 0x4
        elif (self.channels == 2):
            self.channel_mask = 0x3
        else:
            self.channel_mask = 0
Beispiel #12
0
    def read_metadata(self):
        command = self.unsigned(2)
        if (command == 9):
            # got verbatim, so read data
            verbatim_bytes = "".join([chr(self.unsigned(8) & 0xFF)
                                      for i in range(self.unsigned(5))])

            try:
                wave = BitstreamReader(cStringIO.StringIO(verbatim_bytes), 1)
                header = wave.read_bytes(12)
                if (header.startswith("RIFF") and header.endswith("WAVE")):
                    # got RIFF/WAVE header, so parse wave blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size > 0):
                        (chunk_id, chunk_size) = wave.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == 'fmt '):
                            (channels,
                             self.sample_rate,
                             bits_per_sample,
                             channel_mask) = parse_fmt(
                                wave.substream(chunk_size))
                            self.channel_mask = int(channel_mask)
                            return
                        else:
                            if (chunk_size % 2):
                                wave.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                wave.read_bytes(chunk_size)
                                total_size -= chunk_size
                    else:
                        # no fmt chunk, so use default metadata
                        pass
            except (IOError, ValueError):
                pass

            try:
                aiff = BitstreamReader(cStringIO.StringIO(verbatim_bytes), 0)
                header = aiff.read_bytes(12)
                if (header.startswith("FORM") and header.endswith("AIFF")):
                    # got FORM/AIFF header, so parse aiff blocks as needed
                    total_size = len(verbatim_bytes) - 12
                    while (total_size > 0):
                        (chunk_id, chunk_size) = aiff.parse("4b 32u")
                        total_size -= 8
                        if (chunk_id == 'COMM'):
                            (channels,
                             total_sample_frames,
                             bits_per_sample,
                             self.sample_rate,
                             channel_mask) = parse_comm(
                                aiff.substream(chunk_size))
                            self.channel_mask = int(channel_mask)
                            return
                        else:
                            if (chunk_size % 2):
                                aiff.read_bytes(chunk_size + 1)
                                total_size -= (chunk_size + 1)
                            else:
                                aiff.read_bytes(chunk_size)
                                total_size -= chunk_size
                    else:
                        # no COMM chunk, so use default metadata
                        pass
            except IOError:
                pass

        # got something else, so invent some PCM parameters
        self.sample_rate = 44100
        if (self.channels == 1):
            self.channel_mask = 0x4
        elif (self.channels == 2):
            self.channel_mask = 0x3
        else:
            self.channel_mask = 0
Beispiel #13
0
class WavPackDecoder(object):
    def __init__(self, filename):
        self.reader = BitstreamReader(open(filename, "rb"), 1)

        # read initial block to populate
        # sample_rate, bits_per_sample, channels, and channel_mask
        self.reader.mark()
        block_header = Block_Header.read(self.reader)
        sub_blocks_size = block_header.block_size - 24
        sub_blocks_data = self.reader.substream(sub_blocks_size)
        if (block_header.sample_rate != 15):
            self.sample_rate = [
                6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000,
                44100, 48000, 64000, 88200, 96000, 192000
            ][block_header.sample_rate]
        else:
            sub_blocks_data.mark()
            try:
                for sub_block in sub_blocks(sub_blocks_data, sub_blocks_size):
                    if (((sub_block.metadata_function == 7)
                         and (sub_block.nondecoder_data == 1))):
                        self.sample_rate = sub_block.data.read(
                            sub_block.data_size() * 8)
                        break
                else:
                    raise ValueError("invalid sample rate")
            finally:
                sub_blocks_data.rewind()
                sub_blocks_data.unmark()

        self.bits_per_sample = [8, 16, 24, 32][block_header.bits_per_sample]

        if (block_header.initial_block and block_header.final_block):
            if (((block_header.mono_output == 0)
                 or (block_header.false_stereo == 1))):
                self.channels = 2
                self.channel_mask = 0x3
            else:
                self.channels = 1
                self.channel_mask = 0x4
        else:
            # look for channel mask sub block
            sub_blocks_data.mark()
            for sub_block in sub_blocks(sub_blocks_data, sub_blocks_size):
                if (((sub_block.metadata_function == 13)
                     and (sub_block.nondecoder_data == 0))):
                    self.channels = sub_block.data.read(8)
                    self.channel_mask = sub_block.data.read(
                        (sub_block.data_size() - 1) * 8)
                    break
            else:
                # FIXME - handle case of no channel mask sub block
                raise NotImplementedError()
            sub_blocks_data.rewind()
            sub_blocks_data.unmark()

        self.reader.rewind()
        self.reader.unmark()

        self.pcm_finished = False
        self.md5_checked = False
        self.md5sum = md5()

    def read(self, pcm_frames):
        if (self.pcm_finished):
            if (not self.md5_checked):
                self.reader.mark()
                try:
                    try:
                        header = Block_Header.read(self.reader)
                        sub_blocks_size = header.block_size - 24
                        sub_blocks_data = \
                            self.reader.substream(sub_blocks_size)
                        for sub_block in sub_blocks(sub_blocks_data,
                                                    sub_blocks_size):
                            if (((sub_block.metadata_function == 6)
                                 and (sub_block.nondecoder_data == 1))):
                                if ((sub_block.data.read_bytes(16) !=
                                     self.md5sum.digest())):
                                    raise ValueError("invalid stream MD5 sum")
                    except (IOError, ValueError):
                        # no error if a block isn't found
                        pass
                finally:
                    self.reader.rewind()
                    self.reader.unmark()
            return from_list([], self.channels, self.bits_per_sample, True)

        channels = []

        while (True):  # in place of a do-while loop
            try:
                block_header = Block_Header.read(self.reader)
            except (ValueError, IOError):
                self.pcm_finished = True
                return from_list([], self.channels, self.bits_per_sample, True)
            sub_blocks_size = block_header.block_size - 24
            sub_blocks_data = self.reader.substream(sub_blocks_size)
            channels.extend(
                read_block(block_header, sub_blocks_size, sub_blocks_data))

            if (block_header.final_block == 1):
                break

        if ((block_header.block_index + block_header.block_samples) >=
                block_header.total_samples):
            self.pcm_finished = True

        # combine channels of audio data into single block
        block = from_channels(
            [from_list(ch, 1, self.bits_per_sample, True) for ch in channels])

        # update MD5 sum
        self.md5sum.update(block.to_bytes(False, self.bits_per_sample > 8))

        # return single block of audio data
        return block

    def close(self):
        self.reader.close()