Пример #1
0
    def read(self, pcm_frames):
        # if the stream is exhausted, return an empty pcm.FrameList object
        if (self.total_pcm_frames == 0):
            return from_list([], self.channels, self.bits_per_sample, True)

        # otherwise, read one ALAC frameset's worth of frame data
        frameset_data = []
        frame_channels = self.reader.read(3) + 1
        while (frame_channels != 0x8):
            frameset_data.extend(self.read_frame(frame_channels))
            frame_channels = self.reader.read(3) + 1
        self.reader.byte_align()

        # reorder the frameset to Wave order, depending on channel count
        if ((self.channels == 1) or (self.channels == 2)):
            pass
        elif (self.channels == 3):
            frameset_data = [
                frameset_data[1], frameset_data[2], frameset_data[0]
            ]
        elif (self.channels == 4):
            frameset_data = [
                frameset_data[1], frameset_data[2], frameset_data[0],
                frameset_data[3]
            ]
        elif (self.channels == 5):
            frameset_data = [
                frameset_data[1], frameset_data[2], frameset_data[0],
                frameset_data[3], frameset_data[4]
            ]
        elif (self.channels == 6):
            frameset_data = [
                frameset_data[1], frameset_data[2], frameset_data[0],
                frameset_data[5], frameset_data[3], frameset_data[4]
            ]
        elif (self.channels == 7):
            frameset_data = [
                frameset_data[1], frameset_data[2], frameset_data[0],
                frameset_data[6], frameset_data[3], frameset_data[4],
                frameset_data[5]
            ]
        elif (self.channels == 8):
            frameset_data = [
                frameset_data[3], frameset_data[4], frameset_data[0],
                frameset_data[7], frameset_data[5], frameset_data[6],
                frameset_data[1], frameset_data[2]
            ]
        else:
            raise ValueError("unsupported channel count")

        framelist = from_channels([
            from_list(channel, 1, self.bits_per_sample, True)
            for channel in frameset_data
        ])

        # deduct PCM frames from remainder
        self.total_pcm_frames -= framelist.frames

        # return samples as a pcm.FrameList object
        return framelist
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
    def set_format(self, sample_rate, channels, channel_mask, bits_per_sample):
        """sets the output stream to the given format

        if the stream hasn't been initialized, this method initializes it

        if the stream has been initialized to a different format,
        this method closes and reopens the stream to the new format

        if the stream has been initialized to the same format,
        this method does nothing"""

        if (self.__ossaudio__ is None):
            # output hasn't been initialized

            import ossaudiodev

            AudioOutput.set_format(self, sample_rate, channels, channel_mask,
                                   bits_per_sample)

            # initialize audio output device and setup framelist converter
            self.__ossaudio__ = ossaudiodev.open('w')
            self.__ossmixer__ = ossaudiodev.openmixer()
            if (self.bits_per_sample == 8):
                self.__ossaudio__.setfmt(ossaudiodev.AFMT_S8_LE)
                self.__converter__ = lambda f: f.to_bytes(False, True)
            elif (self.bits_per_sample == 16):
                self.__ossaudio__.setfmt(ossaudiodev.AFMT_S16_LE)
                self.__converter__ = lambda f: f.to_bytes(False, True)
            elif (self.bits_per_sample == 24):
                from audiotools.pcm import from_list

                self.__ossaudio__.setfmt(ossaudiodev.AFMT_S16_LE)
                self.__converter__ = lambda f: from_list([
                    i >> 8 for i in list(f)
                ], self.channels, 16, True).to_bytes(False, True)
            else:
                raise ValueError("Unsupported bits-per-sample")

            self.__ossaudio__.channels(channels)
            self.__ossaudio__.speed(sample_rate)
        elif (not self.compatible(sample_rate=sample_rate,
                                  channels=channels,
                                  channel_mask=channel_mask,
                                  bits_per_sample=bits_per_sample)):
            # output has been initialized to a different format

            self.close()
            self.set_format(sample_rate=sample_rate,
                            channels=channels,
                            channel_mask=channel_mask,
                            bits_per_sample=bits_per_sample)
