Beispiel #1
0
    def delete_metadata(self):
        """deletes the track's MetaData

        this removes or unsets tags as necessary in order to remove all data
        raises IOError if unable to write the file"""

        import os
        from audiotools import (transfer_data,
                                LimitedFileReader,
                                TemporaryFile)
        from audiotools.id3 import skip_id3v2_comment

        if (not os.access(self.filename, os.W_OK)):
            raise IOError(self.filename)

        # overwrite original with no tags attached
        old_tta = open(self.filename, "rb")
        skip_id3v2_comment(old_tta)
        old_tta = LimitedFileReader(old_tta, self.data_size())

        new_tta = TemporaryFile(self.filename)
        transfer_data(old_tta.read, new_tta.write)

        old_tta.close()
        new_tta.close()
Beispiel #2
0
    def __init__(self, filename):
        from audiotools.id3 import skip_id3v2_comment

        AudioFile.__init__(self, filename)

        try:
            with open(filename, "rb") as f:
                skip_id3v2_comment(f)

                from audiotools.bitstream import BitstreamReader
                from audiotools.text import (ERR_TTA_INVALID_SIGNATURE,
                                             ERR_TTA_INVALID_FORMAT)

                reader = BitstreamReader(f, True)

                (signature, format_, self.__channels__,
                 self.__bits_per_sample__, self.__sample_rate__,
                 self.__total_pcm_frames__
                 ) = reader.parse("4b 16u 16u 16u 32u 32u 32p")

                if signature != b"TTA1":
                    raise InvalidTTA(ERR_TTA_INVALID_SIGNATURE)
                elif format_ != 1:
                    raise InvalidTTA(ERR_TTA_INVALID_FORMAT)

                self.__total_tta_frames__ = div_ceil(
                    self.__total_pcm_frames__ * 245,
                    self.__sample_rate__ * 256)
                self.__frame_lengths__ = list(
                    reader.parse(
                        "{:d}* 32u".format(self.__total_tta_frames__) + "32p"))
        except IOError as msg:
            raise InvalidTTA(str(msg))
Beispiel #3
0
    def __init__(self, filename):
        from audiotools.id3 import skip_id3v2_comment

        AudioFile.__init__(self, filename)

        try:
            with open(filename, "rb") as f:
                skip_id3v2_comment(f)

                from audiotools.bitstream import BitstreamReader
                from audiotools.text import (ERR_TTA_INVALID_SIGNATURE,
                                             ERR_TTA_INVALID_FORMAT)

                reader = BitstreamReader(f, True)

                (signature,
                 format_,
                 self.__channels__,
                 self.__bits_per_sample__,
                 self.__sample_rate__,
                 self.__total_pcm_frames__) = reader.parse(
                    "4b 16u 16u 16u 32u 32u 32p")

                if (signature != b"TTA1"):
                    raise InvalidTTA(ERR_TTA_INVALID_SIGNATURE)
                elif (format_ != 1):
                    raise InvalidTTA(ERR_TTA_INVALID_FORMAT)

                self.__total_tta_frames__ = div_ceil(
                    self.__total_pcm_frames__ * 245,
                    self.__sample_rate__ * 256)
                self.__frame_lengths__ = list(reader.parse(
                    "%d* 32u" % (self.__total_tta_frames__) + "32p"))
        except IOError as msg:
            raise InvalidTTA(str(msg))
Beispiel #4
0
    def to_pcm(self):
        """returns a PCMReader object containing the track's PCM data

        if an error occurs initializing a decoder, this should
        return a PCMReaderError with an appropriate error message"""

        from audiotools import decoders
        from audiotools import PCMReaderError
        from audiotools.id3 import skip_id3v2_comment

        try:
            tta = open(self.filename, "rb")
        except IOError as msg:
            return PCMReaderError(error_message=str(msg),
                                  sample_rate=self.sample_rate(),
                                  channels=self.channels(),
                                  channel_mask=int(self.channel_mask()),
                                  bits_per_sample=self.bits_per_sample())
        try:
            skip_id3v2_comment(tta)
            return decoders.TTADecoder(tta)
        except (IOError, ValueError) as msg:
            # This isn't likely unless the TTA file is modified
            # between when TrueAudio is instantiated
            # and to_pcm() is called.
            tta.close()
            return PCMReaderError(error_message=str(msg),
                                  sample_rate=self.sample_rate(),
                                  channels=self.channels(),
                                  channel_mask=int(self.channel_mask()),
                                  bits_per_sample=self.bits_per_sample())
