Exemplo n.º 1
0
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, 0)
    mdat_length = ByteCounter()
    mdat.add_callback(mdat_length.update)

    frame_sample_sizes = []
    frame_byte_sizes = []
    frame_file_offsets = []

    #write placeholder mdat header
    mdat.write(32, 0)
    mdat.write_bytes("mdat")

    #read FrameList objects until stream is empty
    frame = pcmreader.read(block_size *
                           pcmreader.channels *
                           (pcmreader.bits_per_sample / 8))
    while (len(frame) > 0):
        frame_sample_sizes.append(frame.frames)
        frame_file_offsets.append(int(mdat_length))
        encode_frameset(mdat, pcmreader, options, frame)
        frame_byte_sizes.append(int(mdat_length) - frame_file_offsets[-1])
        frame = pcmreader.read(block_size *
                               pcmreader.channels *
                               (pcmreader.bits_per_sample / 8))

    #finally, return to start of mdat and write actual length
    mdat.byte_align()
    mdat.pop_callback()
    file.seek(0, 0)
    mdat.write(32, int(mdat_length))

    return (frame_sample_sizes,
            frame_byte_sizes,
            frame_file_offsets,
            int(mdat_length))
Exemplo n.º 2
0
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, 0)
    total_pcm_frames = 0
    frame_byte_sizes = []

    # write placeholder mdat header
    mdat_start = file.tell()
    mdat.write(32, 0)
    mdat.write_bytes("mdat")

    # read FrameList objects until stream is empty
    frame = pcmreader.read(block_size)
    while len(frame) > 0:
        total_pcm_frames += frame.frames
        frame_start = file.tell()
        encode_frameset(mdat, pcmreader, options, frame)
        mdat.flush()
        frame_byte_sizes.append(file.tell() - frame_start)
        frame = pcmreader.read(block_size)

    # finally, return to start of mdat and write actual length
    file.seek(mdat_start)
    mdat.write(32, sum(frame_byte_sizes) + 8)

    return (frame_byte_sizes, total_pcm_frames)
Exemplo n.º 3
0
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.mark()
    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.rewind()
    mdat.write(32, sum(frame_byte_sizes) + 8)
    mdat.unmark()

    return (frame_byte_sizes, total_pcm_frames)
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
    def set_replay_gain(self, replaygain):
        """given a ReplayGain object, sets the track's gain to those values

        may raise IOError if unable to modify the file"""

        from math import log10
        from audiotools import TemporaryFile

        gain_title = int(round((64.82 - replaygain.track_gain) * 256))
        if replaygain.track_peak > 0.0:
            peak_title = int(log10(replaygain.track_peak * 2 ** 15) * 20 * 256)
        else:
            peak_title = 0
        gain_album = int(round((64.82 - replaygain.album_gain) * 256))
        if replaygain.album_peak > 0.0:
            peak_album = int(log10(replaygain.album_peak * 2 ** 15) * 20 * 256)
        else:
            peak_album = 0

        #FIXME - check for missing "RG" block and add one if not present

        metadata = self.get_metadata()

        writer = BitstreamWriter(TemporaryFile(self.filename), False)
        writer.write_bytes(b"MPCK")
        for key, size, block in self.blocks():
            if key != b"RG":
                writer.write_bytes(key)
                size.build(writer)
                writer.write_bytes(block)
            else:
                writer.write_bytes(b"RG")
                MPC_Size(2 + 1 + 1 + 2 * 4, 1).build(writer)
                writer.write(8, 1)
                writer.write(16, gain_title)
                writer.write(16, peak_title)
                writer.write(16, gain_album)
                writer.write(16, peak_album)

        if metadata is not None:
            writer.set_endianness(True)
            metadata.build(writer)

        writer.close()
