def encode_mdat(file, pcmreader, block_size=4096, initial_history=10, history_multiplier=40, maximum_k=14, interlacing_shift=2, min_interlacing_leftweight=0, max_interlacing_leftweight=4): options = Encoding_Options(block_size, initial_history, history_multiplier, maximum_k, interlacing_shift, min_interlacing_leftweight, max_interlacing_leftweight) pcmreader = BufferedPCMReader(pcmreader) mdat = BitstreamWriter(file, False) total_pcm_frames = 0 frame_byte_sizes = [] # write placeholder mdat header mdat_start = mdat.getpos() mdat.write(32, 0) mdat.write_bytes(b"mdat") # read FrameList objects until stream is empty frame = pcmreader.read(block_size) while len(frame) > 0: total_pcm_frames += frame.frames frame_byte_size = Counter() mdat.add_callback(frame_byte_size.add) encode_frameset(mdat, pcmreader, options, frame) mdat.pop_callback() frame_byte_sizes.append(int(frame_byte_size)) frame = pcmreader.read(block_size) # finally, return to start of mdat and write actual length mdat.setpos(mdat_start) mdat.write(32, sum(frame_byte_sizes) + 8) return (frame_byte_sizes, total_pcm_frames)
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 from_pcm(cls, filename, pcmreader, compression=None, total_pcm_frames=None, encoding_function=None): """encodes a new file from PCM data takes a filename string, PCMReader object, optional compression level string and optional total_pcm_frames integer encodes a new audio file from pcmreader's data at the given filename with the specified compression level and returns a new AudioFile-compatible object may raise EncodingError if some problem occurs when encoding the input file. This includes an error in the input stream, a problem writing the output file, or even an EncodingError subclass such as "UnsupportedBitsPerSample" if the input stream is formatted in a way this class is unable to support """ from audiotools import (BufferedPCMReader, CounterPCMReader, transfer_data, EncodingError) # from audiotools.py_encoders import encode_tta from audiotools.encoders import encode_tta from audiotools.bitstream import BitstreamWriter # open output file right away # so we can fail as soon as possible try: file = open(filename, "wb") except IOError as err: pcmreader.close() raise EncodingError(str(err)) writer = BitstreamWriter(file, True) counter = CounterPCMReader(pcmreader) try: if total_pcm_frames is not None: # write header to disk write_header(writer, pcmreader.channels, pcmreader.bits_per_sample, pcmreader.sample_rate, total_pcm_frames) block_size = (pcmreader.sample_rate * 256) // 245 total_tta_frames = div_ceil(total_pcm_frames, block_size) # write temporary seektable to disk seektable_start = writer.getpos() write_seektable(writer, [0] * total_tta_frames) writer.flush() # write frames to disk try: frame_sizes = \ (encode_tta if encoding_function is None else encoding_function)(file, BufferedPCMReader(counter)) except (IOError, ValueError) as err: cls.__unlink__(filename) raise EncodingError(str(err)) # ensure written number of PCM frames # matches total_pcm_frames if counter.frames_written != total_pcm_frames: from audiotools.text import ERR_TOTAL_PCM_FRAMES_MISMATCH cls.__unlink__(filename) raise EncodingError(ERR_TOTAL_PCM_FRAMES_MISMATCH) assert(len(frame_sizes) == total_tta_frames) # go back and rewrite seektable with completed one writer.setpos(seektable_start) write_seektable(writer, frame_sizes) else: import tempfile frames = tempfile.TemporaryFile() # encode TTA frames to temporary file try: frame_sizes = \ (encode_tta if encoding_function is None else encoding_function)(frames, BufferedPCMReader(counter)) except (IOError, ValueError) as err: frames.close() cls.__unlink__(filename) raise EncodingError(str(err)) # write header to disk write_header(writer, pcmreader.channels, pcmreader.bits_per_sample, pcmreader.sample_rate, counter.frames_written) # write seektable to disk write_seektable(writer, frame_sizes) # transfer TTA frames from temporary space to disk frames.seek(0, 0) transfer_data(frames.read, writer.write_bytes) frames.close() finally: counter.close() writer.close() return cls(filename)
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