Beispiel #5
0
    def delete_metadata(self):
        """deletes the track's MetaData

        this removes or unsets tags as necessary in order to remove all data
        raises IOError if unable to write the file"""

        import os
        from audiotools import (transfer_data,
                                LimitedFileReader,
                                TemporaryFile)
        from audiotools.id3 import skip_id3v2_comment

        if (not os.access(self.filename, os.W_OK)):
            raise IOError(self.filename)

        # overwrite original with no tags attached
        old_tta = open(self.filename, "rb")
        skip_id3v2_comment(old_tta)
        old_tta = LimitedFileReader(old_tta, self.data_size())

        new_tta = TemporaryFile(self.filename)
        transfer_data(old_tta.read, new_tta.write)

        old_tta.close()
        new_tta.close()
Beispiel #6
0
    def to_pcm(self):
        """returns a PCMReader object containing the track's PCM data

        if an error occurs initializing a decoder, this should
        return a PCMReaderError with an appropriate error message"""

        from audiotools.decoders import TTADecoder
        from audiotools import PCMReaderError
        from audiotools.id3 import skip_id3v2_comment

        try:
            tta = open(self.filename, "rb")
        except IOError as msg:
            return PCMReaderError(error_message=str(msg),
                                  sample_rate=self.sample_rate(),
                                  channels=self.channels(),
                                  channel_mask=int(self.channel_mask()),
                                  bits_per_sample=self.bits_per_sample())
        try:
            skip_id3v2_comment(tta)
            return TTADecoder(tta)
        except (IOError, ValueError) as msg:
            # This isn't likely unless the TTA file is modified
            # between when TrueAudio is instantiated
            # and to_pcm() is called.
            tta.close()
            return PCMReaderError(error_message=str(msg),
                                  sample_rate=self.sample_rate(),
                                  channels=self.channels(),
                                  channel_mask=int(self.channel_mask()),
                                  bits_per_sample=self.bits_per_sample())
Beispiel #7
0
    def __find_next_mp3_frame__(cls, mp3file):
        from audiotools.id3 import skip_id3v2_comment

        # if we're starting at an ID3v2 header, skip it to save a bunch of time
        bytes_skipped = skip_id3v2_comment(mp3file)

        # then find the next mp3 frame
        from audiotools.bitstream import BitstreamReader

        reader = BitstreamReader(mp3file, False)
        pos = reader.getpos()
        try:
            (sync,
             mpeg_id,
             layer_description) = reader.parse("11u 2u 2u 1p")
        except IOError as err:
            raise err

        while (not ((sync == 0x7FF) and
                    (mpeg_id in (0, 2, 3)) and
                    (layer_description in (1, 2, 3)))):
            reader.setpos(pos)
            reader.skip(8)
            bytes_skipped += 1
            pos = reader.getpos()
            try:
                (sync,
                 mpeg_id,
                 layer_description) = reader.parse("11u 2u 2u 1p")
            except IOError as err:
                raise err
        else:
            reader.setpos(pos)
            return bytes_skipped
Beispiel #8
0
    def __find_next_mp3_frame__(cls, mp3file):
        from audiotools.id3 import skip_id3v2_comment

        # if we're starting at an ID3v2 header, skip it to save a bunch of time
        bytes_skipped = skip_id3v2_comment(mp3file)

        # then find the next mp3 frame
        from audiotools.bitstream import BitstreamReader

        reader = BitstreamReader(mp3file, False)
        pos = reader.getpos()
        try:
            (sync, mpeg_id, layer_description) = reader.parse("11u 2u 2u 1p")
        except IOError as err:
            raise err

        while (not ((sync == 0x7FF) and (mpeg_id in (0, 2, 3)) and
                    (layer_description in (1, 2, 3)))):
            reader.setpos(pos)
            reader.skip(8)
            bytes_skipped += 1
            pos = reader.getpos()
            try:
                (sync, mpeg_id,
                 layer_description) = reader.parse("11u 2u 2u 1p")
            except IOError as err:
                raise err
        else:
            reader.setpos(pos)
            return bytes_skipped