Пример #5
0
    def set_format(self, sample_rate, channels, channel_mask, bits_per_sample):
        """sets the output stream to the given format

        if the stream hasn't been initialized, this method initializes it

        if the stream has been initialized to a different format,
        this method closes and reopens the stream to the new format

        if the stream has been initialized to the same format,
        this method does nothing"""

        if (self.__ossaudio__ is None):
            # output hasn't been initialized

            import ossaudiodev

            AudioOutput.set_format(self, sample_rate, channels,
                                   channel_mask, bits_per_sample)

            # initialize audio output device and setup framelist converter
            self.__ossaudio__ = ossaudiodev.open('w')
            self.__ossmixer__ = ossaudiodev.openmixer()
            if (self.bits_per_sample == 8):
                self.__ossaudio__.setfmt(ossaudiodev.AFMT_S8_LE)
                self.__converter__ = lambda f: f.to_bytes(False, True)
            elif (self.bits_per_sample == 16):
                self.__ossaudio__.setfmt(ossaudiodev.AFMT_S16_LE)
                self.__converter__ = lambda f: f.to_bytes(False, True)
            elif (self.bits_per_sample == 24):
                from audiotools.pcm import from_list

                self.__ossaudio__.setfmt(ossaudiodev.AFMT_S16_LE)
                self.__converter__ = lambda f: from_list(
                    [i >> 8 for i in list(f)],
                    self.channels, 16, True).to_bytes(False, True)
            else:
                raise ValueError("Unsupported bits-per-sample")

            self.__ossaudio__.channels(channels)
            self.__ossaudio__.speed(sample_rate)
        elif (not self.compatible(sample_rate=sample_rate,
                                  channels=channels,
                                  channel_mask=channel_mask,
                                  bits_per_sample=bits_per_sample)):
            # output has been initialized to a different format

            self.close()
            self.set_format(sample_rate=sample_rate,
                            channels=channels,
                            channel_mask=channel_mask,
                            bits_per_sample=bits_per_sample)
Пример #6
0
def encode_compressed_frame(writer, pcmreader, options, channels):
    if pcmreader.bits_per_sample <= 16:
        uncompressed_LSBs = 0
        LSBs = []
    else:
        from audiotools.pcm import from_list
        # extract uncompressed LSBs
        uncompressed_LSBs = (pcmreader.bits_per_sample - 16) // 8
        LSBs = []
        for i in range(len(channels[0])):
            for c in range(len(channels)):
                LSBs.append(channels[c][i] %
                            (2 ** (pcmreader.bits_per_sample - 16)))

        channels = [from_list([i >> (pcmreader.bits_per_sample - 16)
                               for i in channel], 1, 16, True)
                    for channel in channels]

    if len(channels) == 1:
        encode_non_interlaced_frame(writer,
                                    pcmreader,
                                    options,
                                    uncompressed_LSBs,
                                    LSBs,
                                    channels)
    else:
        interlaced_frames = [BitstreamRecorder(0) for i in
                             range(options.min_interlacing_leftweight,
                                   options.max_interlacing_leftweight + 1)]
        for (leftweight,
             frame) in zip(range(options.min_interlacing_leftweight,
                                 options.max_interlacing_leftweight + 1),
                           interlaced_frames):
            encode_interlaced_frame(frame,
                                    pcmreader,
                                    options,
                                    uncompressed_LSBs,
                                    LSBs,
                                    options.interlacing_shift,
                                    leftweight,
                                    channels)

        for i in range(len(interlaced_frames) - 1):
            if ((interlaced_frames[i].bits() <
                 min([f.bits() for f in interlaced_frames[i + 1:]]))):
                interlaced_frames[i].copy(writer)
                break
        else:
            interlaced_frames[0].copy(writer)
Пример #7
0
    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
Пример #8
0
    def read(self, pcm_frames):
        #if the stream is exhausted, return an empty pcm.FrameList object
        if (self.total_pcm_frames == 0):
            return from_list([], self.channels, self.bits_per_sample, True)

        #otherwise, read one ALAC frameset's worth of frame data
        frameset_data = []
        frame_channels = self.reader.read(3) + 1
        while (frame_channels != 0x8):
            frameset_data.extend(self.read_frame(frame_channels))
            frame_channels = self.reader.read(3) + 1
        self.reader.byte_align()

        #reorder the frameset to Wave order, depending on channel count
        if ((self.channels == 1) or (self.channels == 2)):
            pass
        elif (self.channels == 3):
            frameset_data = [frameset_data[1],
                             frameset_data[2],
                             frameset_data[0]]
        elif (self.channels == 4):
            frameset_data = [frameset_data[1],
                             frameset_data[2],
                             frameset_data[0],
                             frameset_data[3]]
        elif (self.channels == 5):
            frameset_data = [frameset_data[1],
                             frameset_data[2],
                             frameset_data[0],
                             frameset_data[3],
                             frameset_data[4]]
        elif (self.channels == 6):
            frameset_data = [frameset_data[1],
                             frameset_data[2],
                             frameset_data[0],
                             frameset_data[5],
                             frameset_data[3],
                             frameset_data[4]]
        elif (self.channels == 7):
            frameset_data = [frameset_data[1],
                             frameset_data[2],
                             frameset_data[0],
                             frameset_data[6],
                             frameset_data[3],
                             frameset_data[4],
                             frameset_data[5]]
        elif (self.channels == 8):
            frameset_data = [frameset_data[3],
                             frameset_data[4],
                             frameset_data[0],
                             frameset_data[7],
                             frameset_data[5],
                             frameset_data[6],
                             frameset_data[1],
                             frameset_data[2]]
        else:
            raise ValueError("unsupported channel count")

        framelist = from_channels([from_list(channel,
                                             1,
                                             self.bits_per_sample,
                                             True)
                                   for channel in frameset_data])

        #deduct PCM frames from remainder
        self.total_pcm_frames -= framelist.frames

        #return samples as a pcm.FrameList object
        return framelist
Пример #9
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
            ])
