def encode_flac(filename, pcmreader, block_size=4096, max_lpc_order=8, adaptive_mid_side=False, mid_side=True, exhaustive_model_search=False, max_residual_partition_order=5): options = Encoding_Options(block_size, max_lpc_order, adaptive_mid_side, mid_side, exhaustive_model_search, max_residual_partition_order, 14 if pcmreader.bits_per_sample <= 16 else 30) streaminfo = STREAMINFO(block_size, block_size, 2 ** 32, 0, pcmreader.sample_rate, pcmreader.channels, pcmreader.bits_per_sample, 0, md5()) pcmreader = BufferedPCMReader(pcmreader) output_file = open(filename, "wb") writer = BitstreamWriter(output_file, 0) #write placeholder metadata blocks writer.write_bytes("fLaC") writer.build("1u 7u 24u", [1, 0, 34]) streaminfo.write(writer) #walk through PCM reader's FrameLists frame_number = 0 frame = pcmreader.read(block_size * (pcmreader.bits_per_sample / 8) * pcmreader.channels) flac_frame = BitstreamRecorder(0) while (len(frame) > 0): streaminfo.input_update(frame) flac_frame.reset() encode_flac_frame(flac_frame, pcmreader, options, frame_number, frame) streaminfo.output_update(flac_frame) flac_frame.copy(writer) frame_number += 1 frame = pcmreader.read(block_size * (pcmreader.bits_per_sample / 8) * pcmreader.channels) #return to beginning of file and rewrite STREAMINFO block output_file.seek(8, 0) streaminfo.write(writer) writer.close()
def build(self, writer): """outputs an APEv2 tag to writer""" from audiotools.bitstream import BitstreamRecorder tags = BitstreamRecorder(1) for tag in self.tags: tag.build(tags) if (self.contains_header): writer.build(ApeTag.HEADER_FORMAT, ("APETAGEX", # preamble 2000, # version tags.bytes() + 32, # tag size len(self.tags), # item count 0, # read only 0, # encoding 1, # is header not self.contains_footer, # no footer self.contains_header)) # has header tags.copy(writer) if (self.contains_footer): writer.build(ApeTag.HEADER_FORMAT, ("APETAGEX", # preamble 2000, # version tags.bytes() + 32, # tag size len(self.tags), # item count 0, # read only 0, # encoding 0, # is header not self.contains_footer, # no footer self.contains_header)) # has header
def encode_frame(writer, pcmreader, options, channels): assert(len(channels) > 0) uncompressed_frame = BitstreamRecorder(0) compressed_frame = BitstreamRecorder(0) writer.write(3, len(channels) - 1) encode_uncompressed_frame(uncompressed_frame, pcmreader, options, channels) if len(channels[0]) >= 10: try: encode_compressed_frame(compressed_frame, pcmreader, options, channels) if compressed_frame.bits() < uncompressed_frame.bits(): compressed_frame.copy(writer) else: uncompressed_frame.copy(writer) except ResidualOverflow: uncompressed_frame.copy(writer) else: uncompressed_frame.copy(writer)
def encode_subframe(writer, options, bits_per_sample, samples): def all_identical(l): if len(l) == 1: return True else: for i in l[1:]: if i != l[0]: return False else: return True def wasted(s): w = 0 while (s & 1) == 0: w += 1 s >>= 1 return w if all_identical(samples): encode_constant_subframe(writer, bits_per_sample, samples[0]) else: # account for wasted BPS, if any wasted_bps = 2**32 for sample in samples: if sample != 0: wasted_bps = min(wasted_bps, wasted(sample)) if wasted_bps == 0: break if wasted_bps == 2**32: # all samples are 0 wasted_bps = 0 elif wasted_bps > 0: samples = [s >> wasted_bps for s in samples] fixed_subframe = BitstreamRecorder(0) encode_fixed_subframe(fixed_subframe, options, wasted_bps, bits_per_sample, samples) if options.max_lpc_order > 0: lpc_subframe = BitstreamRecorder(0) encode_lpc_subframe(lpc_subframe, options, wasted_bps, bits_per_sample, samples) if (((bits_per_sample * len(samples)) < min( fixed_subframe.bits(), lpc_subframe.bits()))): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) elif fixed_subframe.bits() < lpc_subframe.bits(): fixed_subframe.copy(writer) else: lpc_subframe.copy(writer) else: if (bits_per_sample * len(samples)) < fixed_subframe.bits(): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) else: fixed_subframe.copy(writer)
def build(self, writer): """outputs an APEv2 tag to writer""" from audiotools.bitstream import BitstreamRecorder tags = BitstreamRecorder(1) for tag in self.tags: tag.build(tags) if (self.contains_header): writer.build( ApeTag.HEADER_FORMAT, ( "APETAGEX", # preamble 2000, # version tags.bytes() + 32, # tag size len(self.tags), # item count 0, # read only 0, # encoding 1, # is header not self.contains_footer, # no footer self.contains_header)) # has header tags.copy(writer) if (self.contains_footer): writer.build( ApeTag.HEADER_FORMAT, ( "APETAGEX", # preamble 2000, # version tags.bytes() + 32, # tag size len(self.tags), # item count 0, # read only 0, # encoding 0, # is header not self.contains_footer, # no footer self.contains_header)) # has header
def encode_flac(filename, pcmreader, block_size=4096, max_lpc_order=8, min_residual_partition_order=0, max_residual_partition_order=5, mid_side=True, adaptive_mid_side=False, exhaustive_model_search=False, disable_verbatim_subframes=False, disable_constant_subframes=False, disable_fixed_subframes=False, disable_lpc_subframes=False, padding_size=4096): frame_sizes = [] options = Encoding_Options(block_size, max_lpc_order, adaptive_mid_side, mid_side, exhaustive_model_search, max_residual_partition_order, 14 if pcmreader.bits_per_sample <= 16 else 30) streaminfo = STREAMINFO(block_size, block_size, (2**24) - 1, 0, pcmreader.sample_rate, pcmreader.channels, pcmreader.bits_per_sample, 0, md5()) pcmreader = BufferedPCMReader(pcmreader) output_file = open(filename, "wb") writer = BitstreamWriter(output_file, False) # write placeholder metadata blocks such as STREAMINFO and PADDING writer.write_bytes("fLaC") writer.build("1u 7u 24u", [0, 0, 34]) streaminfo_start = writer.getpos() streaminfo.write(writer) writer.build("1u 7u 24u", [1, 1, padding_size]) writer.write_bytes(b"\x00" * padding_size) # walk through PCM reader's FrameLists frame_number = 0 frame = pcmreader.read(block_size) flac_frame = BitstreamRecorder(0) while len(frame) > 0: streaminfo.input_update(frame) flac_frame.reset() encode_flac_frame(flac_frame, pcmreader, options, frame_number, frame) frame_sizes.append((flac_frame.bytes(), frame.frames)) streaminfo.output_update(flac_frame) flac_frame.copy(writer) frame_number += 1 frame = pcmreader.read(block_size) # return to beginning of file and rewrite STREAMINFO block writer.setpos(streaminfo_start) streaminfo.write(writer) writer.flush() writer.close() return frame_sizes
def encode_lpc_subframe(writer, options, wasted_bps, bits_per_sample, samples): """computes the best LPC subframe from the given samples according to the options and writes it to the given BitstreamWriter""" # window signal windowed = [(sample * tukey) for (sample, tukey) in zip(samples, tukey_window(len(samples), 0.5))] # compute autocorrelation values if len(samples) > (options.max_lpc_order + 1): autocorrelation_values = [ sum(x * y for x, y in zip(windowed, windowed[lag:])) for lag in range(0, options.max_lpc_order + 1) ] else: # not enough samples, so build LPC with dummy coeffs write_lpc_subframe(writer=writer, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=1, qlp_precision=options.qlp_precision, qlp_shift_needed=0, qlp_coefficients=[0], samples=samples) return # compute LP coefficients from autocorrelation values if ((len(autocorrelation_values) > 1) and (set(autocorrelation_values) != {0.0})): (lp_coefficients, error) = \ compute_lp_coefficients(autocorrelation_values) else: # all autocorrelation values are zero # so build LPC with dummy coeffs write_lpc_subframe(writer=writer, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=1, qlp_precision=options.qlp_precision, qlp_shift_needed=0, qlp_coefficients=[0], samples=samples) return if not options.exhaustive_model_search: # if not performaing an exhaustive model search # estimate which set of LP coefficients is best # and use those to build subframe order = estimate_best_lpc_order(options, len(samples), bits_per_sample, error) (qlp_coefficients, qlp_shift_needed) = \ quantize_coefficients(options.qlp_precision, lp_coefficients, order) write_lpc_subframe(writer=writer, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=order, qlp_precision=options.qlp_precision, qlp_shift_needed=qlp_shift_needed, qlp_coefficients=qlp_coefficients, samples=samples) else: # otherwise, build all possible subframes # and return the one which is actually the smallest best_subframe_size = 2**32 best_subframe = BitstreamRecorder(0) for order in range(1, options.max_lpc_order + 1): (qlp_coefficients, qlp_shift_needed) = \ quantize_coefficients(options.qlp_precision, lp_coefficients, order) subframe = BitstreamRecorder(0) write_lpc_subframe(writer=subframe, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=order, qlp_precision=options.qlp_precision, qlp_shift_needed=qlp_shift_needed, qlp_coefficients=qlp_coefficients, samples=samples) if subframe.bits() < best_subframe_size: best_subframe = subframe else: best_subframe.copy(writer)
def encode_flac_frame(writer, pcmreader, options, frame_number, frame): crc16 = CRC16() writer.add_callback(crc16.update) if ((pcmreader.channels == 2) and (options.adaptive_mid_side or options.mid_side)): # calculate average/difference average = [(c0 + c1) // 2 for c0, c1 in zip(frame.channel(0), frame.channel(1))] difference = [ c0 - c1 for c0, c1 in zip(frame.channel(0), frame.channel(1)) ] # try different subframes based on encoding options left_subframe = BitstreamRecorder(0) encode_subframe(left_subframe, options, pcmreader.bits_per_sample, list(frame.channel(0))) right_subframe = BitstreamRecorder(0) encode_subframe(right_subframe, options, pcmreader.bits_per_sample, list(frame.channel(1))) average_subframe = BitstreamRecorder(0) encode_subframe(average_subframe, options, pcmreader.bits_per_sample, average) difference_subframe = BitstreamRecorder(0) encode_subframe(difference_subframe, options, pcmreader.bits_per_sample + 1, difference) # write best header/subframes to disk if options.mid_side: if ((left_subframe.bits() + right_subframe.bits()) < min( left_subframe.bits() + difference_subframe.bits(), difference_subframe.bits() + right_subframe.bits(), average_subframe.bits() + difference_subframe.bits())): write_frame_header(writer, pcmreader, frame_number, frame, 0x1) left_subframe.copy(writer) right_subframe.copy(writer) elif (left_subframe.bits() < min(right_subframe.bits(), difference_subframe.bits())): write_frame_header(writer, pcmreader, frame_number, frame, 0x8) left_subframe.copy(writer) difference_subframe.copy(writer) elif right_subframe.bits() < average_subframe.bits(): write_frame_header(writer, pcmreader, frame_number, frame, 0x9) difference_subframe.copy(writer) right_subframe.copy(writer) else: write_frame_header(writer, pcmreader, frame_number, frame, 0xA) average_subframe.copy(writer) difference_subframe.copy(writer) else: if (((left_subframe.bits() + right_subframe.bits()) < (average_subframe.bits() + difference_subframe.bits()))): write_frame_header(writer, pcmreader, frame_number, frame, 0x1) left_subframe.copy(writer) right_subframe.copy(writer) else: write_frame_header(writer, pcmreader, frame_number, frame, 0xA) average_subframe.copy(writer) difference_subframe.copy(writer) else: write_frame_header(writer, pcmreader, frame_number, frame, pcmreader.channels - 1) for i in range(frame.channels): encode_subframe(writer, options, pcmreader.bits_per_sample, list(frame.channel(i))) writer.byte_align() writer.pop_callback() writer.write(16, int(crc16))
def write_block(writer, context, channels, block_index, first_block, last_block, parameters): """writer is a BitstreamWriter-compatible object context is an EncoderContext object channels[c][s] is sample "s" in channel "c" block_index is an integer of the block's offset in PCM frames first_block and last_block are flags indicating the block's sequence parameters is an EncodingParameters object """ assert (len(channels) == 1) or (len(channels) == 2) if (len(channels) == 1) or (channels[0] == channels[1]): # 1 channel block or equivalent if len(channels) == 1: false_stereo = 0 else: false_stereo = 1 # calculate maximum magnitude of channel_0 magnitude = max(map(bits, channels[0])) # determine wasted bits wasted = min(map(wasted_bps, channels[0])) if wasted == INFINITY: # all samples are 0 wasted = 0 # if wasted bits, remove them from channel_0 if (wasted > 0) and (wasted != INFINITY): shifted = [[s >> wasted for s in channels[0]]] else: shifted = [channels[0]] # calculate CRC of shifted_0 crc = calculate_crc(shifted) else: # 2 channel block false_stereo = 0 # calculate maximum magnitude of channel_0/channel_1 magnitude = max(max(map(bits, channels[0])), max(map(bits, channels[1]))) # determine wasted bits wasted = min(min(map(wasted_bps, channels[0])), min(map(wasted_bps, channels[1]))) if wasted == INFINITY: # all samples are 0 wasted = 0 # if wasted bits, remove them from channel_0/channel_1 if wasted > 0: shifted = [[s >> wasted for s in channels[0]], [s >> wasted for s in channels[1]]] else: shifted = channels # calculate CRC of shifted_0/shifted_1 crc = calculate_crc(shifted) # joint stereo conversion of shifted_0/shifted_1 to mid/side channels mid_side = joint_stereo(shifted[0], shifted[1]) sub_blocks = BitstreamRecorder(1) sub_block = BitstreamRecorder(1) # if first block in file, write Wave header if not context.first_block_written: sub_block.reset() if context.wave_header is None: if context.wave_footer is None: write_wave_header(sub_block, context.pcmreader, 0, 0) else: write_wave_header(sub_block, context.pcmreader, 0, len(context.wave_footer)) else: sub_block.write_bytes(context.wave_header) write_sub_block(sub_blocks, WV_WAVE_HEADER, 1, sub_block) context.first_block_written = True # if correlation passes, write three sub blocks of pass data if parameters.correlation_passes > 0: sub_block.reset() write_correlation_terms( sub_block, [p.term for p in parameters.correlation_parameters(false_stereo)], [p.delta for p in parameters.correlation_parameters(false_stereo)], ) write_sub_block(sub_blocks, WV_TERMS, 0, sub_block) sub_block.reset() write_correlation_weights(sub_block, [p.weights for p in parameters.correlation_parameters(false_stereo)]) write_sub_block(sub_blocks, WV_WEIGHTS, 0, sub_block) sub_block.reset() write_correlation_samples( sub_block, [p.term for p in parameters.correlation_parameters(false_stereo)], [p.samples for p in parameters.correlation_parameters(false_stereo)], 2 if ((len(channels) == 2) and (not false_stereo)) else 1, ) write_sub_block(sub_blocks, WV_SAMPLES, 0, sub_block) # if wasted bits, write extended integers sub block if wasted > 0: sub_block.reset() write_extended_integers(sub_block, 0, wasted, 0, 0) write_sub_block(sub_blocks, WV_INT32_INFO, 0, sub_block) # if channel count > 2, write channel info sub block if context.pcmreader.channels > 2: sub_block.reset() sub_block.write(8, context.pcmreader.channels) sub_block.write(32, context.pcmreader.channel_mask) write_sub_block(sub_blocks, WV_CHANNEL_INFO, 0, sub_block) # if nonstandard sample rate, write sample rate sub block if context.pcmreader.sample_rate not in ( 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000, ): sub_block.reset() sub_block.write(32, context.pcmreader.sample_rate) write_sub_block(sub_blocks, WV_SAMPLE_RATE, 1, sub_block) if (len(channels) == 1) or (false_stereo): # 1 channel block # correlate shifted_0 with terms/deltas/weights/samples if parameters.correlation_passes > 0: assert len(shifted) == 1 correlated = correlate_channels(shifted, parameters.correlation_parameters(false_stereo), 1) else: correlated = shifted else: # 2 channel block # correlate shifted_0/shifted_1 with terms/deltas/weights/samples if parameters.correlation_passes > 0: assert len(mid_side) == 2 correlated = correlate_channels(mid_side, parameters.correlation_parameters(false_stereo), 2) else: correlated = mid_side # write entropy variables sub block sub_block.reset() write_entropy_variables(sub_block, correlated, parameters.entropy_variables) write_sub_block(sub_blocks, WV_ENTROPY, 0, sub_block) # write bitstream sub block sub_block.reset() write_bitstream(sub_block, correlated, parameters.entropy_variables) write_sub_block(sub_blocks, WV_BITSTREAM, 0, sub_block) # write block header with size of all sub blocks write_block_header( writer, sub_blocks.bytes(), block_index, len(channels[0]), context.pcmreader.bits_per_sample, len(channels), (len(channels) == 2) and (false_stereo == 0), len(set([-1, -2, -3]) & set([p.term for p in parameters.correlation_parameters(false_stereo)])) > 0, wasted, first_block, last_block, magnitude, context.pcmreader.sample_rate, false_stereo, crc, ) # write sub block data to stream sub_blocks.copy(writer) # round-trip entropy variables parameters.entropy_variables = [ [wv_exp2(wv_log2(p)) for p in parameters.entropy_variables[0]], [wv_exp2(wv_log2(p)) for p in parameters.entropy_variables[1]], ]
def encode_wavpack(filename, pcmreader, block_size, correlation_passes=0, wave_header=None, wave_footer=None): pcmreader = BufferedPCMReader(pcmreader) output_file = open(filename, "wb") writer = BitstreamWriter(output_file, 1) context = EncoderContext( pcmreader, block_parameters(pcmreader.channels, pcmreader.channel_mask, correlation_passes), wave_header, wave_footer, ) block_index = 0 # walk through PCM reader's FrameLists frame = pcmreader.read(block_size * (pcmreader.bits_per_sample / 8) * pcmreader.channels) while len(frame) > 0: context.total_frames += frame.frames context.md5sum.update(frame.to_bytes(False, pcmreader.bits_per_sample >= 16)) c = 0 for parameters in context.block_parameters: if parameters.channel_count == 1: channel_data = [list(frame.channel(c))] else: channel_data = [list(frame.channel(c)), list(frame.channel(c + 1))] first_block = parameters is context.block_parameters[0] last_block = parameters is context.block_parameters[-1] context.block_offsets.append(output_file.tell()) write_block(writer, context, channel_data, block_index, first_block, last_block, parameters) c += parameters.channel_count block_index += frame.frames frame = pcmreader.read(block_size * (pcmreader.bits_per_sample / 8) * pcmreader.channels) # write MD5 sum and optional Wave footer in final block sub_blocks = BitstreamRecorder(1) sub_block = BitstreamRecorder(1) sub_block.reset() sub_block.write_bytes(context.md5sum.digest()) write_sub_block(sub_blocks, WV_MD5, 1, sub_block) # write Wave footer in final block, if present if context.wave_footer is not None: sub_block.reset() sub_block.write_bytes(context.wave_footer) write_sub_block(sub_blocks, WV_WAVE_FOOTER, 1, sub_block) write_block_header( writer, sub_blocks.bytes(), 0xFFFFFFFF, 0, pcmreader.bits_per_sample, 1, 0, 0, 0, 1, 1, 0, pcmreader.sample_rate, 0, 0xFFFFFFFF, ) sub_blocks.copy(writer) # update Wave header's "data" chunk size, if generated if context.wave_header is None: output_file.seek(32 + 2) if context.wave_footer is None: write_wave_header(writer, context.pcmreader, context.total_frames, 0) else: write_wave_header(writer, context.pcmreader, context.total_frames, len(context.wave_footer)) # go back and populate block headers with total samples for block_offset in context.block_offsets: output_file.seek(block_offset + 12, 0) writer.write(32, block_index) writer.close()
def encode_flac(filename, pcmreader, block_size=4096, max_lpc_order=8, min_residual_partition_order=0, max_residual_partition_order=5, mid_side=True, adaptive_mid_side=False, exhaustive_model_search=False, disable_verbatim_subframes=False, disable_constant_subframes=False, disable_fixed_subframes=False, disable_lpc_subframes=False, padding_size=4096): frame_sizes = [] options = Encoding_Options(block_size, max_lpc_order, adaptive_mid_side, mid_side, exhaustive_model_search, max_residual_partition_order, 14 if pcmreader.bits_per_sample <= 16 else 30) streaminfo = STREAMINFO(block_size, block_size, (2 ** 24) - 1, 0, pcmreader.sample_rate, pcmreader.channels, pcmreader.bits_per_sample, 0, md5()) pcmreader = BufferedPCMReader(pcmreader) output_file = open(filename, "wb") writer = BitstreamWriter(output_file, False) # write placeholder metadata blocks such as STREAMINFO and PADDING writer.write_bytes("fLaC") writer.build("1u 7u 24u", [0, 0, 34]) streaminfo_start = writer.getpos() streaminfo.write(writer) writer.build("1u 7u 24u", [1, 1, padding_size]) writer.write_bytes(b"\x00" * padding_size) # walk through PCM reader's FrameLists frame_number = 0 frame = pcmreader.read(block_size) flac_frame = BitstreamRecorder(0) while len(frame) > 0: streaminfo.input_update(frame) flac_frame.reset() encode_flac_frame(flac_frame, pcmreader, options, frame_number, frame) frame_sizes.append((flac_frame.bytes(), frame.frames)) streaminfo.output_update(flac_frame) flac_frame.copy(writer) frame_number += 1 frame = pcmreader.read(block_size) # return to beginning of file and rewrite STREAMINFO block writer.setpos(streaminfo_start) streaminfo.write(writer) writer.flush() writer.close() return frame_sizes
def encode_lpc_subframe(writer, options, wasted_bps, bits_per_sample, samples): """computes the best LPC subframe from the given samples according to the options and writes it to the given BitstreamWriter""" # window signal windowed = [(sample * tukey) for (sample, tukey) in zip(samples, tukey_window(len(samples), 0.5))] # compute autocorrelation values if len(samples) > (options.max_lpc_order + 1): autocorrelation_values = [ sum(x * y for x, y in zip(windowed, windowed[lag:])) for lag in range(0, options.max_lpc_order + 1)] else: # not enough samples, so build LPC with dummy coeffs write_lpc_subframe(writer=writer, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=1, qlp_precision=options.qlp_precision, qlp_shift_needed=0, qlp_coefficients=[0], samples=samples) return # compute LP coefficients from autocorrelation values if ((len(autocorrelation_values) > 1) and (set(autocorrelation_values) != {0.0})): (lp_coefficients, error) = \ compute_lp_coefficients(autocorrelation_values) else: # all autocorrelation values are zero # so build LPC with dummy coeffs write_lpc_subframe(writer=writer, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=1, qlp_precision=options.qlp_precision, qlp_shift_needed=0, qlp_coefficients=[0], samples=samples) return if not options.exhaustive_model_search: # if not performaing an exhaustive model search # estimate which set of LP coefficients is best # and use those to build subframe order = estimate_best_lpc_order(options, len(samples), bits_per_sample, error) (qlp_coefficients, qlp_shift_needed) = \ quantize_coefficients(options.qlp_precision, lp_coefficients, order) write_lpc_subframe(writer=writer, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=order, qlp_precision=options.qlp_precision, qlp_shift_needed=qlp_shift_needed, qlp_coefficients=qlp_coefficients, samples=samples) else: # otherwise, build all possible subframes # and return the one which is actually the smallest best_subframe_size = 2 ** 32 best_subframe = BitstreamRecorder(0) for order in range(1, options.max_lpc_order + 1): (qlp_coefficients, qlp_shift_needed) = \ quantize_coefficients(options.qlp_precision, lp_coefficients, order) subframe = BitstreamRecorder(0) write_lpc_subframe(writer=subframe, options=options, wasted_bps=wasted_bps, bits_per_sample=bits_per_sample, order=order, qlp_precision=options.qlp_precision, qlp_shift_needed=qlp_shift_needed, qlp_coefficients=qlp_coefficients, samples=samples) if subframe.bits() < best_subframe_size: best_subframe = subframe else: best_subframe.copy(writer)
def encode_subframe(writer, options, bits_per_sample, samples): def all_identical(l): if len(l) == 1: return True else: for i in l[1:]: if i != l[0]: return False else: return True def wasted(s): w = 0 while (s & 1) == 0: w += 1 s >>= 1 return w if all_identical(samples): encode_constant_subframe(writer, bits_per_sample, samples[0]) else: # account for wasted BPS, if any wasted_bps = 2 ** 32 for sample in samples: if sample != 0: wasted_bps = min(wasted_bps, wasted(sample)) if wasted_bps == 0: break if wasted_bps == 2 ** 32: # all samples are 0 wasted_bps = 0 elif wasted_bps > 0: samples = [s >> wasted_bps for s in samples] fixed_subframe = BitstreamRecorder(0) encode_fixed_subframe(fixed_subframe, options, wasted_bps, bits_per_sample, samples) if options.max_lpc_order > 0: lpc_subframe = BitstreamRecorder(0) encode_lpc_subframe(lpc_subframe, options, wasted_bps, bits_per_sample, samples) if (((bits_per_sample * len(samples)) < min(fixed_subframe.bits(), lpc_subframe.bits()))): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) elif fixed_subframe.bits() < lpc_subframe.bits(): fixed_subframe.copy(writer) else: lpc_subframe.copy(writer) else: if (bits_per_sample * len(samples)) < fixed_subframe.bits(): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) else: fixed_subframe.copy(writer)
def encode_flac_frame(writer, pcmreader, options, frame_number, frame): crc16 = CRC16() writer.add_callback(crc16.update) if ((pcmreader.channels == 2) and (options.adaptive_mid_side or options.mid_side)): # calculate average/difference average = [(c0 + c1) // 2 for c0, c1 in zip(frame.channel(0), frame.channel(1))] difference = [c0 - c1 for c0, c1 in zip(frame.channel(0), frame.channel(1))] # try different subframes based on encoding options left_subframe = BitstreamRecorder(0) encode_subframe(left_subframe, options, pcmreader.bits_per_sample, list(frame.channel(0))) right_subframe = BitstreamRecorder(0) encode_subframe(right_subframe, options, pcmreader.bits_per_sample, list(frame.channel(1))) average_subframe = BitstreamRecorder(0) encode_subframe(average_subframe, options, pcmreader.bits_per_sample, average) difference_subframe = BitstreamRecorder(0) encode_subframe(difference_subframe, options, pcmreader.bits_per_sample + 1, difference) # write best header/subframes to disk if options.mid_side: if ((left_subframe.bits() + right_subframe.bits()) < min(left_subframe.bits() + difference_subframe.bits(), difference_subframe.bits() + right_subframe.bits(), average_subframe.bits() + difference_subframe.bits())): write_frame_header(writer, pcmreader, frame_number, frame, 0x1) left_subframe.copy(writer) right_subframe.copy(writer) elif (left_subframe.bits() < min(right_subframe.bits(), difference_subframe.bits())): write_frame_header(writer, pcmreader, frame_number, frame, 0x8) left_subframe.copy(writer) difference_subframe.copy(writer) elif right_subframe.bits() < average_subframe.bits(): write_frame_header(writer, pcmreader, frame_number, frame, 0x9) difference_subframe.copy(writer) right_subframe.copy(writer) else: write_frame_header(writer, pcmreader, frame_number, frame, 0xA) average_subframe.copy(writer) difference_subframe.copy(writer) else: if (((left_subframe.bits() + right_subframe.bits()) < (average_subframe.bits() + difference_subframe.bits()))): write_frame_header(writer, pcmreader, frame_number, frame, 0x1) left_subframe.copy(writer) right_subframe.copy(writer) else: write_frame_header(writer, pcmreader, frame_number, frame, 0xA) average_subframe.copy(writer) difference_subframe.copy(writer) else: write_frame_header(writer, pcmreader, frame_number, frame, pcmreader.channels - 1) for i in range(frame.channels): encode_subframe(writer, options, pcmreader.bits_per_sample, list(frame.channel(i))) writer.byte_align() writer.pop_callback() writer.write(16, int(crc16))
def encode_subframe(writer, options, bits_per_sample, samples): def all_identical(l): if (len(l) == 1): return True else: for i in l[1:]: if (i != l[0]): return False else: return True def wasted(s): w = 0 while ((s & 1) == 0): w += 1 s >>= 1 return w if (all_identical(samples)): encode_constant_subframe(writer, bits_per_sample, samples[0]) else: #account for wasted BPS, if any wasted_bps = 2 ** 32 for sample in samples: if (sample != 0): wasted_bps = min(wasted_bps, wasted(sample)) if (wasted_bps == 0): break if (wasted_bps == 2 ** 32): #all samples are 0 wasted_bps = 0 elif (wasted_bps > 0): samples = [s >> wasted_bps for s in samples] fixed_subframe = BitstreamRecorder(0) encode_fixed_subframe(fixed_subframe, options, wasted_bps, bits_per_sample, samples) if (options.max_lpc_order > 0): (lpc_order, qlp_coeffs, qlp_shift_needed) = compute_lpc_coefficients(options, wasted_bps, bits_per_sample, samples) lpc_subframe = BitstreamRecorder(0) encode_lpc_subframe(lpc_subframe, options, wasted_bps, bits_per_sample, lpc_order, options.qlp_precision, qlp_shift_needed, qlp_coeffs, samples) if (((bits_per_sample * len(samples)) < min(fixed_subframe.bits(), lpc_subframe.bits()))): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) elif (fixed_subframe.bits() < lpc_subframe.bits()): fixed_subframe.copy(writer) else: lpc_subframe.copy(writer) else: if ((bits_per_sample * len(samples)) < fixed_subframe.bits()): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) else: fixed_subframe.copy(writer)
def encode_subframe(writer, options, bits_per_sample, samples): def all_identical(l): if (len(l) == 1): return True else: for i in l[1:]: if (i != l[0]): return False else: return True def wasted(s): w = 0 while ((s & 1) == 0): w += 1 s >>= 1 return w if (all_identical(samples)): encode_constant_subframe(writer, bits_per_sample, samples[0]) else: # account for wasted BPS, if any wasted_bps = 2 ** 32 for sample in samples: if (sample != 0): wasted_bps = min(wasted_bps, wasted(sample)) if (wasted_bps == 0): break if (wasted_bps == 2 ** 32): # all samples are 0 wasted_bps = 0 elif (wasted_bps > 0): samples = [s >> wasted_bps for s in samples] fixed_subframe = BitstreamRecorder(0) encode_fixed_subframe(fixed_subframe, options, wasted_bps, bits_per_sample, samples) if (options.max_lpc_order > 0): (lpc_order, qlp_coeffs, qlp_shift_needed) = compute_lpc_coefficients(options, wasted_bps, bits_per_sample, samples) lpc_subframe = BitstreamRecorder(0) encode_lpc_subframe(lpc_subframe, options, wasted_bps, bits_per_sample, lpc_order, options.qlp_precision, qlp_shift_needed, qlp_coeffs, samples) if (((bits_per_sample * len(samples)) < min(fixed_subframe.bits(), lpc_subframe.bits()))): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) elif (fixed_subframe.bits() < lpc_subframe.bits()): fixed_subframe.copy(writer) else: lpc_subframe.copy(writer) else: if ((bits_per_sample * len(samples)) < fixed_subframe.bits()): encode_verbatim_subframe(writer, wasted_bps, bits_per_sample, samples) else: fixed_subframe.copy(writer)