Beispiel #9
0
    def __find_mp3_start__(cls, mp3file):
        """places mp3file at the position of the MP3 file's start"""

        from audiotools.id3 import skip_id3v2_comment

        # if we're starting at an ID3v2 header, skip it to save a bunch of time
        skip_id3v2_comment(mp3file)

        from audiotools.bitstream import BitstreamReader

        reader = BitstreamReader(mp3file, False)

        # skip over any bytes that aren't a valid MPEG header
        pos = reader.getpos()
        (frame_sync, mpeg_id, layer) = reader.parse("11u 2u 2u 1p")
        while (not ((frame_sync == 0x7FF) and (mpeg_id in (0, 2, 3)) and
                    (layer in (1, 2, 3)))):
            reader.setpos(pos)
            reader.skip(8)
            pos = reader.getpos()
        reader.setpos(pos)
Beispiel #10
0
    def __find_mp3_start__(cls, mp3file):
        """places mp3file at the position of the MP3 file's start"""

        from audiotools.id3 import skip_id3v2_comment

        # if we're starting at an ID3v2 header, skip it to save a bunch of time
        skip_id3v2_comment(mp3file)

        from audiotools.bitstream import BitstreamReader

        reader = BitstreamReader(mp3file, False)

        # skip over any bytes that aren't a valid MPEG header
        pos = reader.getpos()
        (frame_sync, mpeg_id, layer) = reader.parse("11u 2u 2u 1p")
        while (not ((frame_sync == 0x7FF) and
                    (mpeg_id in (0, 2, 3)) and
                    (layer in (1, 2, 3)))):
            reader.setpos(pos)
            reader.skip(8)
            pos = reader.getpos()
        reader.setpos(pos)
Beispiel #11
0
    def update_metadata(self, metadata):
        """takes this track's current MetaData object
        as returned by get_metadata() and sets this track's metadata
        with any fields updated in that object

        raises IOError if unable to write the file
        """

        import os
        from audiotools.ape import ApeTag
        from audiotools.id3 import ID3v2Comment
        from audiotools.id3 import ID3CommentPair
        from audiotools.id3v1 import ID3v1Comment

        if (metadata is None):
            return
        elif (not os.access(self.filename, os.W_OK)):
            raise IOError(self.filename)

        # ensure metadata is APEv2, ID3v2, ID3v1, or ID3CommentPair
        if (((not isinstance(metadata, ApeTag)) and
             (not isinstance(metadata, ID3v2Comment)) and
             (not isinstance(metadata, ID3CommentPair)) and
             (not isinstance(metadata, ID3v1Comment)))):
            from audiotools.text import ERR_FOREIGN_METADATA
            raise ValueError(ERR_FOREIGN_METADATA)

        current_metadata = self.get_metadata()

        if (isinstance(metadata, ApeTag) and (current_metadata is None)):
            # if new metadata is APEv2 and no current metadata,
            # simply append APEv2 tag
            from audiotools.bitstream import BitstreamWriter
            with BitstreamWriter(open(self.filename, "ab"), True) as writer:
                metadata.build(writer)
        elif (isinstance(metadata, ApeTag) and
              isinstance(current_metadata, ApeTag) and
              (metadata.total_size() > current_metadata.total_size())):
            # if new metadata is APEv2, current metadata is APEv2
            # and new metadata is larger,
            # overwrite old tag with new tag
            from audiotools.bitstream import BitstreamWriter
            with open(self.filename, "r+b") as f:
                f.seek(-current_metadata.total_size(), 2)
                metadata.build(BitstreamWriter(f, True))
        else:
            from audiotools.bitstream import BitstreamWriter
            from audiotools import (transfer_data,
                                    LimitedFileReader,
                                    TemporaryFile)
            from audiotools.id3 import skip_id3v2_comment

            # otherwise, rebuild TTA with APEv2/ID3 tags in place
            old_tta = open(self.filename, "rb")
            skip_id3v2_comment(old_tta)
            old_tta = LimitedFileReader(old_tta, self.data_size())

            new_tta = TemporaryFile(self.filename)

            if (isinstance(metadata, ApeTag)):
                transfer_data(old_tta.read, new_tta.write)
                metadata.build(BitstreamWriter(new_tta, True))
            elif (isinstance(metadata, ID3CommentPair)):
                metadata.id3v2.build(BitstreamWriter(new_tta, False))
                transfer_data(old_tta.read, new_tta.write)
                metadata.id3v1.build(new_tta)
            elif (isinstance(metadata, ID3v2Comment)):
                metadata.build(BitstreamWriter(new_tta, False))
                transfer_data(old_tta.read, new_tta.write)
            else:
                # ID3v1Comment
                transfer_data(old_tta.read, new_tta.write)
                metadata.build(new_tta)

            old_tta.close()
            new_tta.close()