Пример #10
0
    def read(self, pcm_frames):
        if self.stream_finished:
            return from_channels([empty_framelist(1, self.bits_per_sample)
                                  for channel in range(self.channels)])

        c = 0
        samples = []
        unshifted = []
        while True:
            command = self.unsigned(2)
            if (((0 <= command) and (command <= 3) or
                 (7 <= command) and (command <= 8))):
                # audio data commands
                if command == 0:    # DIFF0
                    samples.append(self.read_diff0(self.block_length,
                                                   self.means[c]))
                elif command == 1:  # DIFF1
                    samples.append(self.read_diff1(self.block_length,
                                                   self.wrapped_samples[c]))
                elif command == 2:  # DIFF2
                    samples.append(self.read_diff2(self.block_length,
                                                   self.wrapped_samples[c]))
                elif command == 3:  # DIFF3
                    samples.append(self.read_diff3(self.block_length,
                                                   self.wrapped_samples[c]))
                elif command == 7:  # QLPC
                    samples.append(self.read_qlpc(self.block_length,
                                                  self.means[c],
                                                  self.wrapped_samples[c]))
                elif command == 8:  # ZERO
                    samples.append([0] * self.block_length)

                # update means for channel
                self.means[c].append(shnmean(samples[c]))
                self.means[c] = self.means[c][1:]

                # wrap samples for next command in channel
                self.wrapped_samples[c] = samples[c][-(max(3, self.max_LPC)):]

                # apply left shift to samples
                if self.left_shift > 0:
                    unshifted.append([s << self.left_shift
                                      for s in samples[c]])
                else:
                    unshifted.append(samples[c])

                c += 1
                if c == self.channels:
                    # return a FrameList from shifted data
                    return from_channels([from_list(channel, 1,
                                                    self.bits_per_sample,
                                                    self.signed_samples)
                                          for channel in unshifted])
            else:
                # non audio commands
                if command == 4:  # QUIT
                    self.stream_finished = True
                    return from_channels(
                        [empty_framelist(1, self.bits_per_sample)
                         for channel in range(self.channels)])
                elif command == 5:  # BLOCKSIZE
                    self.block_length = self.long()
                elif command == 6:  # BITSHIFT
                    self.left_shift = self.unsigned(2)
                elif command == 9:  # VERBATIM
                    # skip this command during reading
                    size = self.unsigned(5)
                    for i in range(size):
                        self.skip_unsigned(8)
                else:
                    raise ValueError("unsupported Shorten command")
Пример #11
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])
Пример #12
0
    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
Пример #13
0
    def read(self, pcm_frames):
        if (self.stream_finished):
            return from_channels([
                empty_framelist(1, self.bits_per_sample)
                for channel in range(self.channels)
            ])

        c = 0
        samples = []
        unshifted = []
        while (True):
            command = self.unsigned(2)
            if (((0 <= command) and (command <= 3)
                 or (7 <= command) and (command <= 8))):
                # audio data commands
                if (command == 0):  # DIFF0
                    samples.append(
                        self.read_diff0(self.block_length, self.means[c]))
                elif (command == 1):  # DIFF1
                    samples.append(
                        self.read_diff1(self.block_length,
                                        self.wrapped_samples[c]))
                elif (command == 2):  # DIFF2
                    samples.append(
                        self.read_diff2(self.block_length,
                                        self.wrapped_samples[c]))
                elif (command == 3):  # DIFF3
                    samples.append(
                        self.read_diff3(self.block_length,
                                        self.wrapped_samples[c]))
                elif (command == 7):  # QLPC
                    samples.append(
                        self.read_qlpc(self.block_length, self.means[c],
                                       self.wrapped_samples[c]))
                elif (command == 8):  # ZERO
                    samples.append([0] * self.block_length)

                # update means for channel
                self.means[c].append(shnmean(samples[c]))
                self.means[c] = self.means[c][1:]

                # wrap samples for next command in channel
                self.wrapped_samples[c] = samples[c][-(max(3, self.max_LPC)):]

                # apply left shift to samples
                if (self.left_shift > 0):
                    unshifted.append(
                        [s << self.left_shift for s in samples[c]])
                else:
                    unshifted.append(samples[c])

                c += 1
                if (c == self.channels):
                    # return a FrameList from shifted data
                    return from_channels([
                        from_list(channel, 1, self.bits_per_sample,
                                  self.signed_samples) for channel in unshifted
                    ])
            else:
                # non audio commands
                if (command == 4):  # QUIT
                    self.stream_finished = True
                    return from_channels([
                        empty_framelist(1, self.bits_per_sample)
                        for channel in range(self.channels)
                    ])
                elif (command == 5):  # BLOCKSIZE
                    self.block_length = self.long()
                elif (command == 6):  # BITSHIFT
                    self.left_shift = self.unsigned(2)
                elif (command == 9):  # VERBATIM
                    # skip this command during reading
                    size = self.unsigned(5)
                    for i in range(size):
                        self.skip_unsigned(8)
                else:
                    raise ValueError("unsupported Shorten command")