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 empty_framelist(self.channels, self.bits_per_sample) 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 empty_framelist(self.channels, self.bits_per_sample) 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 read(self, pcm_frames): if self.pcm_finished: if not self.md5_checked: block_start = self.reader.getpos() 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.setpos(block_start) return empty_framelist(self.channels, self.bits_per_sample) 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 empty_framelist(self.channels, self.bits_per_sample) 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 read(self, pcm_frames): # if the stream is exhausted, return an empty pcm.FrameList object if (self.total_pcm_frames == 0): return empty_framelist(self.channels, self.bits_per_sample) # 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
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")
def read(self, pcm_frames): if (self.total_pcm_frames == 0): return empty_framelist(self.channels, self.bits_per_sample) 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 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(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(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")
def read(self, pcm_frames): if self.total_pcm_frames == 0: return empty_framelist(self.channels, self.bits_per_sample) 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 read(self, pcm_frames): # if the stream is exhausted, return an empty pcm.FrameList object if self.total_pcm_frames == 0: return empty_framelist(self.channels, self.bits_per_sample) # 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