Beispiel #12
0
    def update_metadata(self, metadata):
        """takes this track's current MetaData object
        as returned by get_metadata() and sets this track's metadata
        with any fields updated in that object

        raises IOError if unable to write the file
        """

        import os
        from audiotools.ape import ApeTag
        from audiotools.id3 import ID3v2Comment
        from audiotools.id3 import ID3CommentPair
        from audiotools.id3v1 import ID3v1Comment

        if (metadata is None):
            return
        elif (not os.access(self.filename, os.W_OK)):
            raise IOError(self.filename)

        # ensure metadata is APEv2, ID3v2, ID3v1, or ID3CommentPair
        if (((not isinstance(metadata, ApeTag))
             and (not isinstance(metadata, ID3v2Comment))
             and (not isinstance(metadata, ID3CommentPair))
             and (not isinstance(metadata, ID3v1Comment)))):
            from audiotools.text import ERR_FOREIGN_METADATA
            raise ValueError(ERR_FOREIGN_METADATA)

        current_metadata = self.get_metadata()

        if (isinstance(metadata, ApeTag) and (current_metadata is None)):
            # if new metadata is APEv2 and no current metadata,
            # simply append APEv2 tag
            from audiotools.bitstream import BitstreamWriter
            with BitstreamWriter(open(self.filename, "ab"), True) as writer:
                metadata.build(writer)
        elif (isinstance(metadata, ApeTag)
              and isinstance(current_metadata, ApeTag)
              and (metadata.total_size() > current_metadata.total_size())):
            # if new metadata is APEv2, current metadata is APEv2
            # and new metadata is larger,
            # overwrite old tag with new tag
            from audiotools.bitstream import BitstreamWriter
            with open(self.filename, "r+b") as f:
                f.seek(-current_metadata.total_size(), 2)
                metadata.build(BitstreamWriter(f, True))
        else:
            from audiotools.bitstream import BitstreamWriter
            from audiotools import (transfer_data, LimitedFileReader,
                                    TemporaryFile)
            from audiotools.id3 import skip_id3v2_comment

            # otherwise, rebuild TTA with APEv2/ID3 tags in place
            old_tta = open(self.filename, "rb")
            skip_id3v2_comment(old_tta)
            old_tta = LimitedFileReader(old_tta, self.data_size())

            new_tta = TemporaryFile(self.filename)

            if (isinstance(metadata, ApeTag)):
                transfer_data(old_tta.read, new_tta.write)
                metadata.build(BitstreamWriter(new_tta, True))
            elif (isinstance(metadata, ID3CommentPair)):
                metadata.id3v2.build(BitstreamWriter(new_tta, False))
                transfer_data(old_tta.read, new_tta.write)
                metadata.id3v1.build(new_tta)
            elif (isinstance(metadata, ID3v2Comment)):
                metadata.build(BitstreamWriter(new_tta, False))
                transfer_data(old_tta.read, new_tta.write)
            else:
                # ID3v1Comment
                transfer_data(old_tta.read, new_tta.write)
                metadata.build(new_tta)

            old_tta.close()
            new_tta.close()