Exemplo n.º 6
0
    def set_replay_gain(self, replaygain):
        """given a ReplayGain object, sets the track's gain to those values

        may raise IOError if unable to modify the file"""

        from math import log10
        from audiotools import TemporaryFile

        gain_title = int(round((64.82 - replaygain.track_gain) * 256))
        if replaygain.track_peak > 0.0:
            peak_title = int(log10(replaygain.track_peak * 2**15) * 20 * 256)
        else:
            peak_title = 0
        gain_album = int(round((64.82 - replaygain.album_gain) * 256))
        if replaygain.album_peak > 0.0:
            peak_album = int(log10(replaygain.album_peak * 2**15) * 20 * 256)
        else:
            peak_album = 0

        #FIXME - check for missing "RG" block and add one if not present

        metadata = self.get_metadata()

        writer = BitstreamWriter(TemporaryFile(self.filename), False)
        writer.write_bytes(b"MPCK")
        for key, size, block in self.blocks():
            if key != b"RG":
                writer.write_bytes(key)
                size.build(writer)
                writer.write_bytes(block)
            else:
                writer.write_bytes(b"RG")
                MPC_Size(2 + 1 + 1 + 2 * 4, 1).build(writer)
                writer.write(8, 1)
                writer.write(16, gain_title)
                writer.write(16, peak_title)
                writer.write(16, gain_album)
                writer.write(16, peak_album)

        if metadata is not None:
            writer.set_endianness(True)
            metadata.build(writer)

        writer.close()
Exemplo n.º 7
0
    def delete_replay_gain(self):
        """removes ReplayGain values from file, if any

        may raise IOError if unable to modify the file"""

        from audiotools import TemporaryFile

        writer = BitstreamWriter(TemporaryFile(self.filename), False)
        writer.write_bytes(b"MPCK")
        for key, size, block in self.blocks():
            if key != b"RG":
                writer.write_bytes(key)
                size.build(writer)
                writer.write_bytes(block)
            else:
                writer.write_bytes(b"RG")
                MPC_Size(2 + 1 + 1 + 2 * 4, 1).build(writer)
                writer.write(8, 1)
                writer.write(16, 0)
                writer.write(16, 0)
                writer.write(16, 0)
                writer.write(16, 0)
        writer.close()
Exemplo n.º 8
0
    def delete_replay_gain(self):
        """removes ReplayGain values from file, if any

        may raise IOError if unable to modify the file"""

        from audiotools import TemporaryFile

        writer = BitstreamWriter(TemporaryFile(self.filename), False)
        writer.write_bytes(b"MPCK")
        for key, size, block in self.blocks():
            if key != b"RG":
                writer.write_bytes(key)
                size.build(writer)
                writer.write_bytes(block)
            else:
                writer.write_bytes(b"RG")
                MPC_Size(2 + 1 + 1 + 2 * 4, 1).build(writer)
                writer.write(8, 1)
                writer.write(16, 0)
                writer.write(16, 0)
                writer.write(16, 0)
                writer.write(16, 0)
        writer.close()
Exemplo n.º 9
0
def encode_shn(filename, pcmreader, is_big_endian, signed_samples, header_data, footer_data="", block_size=256):
    """filename is a string to the output file's path
    pcmreader is a PCMReader object
    header_data and footer_data are binary strings
    block_size is the default size of each Shorten audio command
    """

    pcmreader = BufferedPCMReader(pcmreader)
    output_file = open(filename, "wb")
    writer = BitstreamWriter(output_file, 0)

    left_shift = 0
    wrapped_channels = [[] for c in xrange(pcmreader.channels)]

    # write magic number and version
    writer.build("4b 8u", ["ajkg", 2])

    bytes_written = __Counter__()
    writer.add_callback(bytes_written.byte)

    # write header from PCMReader info and encoding options
    if pcmreader.bits_per_sample == 8:
        if signed_samples:
            write_long(writer, 1)  # signed, 8-bit
            sign_adjustment = 0
        else:
            write_long(writer, 2)  # unsigned, 8-bit
            sign_adjustment = 1 << (pcmreader.bits_per_sample - 1)
        # 8-bit samples have no endianness
    elif pcmreader.bits_per_sample == 16:
        if signed_samples:
            if is_big_endian:
                write_long(writer, 3)  # signed, 16-bit, big-endian
            else:
                write_long(writer, 5)  # signed, 16-bit, little-endian
            sign_adjustment = 0
        else:
            if is_big_endian:
                write_long(writer, 4)  # unsigned, 16-bit, big-endian
            else:
                write_long(writer, 6)  # unsigned, 16-bit, little-endian
            sign_adjustment = 1 << (pcmreader.bits_per_sample - 1)
    else:
        raise ValueError("unsupported bits_per_sample")

    write_long(writer, pcmreader.channels)
    write_long(writer, block_size)
    write_long(writer, 0)  # max LPC
    write_long(writer, 0)  # mean count
    write_long(writer, 0)  # bytes to skip

    # write header as a VERBATIM block
    write_unsigned(writer, COMMAND_SIZE, FN_VERBATIM)
    write_unsigned(writer, VERBATIM_SIZE, len(header_data))
    for b in header_data:
        write_unsigned(writer, VERBATIM_BYTE_SIZE, ord(b))

    # split PCMReader into block_size chunks
    # and continue until the number of PCM frames is 0
    frame = pcmreader.read(block_size)
    while len(frame) > 0:
        # if the chunk isn't block_size frames long,
        # issue a command to change it
        if frame.frames != block_size:
            block_size = frame.frames
            write_unsigned(writer, COMMAND_SIZE, FN_BLOCKSIZE)
            write_long(writer, block_size)

        # split chunk into individual channels
        for c in xrange(pcmreader.channels):
            # convert PCM data to unsigned, if necessary
            if signed_samples:
                channel = list(frame.channel(c))
            else:
                channel = [s + sign_adjustment for s in frame.channel(c)]

            # if all samples are 0, issue a ZERO command
            if all_zeroes(channel):
                write_unsigned(writer, COMMAND_SIZE, FN_ZERO)

                # wrap zeroes around for next set of channels
                wrapped_channels[c] = channel
            else:
                # if channel's shifted bits have changed
                # from the previous channel's shift
                # issue a new BITSHIFT command
                wasted_bits = wasted_bps(channel)
                if wasted_bits != left_shift:
                    write_unsigned(writer, COMMAND_SIZE, FN_BITSHIFT)
                    write_unsigned(writer, BITSHIFT_SIZE, wasted_bits)
                    left_shift = wasted_bits

                # and shift the channel's bits if the amount is still > 0
                if left_shift > 0:
                    shifted = [s >> left_shift for s in channel]
                else:
                    shifted = channel

                # determine the best DIFF command and residuals
                # to issue for shifted channel data
                (diff, residuals) = best_diff(wrapped_channels[c], shifted)

                # determine the best energy size for DIFF's residuals
                energy = best_energy(residuals)

                # write DIFF command, energy size and residuals
                write_unsigned(writer, COMMAND_SIZE, {1: FN_DIFF1, 2: FN_DIFF2, 3: FN_DIFF3}[diff])
                write_unsigned(writer, ENERGY_SIZE, energy)
                for residual in residuals:
                    write_signed(writer, energy, residual)

                # wrap shifted channels around for next set of channels
                wrapped_channels[c] = shifted

        # and get another set of channels to encode
        frame = pcmreader.read(block_size)

    # once all PCM data has been sent
    # if there's any footer data, write it as another VERBATIM block
    if len(footer_data) > 0:
        write_unsigned(writer, COMMAND_SIZE, FN_VERBATIM)
        write_unsigned(writer, VERBATIM_SIZE, len(footer_data))
        for b in footer_data:
            write_unsigned(writer, VERBATIM_BYTE_SIZE, ord(b))

    # issue a QUIT command
    write_unsigned(writer, COMMAND_SIZE, FN_QUIT)

    # finally, due to Shorten's silly way of using bit buffers,
    # output (not counting the 5 bytes of magic + version)
    # must be padded to a multiple of 4 bytes
    # or its reference decoder explodes
    writer.byte_align()
    while (int(bytes_written) % 4) != 0:
        writer.write(8, 0)
Exemplo n.º 10
0
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()
Exemplo n.º 11
0
def encode_shn(filename,
               pcmreader,
               is_big_endian,
               signed_samples,
               header_data,
               footer_data="",
               block_size=256):
    """filename is a string to the output file's path
    pcmreader is a PCMReader object
    header_data and footer_data are binary strings
    block_size is the default size of each Shorten audio command
    """

    pcmreader = BufferedPCMReader(pcmreader)
    output_file = open(filename, "wb")
    writer = BitstreamWriter(output_file, 0)

    left_shift = 0
    wrapped_channels = [[] for c in xrange(pcmreader.channels)]

    #write magic number and version
    writer.build("4b 8u", ["ajkg", 2])

    bytes_written = __Counter__()
    writer.add_callback(bytes_written.byte)

    #write header from PCMReader info and encoding options
    if (pcmreader.bits_per_sample == 8):
        if (signed_samples):
            write_long(writer, 1)  # signed, 8-bit
            sign_adjustment = 0
        else:
            write_long(writer, 2)  # unsigned, 8-bit
            sign_adjustment = 1 << (pcmreader.bits_per_sample - 1)
        #8-bit samples have no endianness
    elif (pcmreader.bits_per_sample == 16):
        if (signed_samples):
            if (is_big_endian):
                write_long(writer, 3)  # signed, 16-bit, big-endian
            else:
                write_long(writer, 5)  # signed, 16-bit, little-endian
            sign_adjustment = 0
        else:
            if (is_big_endian):
                write_long(writer, 4)  # unsigned, 16-bit, big-endian
            else:
                write_long(writer, 6)  # unsigned, 16-bit, little-endian
            sign_adjustment = 1 << (pcmreader.bits_per_sample - 1)
    else:
        raise ValueError("unsupported bits_per_sample")

    write_long(writer, pcmreader.channels)
    write_long(writer, block_size)
    write_long(writer, 0)  # max LPC
    write_long(writer, 0)  # mean count
    write_long(writer, 0)  # bytes to skip

    #write header as a VERBATIM block
    write_unsigned(writer, COMMAND_SIZE, FN_VERBATIM)
    write_unsigned(writer, VERBATIM_SIZE, len(header_data))
    for b in header_data:
        write_unsigned(writer, VERBATIM_BYTE_SIZE, ord(b))

    #split PCMReader into block_size chunks
    #and continue until the number of PCM frames is 0
    frame = pcmreader.read(block_size)
    while (len(frame) > 0):
        #if the chunk isn't block_size frames long,
        #issue a command to change it
        if (frame.frames != block_size):
            block_size = frame.frames
            write_unsigned(writer, COMMAND_SIZE, FN_BLOCKSIZE)
            write_long(writer, block_size)

        #split chunk into individual channels
        for c in xrange(pcmreader.channels):
            #convert PCM data to unsigned, if necessary
            if (signed_samples):
                channel = list(frame.channel(c))
            else:
                channel = [s + sign_adjustment for s in frame.channel(c)]

            #if all samples are 0, issue a ZERO command
            if (all_zeroes(channel)):
                write_unsigned(writer, COMMAND_SIZE, FN_ZERO)

                #wrap zeroes around for next set of channels
                wrapped_channels[c] = channel
            else:
                #if channel's shifted bits have changed
                #from the previous channel's shift
                #issue a new BITSHIFT command
                wasted_bits = wasted_bps(channel)
                if (wasted_bits != left_shift):
                    write_unsigned(writer, COMMAND_SIZE, FN_BITSHIFT)
                    write_unsigned(writer, BITSHIFT_SIZE, wasted_bits)
                    left_shift = wasted_bits

                #and shift the channel's bits if the amount is still > 0
                if (left_shift > 0):
                    shifted = [s >> left_shift for s in channel]
                else:
                    shifted = channel

                #determine the best DIFF command and residuals
                #to issue for shifted channel data
                (diff, residuals) = best_diff(wrapped_channels[c], shifted)

                #determine the best energy size for DIFF's residuals
                energy = best_energy(residuals)

                #write DIFF command, energy size and residuals
                write_unsigned(writer, COMMAND_SIZE, {
                    1: FN_DIFF1,
                    2: FN_DIFF2,
                    3: FN_DIFF3
                }[diff])
                write_unsigned(writer, ENERGY_SIZE, energy)
                for residual in residuals:
                    write_signed(writer, energy, residual)

                #wrap shifted channels around for next set of channels
                wrapped_channels[c] = shifted

        #and get another set of channels to encode
        frame = pcmreader.read(block_size)

    #once all PCM data has been sent
    #if there's any footer data, write it as another VERBATIM block
    if (len(footer_data) > 0):
        write_unsigned(writer, COMMAND_SIZE, FN_VERBATIM)
        write_unsigned(writer, VERBATIM_SIZE, len(footer_data))
        for b in footer_data:
            write_unsigned(writer, VERBATIM_BYTE_SIZE, ord(b))

    #issue a QUIT command
    write_unsigned(writer, COMMAND_SIZE, FN_QUIT)

    #finally, due to Shorten's silly way of using bit buffers,
    #output (not counting the 5 bytes of magic + version)
    #must be padded to a multiple of 4 bytes
    #or its reference decoder explodes
    writer.byte_align()
    while ((int(bytes_written) % 4) != 0):
        writer.write(8, 0)