:mod:`audiotools` --- the Base Python Audio Tools Module
========================================================

.. module:: audiotools
   :synopsis: the Base Python Audio Tools Module


The :mod:`audiotools` module contains a number of useful base
classes and functions upon which all of the other modules depend.


.. data:: VERSION

   The current Python Audio Tools version as a plain string.

.. data:: AVAILABLE_TYPES

   A tuple of :class:`AudioFile`-compatible classes of available
   audio types.
   Note these are types available to audiotools, not necessarily
   available to the user - depending on whether the required binaries
   are installed or not.

   ============= ==================================
   Class         Format
   ------------- ----------------------------------
   AACAudio      AAC in ADTS container
   AiffAudio     Audio Interchange File Format
   ALACAudio     Apple Lossless
   AuAudio       Sun Au
   FlacAudio     Native Free Lossless Audio Codec
   M4AAudio      AAC in M4A container
   MP3Audio      MPEG-1 Layer 3
   MP2Audio      MPEG-1 Layer 2
   OggFlacAudio  Ogg Free Lossless Audio Codec
   OpusAudio     Opus Audio Codec
   ShortenAudio  Shorten
   SpeexAudio    Ogg Speex
   VorbisAudio   Ogg Vorbis
   WaveAudio     Waveform Audio File Format
   WavPackAudio  WavPack
   ============= ==================================

.. data:: DEFAULT_TYPE

   The default type to use as a plain string, such as ``'wav'`` or ``'flac'``.

.. data:: DEFAULT_QUALITY

   A dict of type name strings -> quality value strings
   indicating the default compression quality value for the given type
   name suitable for :meth:`AudioFile.from_pcm` and :meth:`AudioFile.convert`
   method calls.

.. data:: DEFAULT_CDROM

   The default CD-ROM device to use for CD audio and DVD-Audio
   extraction as a plain string.

.. data:: TYPE_MAP

   A dictionary of type name strings -> :class:`AudioFile`
   values containing only types which have all required binaries
   installed.

.. data:: FILENAME_FORMAT

   The default format string to use for newly created files.

.. data:: BIN

   A dictionary-like class for performing lookups of system binaries.
   This checks the system and user's config files and ensures that
   any redirected binaries are called from their proper location.
   For example, if the user has configured ``flac(1)`` to be run
   from ``/opt/flac/bin/flac``

   >>> BIN["flac"]
   "/opt/flac/bin/flac"

   This class also has a ``can_execute()`` method which returns
   ``True`` if the given binary is executable.

   >>> BIN.can_execute(BIN["flac"])
   True

.. data:: IO_ENCODING

   The defined encoding to use for output to the screen as a plain
   string.
   This is typically ``'utf-8'``.

.. data:: FS_ENCODING

   The defined encoding to use for filenames read and written to disk
   as a plain string.
   This is typically ``'utf-8'``.

.. data:: MAX_JOBS

   The maximum number of simultaneous jobs to run at once by default
   as an integer.
   This may be defined from the user's config file.
   Otherwise, if Python's ``multiprocessing`` module is available,
   this is set to the user's CPU count.
   If neither is available, this is set to 1.

.. function:: file_type(file)

   Given a seekable file object returns an :class:`AudioFile`-compatible
   class of the stream's detected type, or ``None``
   if the stream's type is unknown.

   The :class:`AudioFile` class may not be available for use
   and so its :meth:`AudioFile.available` classmethod
   may need to be checked separately.

.. function:: open(filename)

   Opens the given filename string and returns an :class:`AudioFile`-compatible
   object.
   Raises :exc:`UnsupportedFile` if the file cannot identified or is
   not supported.
   Raises :exc:`IOError` if the file cannot be opened at all.

.. function:: open_files(filenames[, sorted][, messenger][, no_duplicates][, warn_duplicates][, opened_files])

   Given a list of filename strings, returns a list of
   :class:`AudioFile`-compatible objects which are successfully opened.
   By default, they are returned sorted by album number and track number.

   If ``sorted`` is ``False``, they are returned in the same order
   as they appear in the filenames list.

   If ``messenger`` is given, use that :class:`Messenger` object
   to for warnings if files cannot be opened.
   Otherwise, such warnings are sent to stdout.

   If ``no_duplicates`` is ``True``, attempting to open
   the same file twice raises a :exc:`DuplicateFile` exception.

   If ``no_duplicates`` is ``False`` and ``warn_duplicates`` is ``True``,
   attempting to open the same file twice results in a
   warning to ``messenger``, if present.

   ``opened_files``, if present, is a set of previously opened
   :class:`Filename` objects for the purpose of detecting duplicates.
   Any opened files are added to that set.

.. function:: open_directory(directory[, sorted[, messenger]])

   Given a root directory, returns an iterator of all the
   :class:`AudioFile`-compatible objects found via a recursive
   search of that directory.
   ``sorted``, and ``messenger`` work as in :func:`open_files`.

.. function:: sorted_tracks(audiofiles)

   Given a list of :class:`AudioFile` objects,
   returns a new list of those objects sorted by
   album number and track number, if present.
   If album number and track number aren't present,
   objects are sorted by base filename.

.. function:: group_tracks(audiofiles)

   Given an iterable collection of :class:`AudioFile`-compatible objects,
   returns an iterator of objects grouped into lists by album.
   That is, all objects with the same ``album_name`` and ``album_number``
   metadata fields will be returned in the same list on each pass.

.. function:: filename_to_type(path)

   Given a path, try to guess its :class:`AudioFile` class based on
   its filename suffix.
   Raises :exc:`UnknownAudioType` if the suffix is unrecognized.
   Raises :exc:`AmbiguousAudioType` if more than one type of audio
   shares the same suffix.

.. function:: transfer_data(from_function, to_function)

   This function takes two functions, presumably analogous
   to :func:`write` and :func:`read` functions, respectively.
   It calls ``to_function`` on the object returned by calling
   ``from_function`` with an integer argument (presumably a string)
   until that object's length is 0.

   >>> infile = open("input.txt", "r")
   >>> outfile = open("output.txt", "w")
   >>> transfer_data(infile.read, outfile.write)
   >>> infile.close()
   >>> outfile.close()

.. function:: transfer_framelist_data(pcmreader, to_function[, signed[, big_endian]])

   A natural progression of :func:`transfer_data`, this function takes
   a :class:`PCMReader` object and transfers the :class:`pcm.FrameList`
   objects returned by its :meth:`PCMReader.read` method to ``to_function``
   after converting them to plain strings.

   The pcmreader is closed once decoding is complete.

   May raise :exc:`IOError` or :exc:`ValueError` if a problem
   occurs during decoding.

   >>> pcm_data = audiotools.open("file.wav").to_pcm()
   >>> outfile = open("output.pcm","wb")
   >>> transfer_framelist_data(pcm_data,outfile)
   >>> pcm_data.close()
   >>> outfile.close()

.. function:: pcm_cmp(pcmreader1, pcmreader2)

   This function takes two :class:`PCMReader` objects and compares
   their PCM output.
   Returns ``True`` if that output matches exactly, ``False`` if not.

   Both streams are closed once comparison is completed.

   May raise :exc:`IOError` or :exc:`ValueError` if problems
   occur during reading.

.. function:: pcm_frame_cmp(pcmreader1, pcmreader2)

   This function takes two :class:`PCMReader` objects and compares
   their PCM frame output.
   It returns the frame number of the first mismatch as an integer
   which begins at frame number 0.
   If the two streams match completely, it returns ``None``.

   Both streams are closed once comparison is completed.

   May raise :exc:`IOError` or :exc:`ValueError` if problems
   occur during reading.

.. function:: pcm_split(pcmreader, pcm_lengths)

   Takes a :class:`PCMReader` object and list of PCM sample length integers.
   Returns an iterator of new :class:`PCMReader` objects,
   each limited to the given lengths.
   The original pcmreader is closed upon the iterator's completion.

.. function:: calculate_replay_gain(audiofiles)

   Takes a list of :class:`AudioFile`-compatible objects.
   Returns an iterator of
   ``(audiofile, track_gain, track_peak, album_gain, album_peak)``
   tuples or raises :exc:`ValueError` if a problem occurs during calculation.

.. function:: read_sheet(filename)

   Given a ``.cue`` or ``.toc`` filename, returns a :class:`Sheet`
   of that file's cuesheet data.
   May raise :exc:`SheetException` if the file cannot be read
   or parsed correctly.

.. function:: to_pcm_progress(audiofile, progress)

   Given an :class:`AudioFile`-compatible object and ``progress``
   function, returns a :class:`PCMReaderProgress` object
   of that object's PCM stream.

   If ``progress`` is ``None``, the audiofile's PCM stream
   is returned as-is.

Filename Objects
----------------

.. class:: Filename(filename)

   :class:`Filename` is a file which may or may not exist on disk.
   ``filename`` is a raw string of the actual filename.
   Filename objects are immutable and hashable,
   which means they can be used as dictionary keys
   or placed in sets.

   The purpose of Filename objects is for easier
   conversion of raw string filename paths to Unicode,
   and to make it easier to detect filenames
   which point to the same file on disk.

   The former case is used by utilities to display
   output about file operations in progress.
   The latter case is for utilities
   which need to avoid overwriting input files
   with output files.

.. function:: Filename.__str__()

   Returns the raw string of the actual filename after
   being normalized.

.. function:: Filename.__unicode__()

   Returns a Unicode string of the filename after being decoded
   through :attr:`FS_ENCODING`.

.. function:: Filename.__eq__(filename)

   Filename objects which exist on disk hash and compare equally
   if their device ID and inode number values match
   (the ``st_dev`` and ``st_ino`` fields according to stat(2)).
   Filename objects which don't exist on disk hash and compare
   equally if their filename string matches.

.. function:: Filename.open(mode)

   Returns a file object of this filename opened with the given mode.

.. function:: Filename.disk_file()

   Returns ``True`` if the file currently exists on disk.

.. function:: Filename.dirname()

   Returns the directory name of this filename as a new
   :class:`Filename` object.

.. function:: Filename.basename()

   Returns the base name (no directory) of this filename as a new
   :class:`Filename` object.

.. function:: Filename.expanduser()

   Returns a new :class:`Filename` object with the user directory
   expanded, if any.

AudioFile Objects
-----------------

.. class:: AudioFile()

   The :class:`AudioFile` class represents an audio file on disk,
   such as a FLAC file, MP3 file, WAVE file and so forth.
   It is not meant to be instantiated directly.  Instead, functions
   such as :func:`open` will return :class:`AudioFile`-compatible
   objects with the following attributes and methods.

.. attribute:: AudioFile.NAME

   The name of the format as a string.
   This is how the format is referenced by utilities via the `-t` option,
   and must be unique among all formats.

.. attribute:: AudioFile.SUFFIX

   The default file suffix as a string.
   This is used by the ``%(suffix)s`` format field in the
   :meth:`track_name` classmethod, and by the :func:`filename_to_type`
   function for inferring the file format from its name.
   However, it need not be unique among all formats.

.. attribute:: AudioFile.DESCRIPTION

   A longer, descriptive name for the audio type as a Unicode string.
   This is meant to be human-readable.

.. attribute:: AudioFile.COMPRESSION_MODES

   A tuple of valid compression level strings, for use with the
   :meth:`from_pcm` and :meth:`convert` methods.
   If the format has no compression levels, this tuple will be empty.

.. attribute:: AudioFile.DEFAULT_COMPRESSION

   A string of the default compression level to use
   with :meth:`from_pcm` and :meth:`convert`, if none is given.
   This is *not* the default compression indicated in the user's
   configuration file; it is a hard-coded value of last resort.

.. attribute:: AudioFile.COMPRESSION_DESCRIPTIONS

   A dict of compression descriptions, as Unicode strings.
   The key is a valid compression mode string.
   Not all compression modes need have a description;
   some may be left blank.

.. attribute:: AudioFile.BINARIES

   A tuple of binary strings required by the format.
   For example, the Vorbis format may require ``"oggenc"`` and ``"oggdec"``
   in order to be available for the user.

.. attribute:: AudioFile.REPLAYGAIN_BINARIES

   A tuple of binary strings required for ReplayGain application.
   For example, the Vorbis format may require ``"vorbisgain"`` in
   order to use the :meth:`add_replay_gain` classmethod.
   This tuple may be empty if the format requires no binaries
   or has no ReplayGain support.

.. method:: AudioFile.bits_per_sample()

   Returns the number of bits-per-sample in this audio file as a positive
   integer.

.. method:: AudioFile.channels()

   Returns the number of channels in this audio file as a positive integer.

.. method:: AudioFile.channel_mask()

   Returns a :class:`ChannelMask` object representing the channel assignment
   of this audio file.
   If the channel assignment is unknown or undefined, that :class:`ChannelMask`
   object may have an undefined value.

.. method:: AudioFile.sample_rate()

   Returns the sample rate of this audio file, in Hz, as a positive integer.

.. method:: AudioFile.total_frames()

   Returns the total number of PCM frames in this audio file,
   as a non-negative integer.

.. method:: AudioFile.cd_frames()

   Returns the total number of CD frames in this audio file,
   as a non-negative integer.
   Each CD frame is 1/75th of a second.

.. method:: AudioFile.seconds_length()

   Returns the length of this audio file as a :class:`fractions.Fraction`
   number of seconds.

.. method:: AudioFile.lossless()

   Returns ``True`` if the data in the audio file has been stored losslessly.
   Returns ``False`` if not.

.. classmethod:: AudioFile.supports_metadata()

   Returns ``True`` is this audio type supports metadata.
   If not, :meth:`AudioFile.get_metadata` will always return
   ``None`` and the metadata updating routines will do nothing.

.. method:: AudioFile.set_metadata(metadata)

   Takes a :class:`MetaData` object and sets this audio file's
   metadata to that value, if possible.
   Setting metadata to ``None`` is the same as calling
   :meth:`AudioFile.delete_metadata`.
   Raises :exc:`IOError` if a problem occurs when writing the file.

.. method:: AudioFile.update_metadata(metadata)

   Takes the :class:`MetaData`-compatible object returned by this
   audio file's :meth:`AudioFile.get_metadata` method
   and sets this audiofile's metadata to that value, if possible.
   Raises :exc:`IOError` if a problem occurs when writing the file.

.. note::

   What's the difference between :meth:`AudioFile.set_metadata`
   and :meth:`AudioFile.update_metadata`?

   Metadata implementations may also contain side information
   such as track length, file encoder, and so forth.
   :meth:`AudioFile.set_metadata` presumes the :class:`MetaData`
   object is from a different :class:`AudioFile` object or has
   been built from scratch.
   Therefore, it will update the newly added
   metadata side info as needed so as to not break the file.

   :meth:`AudioFile.update_metadata` presumes the :class:`MetaData`
   object is either taken from the original :class:`AudioFile` object
   or has been carefully constructed to not break anything when
   applied to the file.
   It is a lower-level routine which does *not* update metadata side info
   (which may be necessary when modifying that side info is required).

.. method:: AudioFile.get_metadata()

   Returns a :class:`MetaData`-compatible object representing this
   audio file's metadata, or ``None`` if this file contains no
   metadata.
   Raises :exc:`IOError` if a problem occurs when reading the file.

.. method:: AudioFile.delete_metadata()

   Deletes the audio file's metadata, removing or unsetting tags
   as necessary.
   Raises :exc:`IOError` if a problem occurs when writing the file.

.. method:: AudioFile.to_pcm()

   Returns this audio file's PCM data as a :class:`PCMReader`-compatible
   object.
   May return a :class:`PCMReaderError` if an error occurs
   initializing the decoder.

.. classmethod:: AudioFile.supports_to_pcm()

   Returns ``True`` if the necessary libraries or binaries
   are installed to support decoding this format.

.. classmethod:: AudioFile.from_pcm(filename, pcmreader[, compression][, total_pcm_frames])

   Takes a filename string, :class:`PCMReader`-compatible object,
   optional compression level string and optional total_pcm_frames integer.
   Creates a new audio file as the same format as this audio class
   and returns a new :class:`AudioFile`-compatible object.
   The :meth:`PCMReader.close` method is called once encoding is complete.

   Raises :exc:`EncodingError` if a problem occurs during encoding.

   Specifying the total number of PCM frames to be encoded,
   when the number is known in advance, may allow the encoder
   to work more efficiently but is never required.

   In this example, we'll transcode ``track.flac`` to ``track.mp3``
   at the default compression level:

   >>> audiotools.MP3Audio.from_pcm("track.mp3",
   ...                              audiotools.open("track.flac").to_pcm())

.. classmethod:: AudioFile.supports_from_pcm()

   Returns ``True`` if the necessary libraries or binaries
   are installed to support encoding this format.

.. method:: AudioFile.convert(filename, target_class[, compression[, progress]])

   Takes a filename string, :class:`AudioFile` subclass
   and optional compression level string.
   Creates a new audio file and returns an object of the same class.
   Raises :exc:`EncodingError` if a problem occurs during encoding.

   In this example, we'll transcode ``track.flac`` to ``track.mp3``
   at the default compression level:

   >>> audiotools.open("track.flac").convert("track.mp3",
   ...                                       audiotools.MP3Audio)

   Why have both a ``convert`` method as well as ``to_pcm``/``from_pcm``
   methods?
   Although the former is often implemented using the latter,
   the pcm methods alone contain only raw audio data.
   By comparison, the ``convert`` method has information about
   what is the file is being converted to and can transfer other side data
   if necessary.

   For example, if .wav file with non-audio RIFF chunks is
   converted to WavPack, this method will preserve those chunks:

   >>> audiotools.open("chunks.wav").convert("chunks.wv",
   ...                                       audiotools.WavPackAudio)

   whereas the ``to_pcm``/``from_pcm`` method alone will not.

   The optional ``progress`` argument is a function which takes
   a single :class:`Fraction` argument which is the current
   progress between 0 and 1, inclusive.
   If supplied, this function is called at regular intervals
   during the conversion process and may be used to indicate
   the current status to the user.

.. method:: AudioFile.seekable()

   Returns ``True`` if the file is seekable.
   That is, if its :class:`PCMReader` has a .seek() method
   and that method supports some fine-grained seeking
   when the PCMReader is working from on-disk files.

.. method:: AudioFile.verify([progress])

   Verifies the track for correctness.
   Returns ``True`` if verification is successful.
   Raises an :class:`InvalidFile` subclass if some problem is detected.
   If the file has built-in checksums or other error detection
   capabilities, this method checks those values to ensure it has not
   been damaged in some way.

   The optional ``progress`` argument functions identically
   to the one provided to :meth:`convert`.

.. classmethod:: AudioFile.track_name(file_path[, track_metadata[, format[, suffix]]])

   Given a file path string, optional :class:`MetaData`-compatible object,
   optional Python format string, and optional suffix string,
   returns a filename string with the format string fields filled-in.
   Raises :exc:`UnsupportedTracknameField` if the format string contains
   unsupported fields.

   Currently supported fields are:

   ========================== ===============================================
   Field                      Value
   -------------------------- -----------------------------------------------
   ``%(album_name)s``         ``track_metadata.album_name``
   ``%(album_number)s``       ``track_metadata.album_number``
   ``%(album_total)s``        ``track_metadata.album_total``
   ``%(album_track_number)s`` ``album_number`` combined with ``track_number``
   ``%(artist_name)s``        ``track_metadata.artist_name``
   ``%(catalog)s``            ``track_metadata.catalog``
   ``%(comment)s``            ``track_metadata.comment``
   ``%(composer_name)s``      ``track_metadata.composer_name``
   ``%(conductor_name)s``     ``track_metadata.conductor_name``
   ``%(copyright)s``          ``track_metadata.copyright``
   ``%(date)s``               ``track_metadata.date``
   ``%(ISRC)s``               ``track_metadata.ISRC``
   ``%(media)s``              ``track_metadata.year``
   ``%(performer_name)s``     ``track_metadata.performer_name``
   ``%(publisher)s``          ``track_metadata.publisher``
   ``%(suffix)s``             the :class:`AudioFile` suffix
   ``%(track_name)s``         ``track_metadata.track_name``
   ``%(track_number)2.2d``    ``track_metadata.track_number``
   ``%(track_total)s``        ``track_metadata.track_total``
   ``%(year)s``               ``track_metadata.year``
   ``%(basename)s``           ``file_path`` basename without suffix
   ========================== ===============================================

.. classmethod:: AudioFile.supports_replay_gain()

   Returns ``True`` if this class supports ReplayGain metadata.

.. method:: AudioFile.get_replay_gain()

   Returns this audio file's ReplayGain values as a
   :class:`ReplayGain` object, or ``None`` if this audio file has no values.

.. method:: AudioFile.set_replay_gain(replaygain)

   Given a :class:`ReplayGain` object, sets the audio file's gain values.

   Raises :exc:`IOError` if unable to modify the file.

.. method:: AudioFile.delete_replay_gain()

   Removes any gain values from the file.

   Raises :exc:`IOError` if unable to modify the file.

.. classmethod:: AudioFile.supports_cuesheet()

   Returns ``True`` if the audio format supports embedded
   :class:`Sheet` objects.

.. method:: AudioFile.set_cuesheet(cuesheet)

   Given a :class:`Sheet` object, embeds a cuesheet in the track.
   This is for tracks which represent a whole CD image
   and wish to store track break data internally.
   May raise :exc:`IOError` if an error occurs writing the file.

.. method:: AudioFile.get_cuesheet()

   Returns a :class:`Sheet` object of a track's embedded cuesheet,
   or ``None`` if the track contains no cuesheet.
   May raise :exc:`IOError` if an error occurs reading the file.

.. method:: AudioFile.delete_cuesheet()

   Deletes embedded :class:`Sheet` object, if any.
   May raise :exc:`IOError` if an error occurs updating the file.

.. method:: AudioFile.clean([output_filename])

   Cleans the audio file of known data and metadata problems.

   ``output_filename`` is an optional string in which the fixed
   audio file is placed.
   If omitted, no actual fixes are performed.
   Note that this method never modifies the original file.

   Returns list of fixes performed as Unicode strings.

   Raises :exc:`IOError` if some error occurs when writing the new file.
   Raises :exc:`ValueError` if the file itself is invalid.

WaveContainer Objects
^^^^^^^^^^^^^^^^^^^^^

This is an abstract :class:`AudioFile` subclass suitable
for extending by formats that store RIFF WAVE chunks internally,
such as Wave, FLAC, WavPack and Shorten.
It overrides the :meth:`AudioFile.convert` method such that
any stored chunks are transferred properly from one file to the next.
This is accomplished by implementing three additional methods.

.. class:: WaveContainer

.. method:: WaveContainer.has_foreign_wave_chunks()

   Returns ``True`` if our object has non-audio RIFF WAVE chunks.

.. method:: WaveContainer.wave_header_footer()

   Returns ``(header, footer)`` tuple of strings
   where ``header`` is everything before the PCM data
   and ``footer`` is everything after the PCM data.

   May raise :exc:`ValueError` if there's a problem
   with the header or footer data, such as invalid chunk IDs.
   May raise :exc:`IOError` if there's a problem
   reading the header or footer data from the file.

.. classmethod:: WaveContainer.from_wave(filename, header, pcmreader, footer[, compression])

   Encodes a new file from wave data.
   ``header`` and ``footer`` are binary strings as returned by a
   :meth:`WaveContainer.wave_header_footer` method,
   ``pcmreader`` is a :class:`PCMReader` object
   and ``compression`` is a binary string.

   Returns a new :class:`AudioFile`-compatible object
   or raises :exc:`EncodingError` if some error occurs when
   encoding the file.

AiffContainer Objects
^^^^^^^^^^^^^^^^^^^^^

Much like :class:`WaveContainer`, this is an abstract
:class:`AudioFile` subclass suitable
for extending by formats that store AIFF chunks internally,
such as AIFF, FLAC and Shorten.
It overrides the :meth:`AudioFile.convert` method such that
any stored chunks are transferred properly from one file to the next.
This is accomplished by implementing three additional methods.

.. class:: AiffContainer

.. method:: AiffContainer.has_foreign_aiff_chunks()

   Returns ``True`` if our object has non-audio AIFF chunks.

.. method:: AiffContainer.aiff_header_footer()

   Returns ``(header, footer)`` tuple of strings
   where ``header`` is everything before the PCM data
   and ``footer`` is everything after the PCM data.

   May raise :exc:`ValueError` if there's a problem
   with the header or footer data, such as invalid chunk IDs.
   May raise :exc:`IOError` if there's a problem
   reading the header or footer data from the file.

.. classmethod:: AiffContainer.from_aiff(filename, header, pcmreader, footer[, compression])

   Encodes a new file from wave data.
   ``header`` and ``footer`` are binary strings as returned by a
   :meth:`AiffContainer.aiff_header_footer` method,
   ``pcmreader`` is a :class:`PCMReader` object
   and ``compression`` is a binary string.

   Returns a new :class:`AudioFile`-compatible object
   or raises :exc:`EncodingError` if some error occurs when
   encoding the file.

MetaData Objects
----------------

.. class:: MetaData([track_name][, track_number][, track_total][, album_name][, artist_name][, performer_name][, composer_name][, conductor_name][, media][, ISRC][, catalog][, copyright][, publisher][, year][, data][, album_number][, album_total][, comment][, images])

   The :class:`MetaData` class represents an :class:`AudioFile`'s
   non-technical metadata.
   It can be instantiated directly for use by the :meth:`set_metadata`
   method.
   However, the :meth:`get_metadata` method will typically return
   :class:`MetaData`-compatible objects corresponding to the audio file's
   low-level metadata implementation rather than actual :class:`MetaData`
   objects.
   Modifying fields within a :class:`MetaData`-compatible object
   will modify its underlying representation and those changes
   will take effect should :meth:`set_metadata` be called with
   that updated object.

   The ``images`` argument, if given, should be an iterable collection
   of :class:`Image`-compatible objects.

   MetaData attributes may be ``None``,
   which indicates the low-level implementation has
   no corresponding entry.
   For instance, ID3v2.3 tags use the ``"TALB"`` frame
   to indicate the track's album name.
   If that frame is present, an :class:`audiotools.ID3v23Comment`
   MetaData object will have an ``album_name`` field containing
   a Unicode string of its value.
   If that frame is not present in the ID3v2.3 tag,
   its ``album_name`` field will be ``None``.

   For example, to access a track's album name field:

   >>> metadata = track.get_metadata()
   >>> metadata.album_name
   u"Album Name"

   To change a track's album name field:

   >>> metadata = track.get_metadata()
   >>> metadata.album_name = u"Updated Album Name"
   >>> track.update_metadata(metadata)  # because metadata comes from track's get_metadata() method, one can use update_metadata()

   To delete a track's album name field:

   >>> metadata = track.get_metadata()
   >>> del(metadata.album_name)
   >>> track.update_metadata(metadata)

   Or to replace a track's entire set of metadata:

   >>> metadata = MetaData(track_name=u"Track Name",
   ...                     album_name=u"Updated Album Name",
   ...                     track_number=1,
   ...                     track_total=3)
   >>> track.set_metadata(metadata)  # because metadata is built from scratch, one must use set_metadata()

.. data:: MetaData.track_name

   This individual track's name as a Unicode string.

.. data:: MetaData.track_number

   This track's number within the album as an integer.

.. data:: MetaData.track_total

   The total number of tracks on the album as an integer.

.. data:: MetaData.album_name

   The name of this track's album as a Unicode string.

.. data:: MetaData.artist_name

   The name of this track's original creator/composer as a Unicode string.

.. data:: MetaData.performer_name

   The name of this track's performing artist as a Unicode string.

.. data:: MetaData.composer_name

   The name of this track's composer as a Unicode string.

.. data:: MetaData.conductor_name

   The name of this track's conductor as a Unicode string.

.. data:: MetaData.media

   The album's media type, such as u"CD", u"tape", u"LP", etc.
   as a Unicode string.

.. data:: MetaData.ISRC

   This track's ISRC value as a Unicode string.

.. data:: MetaData.catalog

   This track's album catalog number as a Unicode string.

.. data:: MetaData.year

   This track's album release year as a Unicode string.

.. data:: MetaData.date

   This track's album recording date as a Unicode string.

.. data:: MetaData.album_number

   This track's album number if it is one of a series of albums,
   as an integer.

.. data:: MetaData.album_total

   The total number of albums within the set, as an integer.

.. data:: MetaData.comment

   This track's comment as a Unicode string.

.. method:: MetaData.fields()

   Yields an ``(attr, value)`` tuple per :class:`MetaData` field.

.. method:: MetaData.filled_fields()

   Yields an ``(attr, value)`` tuple per non-blank :class:`MetaData` field.
   Non-blank fields are those with a value other than ``None``.

.. method:: MetaData.empty_fields()

   Yields an ``(attr, value)`` tuple per blank :class:`MetaData` field.
   Blank fields are those with a value of ``None``.

.. classmethod:: MetaData.converted(metadata)

   Takes a :class:`MetaData`-compatible object (or ``None``)
   and returns a new :class:`MetaData` object of the same class, or ``None``.
   For instance, ``VorbisComment.converted()`` returns ``VorbisComment``
   objects.
   The purpose of this classmethod is to offload metadata conversion
   to the metadata classes themselves.
   Therefore, by using the ``VorbisComment.converted()`` classmethod,
   the ``VorbisAudio`` class only needs to know how to handle
   ``VorbisComment`` metadata.

   Why not simply handle all metadata using this high-level representation
   and avoid conversion altogether?
   The reason is that :class:`MetaData` is often only a subset of
   what the low-level implementation can support.
   For example, a ``VorbisComment`` may contain the ``'FOO'`` tag
   which has no analogue in :class:`MetaData`'s list of fields.
   But when passed through the ``VorbisComment.converted()`` classmethod,
   that ``'FOO'`` tag will be preserved as one would expect.

   The key is that performing:

   >>> track.set_metadata(track.get_metadata())

   should always round-trip properly and not lose any metadata values.

.. classmethod:: MetaData.supports_images()

   Returns ``True`` if this :class:`MetaData` implementation supports images.
   Returns ``False`` if not.

.. method:: MetaData.images()

   Returns a list of :class:`Image`-compatible objects this metadata contains.

.. method:: MetaData.front_covers()

   Returns a subset of :meth:`images` which are marked as front covers.

.. method:: MetaData.back_covers()

   Returns a subset of :meth:`images` which are marked as back covers.

.. method:: MetaData.leaflet_pages()

   Returns a subset of :meth:`images` which are marked as leaflet pages.

.. method:: MetaData.media_images()

   Returns a subset of :meth:`images` which are marked as media.

.. method:: MetaData.other_images()

   Returns a subset of :meth:`images` which are marked as other.

.. method:: MetaData.add_image(image)

   Takes a :class:`Image`-compatible object and adds it to this
   metadata's list of images.

.. method:: MetaData.delete_image(image)

   Takes an :class:`Image` from this class, as returned by :meth:`images`,
   and removes it from this metadata's list of images.

.. method:: MetaData.clean()

   Returns a (:class:`MetaData`, ``fixes_performed``) tuple
   where ``MetaData`` is an object that's been cleaned of problems
   and ``fixes_performed`` is a list of unicode strings detailing
   those problems.
   Problems include:

   * Leading whitespace in text fields
   * Trailing whitespace in text fields
   * Empty fields
   * Leading zeroes in numerical fields
   * Incorrectly labeled image metadata fields

.. method:: MetaData.raw_info()

   Returns a Unicode string of raw metadata information
   with as little filtering as possible.
   This is meant to be useful for debugging purposes.

Image Objects
-------------

.. class:: Image(data, mime_type, width, height, color_depth, color_count, description, type)

   This class is a container for image data.

.. data:: Image.data

   A plain string of raw image bytes.

.. data:: Image.mime_type

   A Unicode string of this image's MIME type, such as u'image/jpeg'

.. data:: Image.width

   This image's width in pixels as an integer.

.. data:: Image.height

   This image's height in pixels as an integer

.. data:: Image.color_depth

   This image's color depth in bits as an integer.
   24 for JPEG, 8 for GIF, etc.

.. data:: Image.color_count

   For palette-based images, this is the number of colors the image contains
   as an integer.
   For non-palette images, this value is 0.

.. data:: Image.description

   A Unicode string of this image's description.

.. data:: Image.type

   An integer representing this image's type.

   ===== ============
   Value Type
   ----- ------------
   0     front cover
   1     back cover
   2     leaflet page
   3     media
   4     other
   ===== ============

.. method:: Image.suffix()

   Returns this image's typical filename suffix as a plain string.
   For example, JPEGs return ``"jpg"``

.. method:: Image.type_string()

   Returns this image's type as a plain string.
   For example, an image of type 0 returns ``"Front Cover"``

.. classmethod:: Image.new(image_data, description, type)

   Given a string of raw image bytes, a Unicode description string
   and image type integer, returns an :class:`Image`-compatible object.
   Raises :exc:`InvalidImage` If unable to determine the
   image type from the data string.

ReplayGain Objects
------------------

.. class:: ReplayGain(track_gain, track_peak, album_gain, album_peak)

   This is a simple container for ReplayGain values.

.. data:: ReplayGain.track_gain

   A float of a track's ReplayGain value.

.. data:: ReplayGain.track_peak

   A float of a track's peak value, from 0.0 to 1.0

.. data:: ReplayGain.album_gain

   A float of an album's ReplayGain value.

.. data:: ReplayGain.album_peak

   A float of an album's peak value, from 0.0 to 1.0

PCMReader Objects
-----------------

.. class:: PCMReader(sample_rate, channels, channel_mask, bits_per_sample)

   This is an abstract base class for streams of audio data
   which are file-like objects with additional stream parameters.
   Subclasses are expected to implement ``read`` and ``close``.

.. data:: PCMReader.sample_rate

   The sample rate of this audio stream, in Hz, as a positive integer.

.. data:: PCMReader.channels

   The number of channels in this audio stream as a positive integer.

.. data:: PCMReader.channel_mask

   The channel mask of this audio stream as a non-negative integer.

.. data:: PCMReader.bits_per_sample

   The number of bits-per-sample in this audio stream as a positive integer.

.. method:: PCMReader.read(pcm_frames)

   Try to read a :class:`pcm.FrameList` object with the given
   number of PCM frames, if possible.
   This method is *not* guaranteed to read that amount of frames.
   It may return less, particularly at the end of an audio stream.
   It may even return FrameLists larger than requested.
   However, it must always return a non-empty FrameList until the
   end of the PCM stream is reached.

   Once the end of the stream is reached, subsequent calls
   will return empty FrameLists.

   May raise :exc:`IOError` if there is a problem reading the
   source file, or :exc:`ValueError` if the source file has
   some sort of error.

.. method:: PCMReader.close()

   Closes the audio stream.
   If any subprocesses were used for audio decoding, they will also be
   closed and waited for their process to finish.

   Subsequent calls to :meth:`PCMReader.read` will
   raise :exc:`ValueError` exceptions once the stream is closed.

.. method:: PCMReader.__enter__()

   Returns the PCMReader.
   This is used for implementing context management.

.. method:: PCMReader.__exit__(exc_type, exc_value, traceback)

   Calls :meth:`PCMReader.close`.
   This is used for implementing context management.

PCMFileReader Objects
^^^^^^^^^^^^^^^^^^^^^

.. class:: PCMFileReader(file, sample_rate, channels, channel_mask, bits_per_sample[, process[, signed[, big_endian]]])

   This class wraps around file-like objects and generates
   :class:`pcm.FrameList` objects on each call to :meth:`read`.
   ``sample_rate``, ``channels``, ``channel_mask`` and ``bits_per_sample``
   should be integers.
   ``process`` is a subprocess helper object which generates PCM data.
   ``signed`` is ``True`` if the generated PCM data is signed.
   ``big_endian`` is ``True`` if the generated PCM data is big-endian.

PCMReaderError Objects
^^^^^^^^^^^^^^^^^^^^^^

.. class:: PCMReaderError(error_message, sample_rate, channels, channel_mask, bits_per_sample)

   This is a subclass of :class:`PCMReader` which always returns empty
   always raises a :class:`ValueError` when its read method is called.
   The purpose of this is to postpone error generation so that
   all encoding errors, even those caused by unsuccessful decoding,
   are restricted to the :meth:`from_pcm` classmethod
   which can then propagate an :class:`EncodingError` error message
   to the user.

PCMConverter Objects
^^^^^^^^^^^^^^^^^^^^

.. class:: PCMConverter(pcmreader, sample_rate, channels, channel_mask, bits_per_sample)

   This class takes an existing :class:`PCMReader`-compatible object
   along with a new set of ``sample_rate``, ``channels``,
   ``channel_mask`` and ``bits_per_sample`` values.
   Data from ``pcmreader`` is then automatically converted to
   the same format as those values.

.. data:: PCMConverter.sample_rate

   If the new sample rate differs from ``pcmreader``'s sample rate,
   audio data is automatically resampled on each call to :meth:`read`.

.. data:: PCMConverter.channels

   If the new number of channels is smaller than ``pcmreader``'s channel
   count, existing channels are removed or downmixed as necessary.
   If the new number of channels is larger, data from the first channel
   is duplicated as necessary to fill the rest.

.. data:: PCMConverter.channel_mask

   If the new channel mask differs from ``pcmreader``'s channel mask,
   channels are removed as necessary such that the proper channel
   only outputs to the proper speaker.

.. data:: PCMConverter.bits_per_sample

   If the new bits-per-sample differs from ``pcmreader``'s
   number of bits-per-sample, samples are shrunk or enlarged
   as necessary to cover the full amount of bits.

.. method:: PCMConverter.read

   This method functions the same as the :meth:`PCMReader.read` method.

.. method:: PCMConverter.close

   This method functions the same as the :meth:`PCMReader.close` method.

BufferedPCMReader Objects
^^^^^^^^^^^^^^^^^^^^^^^^^

.. class:: BufferedPCMReader(pcmreader)

   This class wraps around an existing :class:`PCMReader` object.
   Its calls to :meth:`read` are guaranteed to return
   :class:`pcm.FrameList` objects as close to the requested amount
   of PCM frames as possible without going over by buffering data
   internally.

   The reason such behavior is not required is that we often
   don't care about the size of the individual FrameLists being
   passed from one routine to another.
   But on occasions when we need :class:`pcm.FrameList` objects
   to be of a particular size, this class can accomplish that.

CounterPCMReader Objects
^^^^^^^^^^^^^^^^^^^^^^^^

.. class:: CounterPCMReader(pcmreader)

   This class wraps around an existing :class:`PCMReader` object
   and keeps track of the number of bytes and frames written
   upon each call to ``read``.

.. attribute:: CounterPCMReader.frames_written

   The number of PCM frames written thus far.

.. method:: CounterPCMReader.bytes_written()

   The number of bytes written thus far.

ReorderedPCMReader Objects
^^^^^^^^^^^^^^^^^^^^^^^^^^

.. class:: ReorderedPCMReader(pcmreader, channel_order)

   This class wraps around an existing :class:`PCMReader` object.
   It takes a list of channel number integers
   (which should be the same as ``pcmreader``'s channel count)
   and reorders channels upon each call to :meth:`read`.

   For example, to swap channels 0 and 1 in a stereo stream,
   one could do the following:

   >>> reordered = ReorderedPCMReader(original, [1, 0])

   Calls to ``reordered.read()`` will then have the left channel
   on the right side and vice versa.

PCMCat Objects
^^^^^^^^^^^^^^

.. class:: PCMCat(pcmreaders)

   This class wraps around a list of :class:`PCMReader` objects
   and concatenates their output into a single output stream.

   If any of the readers has different attributes
   from the first reader in the stream, :exc:`ValueError` is raised
   at init-time.

PCMReaderWindow Objects
^^^^^^^^^^^^^^^^^^^^^^^

.. class:: PCMReaderWindow(pcmreader, initial_offset, total_pcm_frames, [forward_close=True])

   This class wraps around an existing :class:`PCMReader` object
   and truncates or extends its samples as needed.
   ``initial_offset``, if positive, indicates how many
   PCM frames to truncate from the beginning of the stream.
   If negative, the beginning of the stream is padded by
   that many PCM frames - all of which have a value of 0.
   ``total_pcm_frames`` indicates the total length of the stream
   as a non-negative number of PCM frames.
   If shorter than the actual length of the PCM reader's stream,
   the reader is truncated.
   If longer, the stream is extended by as many PCM frames as needed.
   Again, padding frames have a value of 0.

   If ``forward_close`` is True, calls to :meth:`PCMReaderWindow.close`
   are passed along to the wrapped :class:`PCMReader` object.
   Otherwise, the close is confined to the :class:`PCMReaderWindow`
   object.
   This may be necessary when encoding sub-streams from a larger
   stream in which closing the larger stream after each encode
   isn't desirable.

LimitedPCMReader Objects
^^^^^^^^^^^^^^^^^^^^^^^^

.. class:: LimitedPCMReader(buffered_pcmreader, total_pcm_frames)

   This class wraps around an existing :class:`BufferedPCMReader`
   and ensures that no more than ``total_pcm_frames`` will be read
   from that stream by limiting reads to it.

.. note::

   :class:`PCMReaderWindow` is designed primarily for handling
   sample offset values in a :class:`CDTrackReader`,
   or for skipping a potentially large number of samples
   in a stream.
   :class:`LimitedPCMReader` is designed for splitting a
   stream into several smaller streams without losing any PCM frames.

   Which to use for a given situation depends on whether one cares
   about consuming the samples outside of the sub-reader or not.

PCMReaderProgress Objects
^^^^^^^^^^^^^^^^^^^^^^^^^

.. class:: PCMReaderProgress(pcmreader, total_frames, progress)

   This class wraps around an existing :class:`PCMReader` object
   and generates periodic updates to a given ``progress`` function.
   ``total_frames`` indicates the total number of PCM frames
   in the PCM stream.

   >>> progress_display = SingleProgressDisplay(Messenger("audiotools"), u"encoding file")
   >>> pcmreader = source_audiofile.to_pcm()
   >>> source_frames = source_audiofile.total_frames()
   >>> target_audiofile = AudioType.from_pcm("target_filename",
   ...                                       PCMReaderProgress(pcmreader,
   ...                                                         source_frames,
   ...                                                         progress_display.update))


ReplayGainCalculator Objects
----------------------------

.. class:: ReplayGainCalculator(sample_rate)

   This class is for incrementally calculating ReplayGain
   for an album during decoding.
   All tracks calculated must have the same sample rate
   which may mean resampling them to that rate if necessary.

.. method:: ReplayGainCalculator.to_pcm(pcmreader)

   Given a :class:`PCMReader` object,
   returns a :class:`ReplayGainCalculatorReader`
   linked to this calculator.

.. method:: ReplayGainCalculator.__iter__()

   Yields ``(title_gain, title_peak, album_gain, album_peak)`` tuples
   for each :class:`PCMReader` processed with
   :meth:`ReplayGainCalculator.to_pcm`
   in the order in which they were processed.

ReplayGainCalculatorReader Objects
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. class:: ReplayGainCalculatorReader(replaygain, pcmreader)

   These objects are typically returned from
   :meth:`ReplayGainCalculator.to_pcm` rather
   than instantiated directly.
   They function as :class:`PCMReader` objects
   which process the :class:`pcm.FrameList` objects
   returned by ``read`` prior to returning them.

.. method:: ReplayGainCalculatorReader.title_gain()

   Returns the title gain of the whole track as a floating point value.

.. method:: ReplayGainCalculatorReader.title_peak()

   Returns the title peak of the whole track as a floating point value.

ChannelMask Objects
-------------------

.. class:: ChannelMask(mask)

   This is an integer-like class that abstracts channel assignments
   into a set of bit fields.

   ======= =========================
   Mask    Speaker
   ------- -------------------------
   0x1     ``front_left``
   0x2     ``front_right``
   0x4     ``front_center``
   0x8     ``low_frequency``
   0x10    ``back_left``
   0x20    ``back_right``
   0x40    ``front_left_of_center``
   0x80    ``front_right_of_center``
   0x100   ``back_center``
   0x200   ``side_left``
   0x400   ``side_right``
   0x800   ``top_center``
   0x1000  ``top_front_left``
   0x2000  ``top_front_center``
   0x4000  ``top_front_right``
   0x8000  ``top_back_left``
   0x10000 ``top_back_center``
   0x20000 ``top_back_right``
   ======= =========================

   All channels in a :class:`pcm.FrameList` will be in RIFF WAVE order
   as a sensible convention.
   But which channel corresponds to which speaker is decided by this mask.
   For example, a 4 channel PCMReader with the channel mask ``0x33``
   corresponds to the bits ``00110011``

   Reading those bits from right to left (least significant first)
   the ``front_left``, ``front_right``, ``back_left``, ``back_right``
   speakers are set.
   Therefore, the PCMReader's 4 channel FrameLists are laid out as follows:

   0. ``front_left``
   1. ``front_right``
   2. ``back_left``
   3. ``back_right``

   Since the ``front_center`` and ``low_frequency`` bits are not set,
   those channels are skipped in the returned FrameLists.

   Many formats store their channels internally in a different order.
   Their :class:`PCMReader` objects will be expected to reorder channels
   and set a :class:`ChannelMask` matching this convention.
   And, their :func:`from_pcm` classmethods will be expected
   to reverse the process.

   A :class:`ChannelMask` of 0 is "undefined",
   which means that channels aren't assigned to *any* speaker.
   This is an ugly last resort for handling formats
   where multi-channel assignments aren't properly defined.
   In this case, a :func:`from_pcm` classmethod is free to assign
   the undefined channels any way it likes, and is under no obligation
   to keep them undefined when passing back out to :meth:`to_pcm`

.. method:: ChannelMask.defined()

   Returns ``True`` if this mask is defined.

.. method:: ChannelMask.undefined()

   Returns ``True`` if this mask is undefined.

.. method:: ChannelMask.channels()

   Returns the speakers this mask contains as a list of strings
   in the order they appear in the PCM stream.

.. method:: ChannelMask.index(channel_name)

   Given a channel name string, returns the index of that channel
   within the PCM stream.
   For example:

   >>> mask = ChannelMask(0xB)     #fL, fR, LFE, but no fC
   >>> mask.index("low_frequency")
   2

.. classmethod:: ChannelMask.from_fields(**fields)

   Takes channel names as function arguments and returns a
   :class:`ChannelMask` object.

   >>> mask = ChannelMask.from_fields(front_right=True,
   ...                                front_left=True,
   ...                                front_center=True)
   >>> int(mask)
   7

.. classmethod:: ChannelMask.from_channels(channel_count)

   Takes a channel count integer and returns a :class:`ChannelMask` object.

.. warning::

   :func:`from_channels` *only* works for 1 and 2 channel counts
   and is meant purely as a convenience method for mono or stereo streams.
   All other values will trigger a :exc:`ValueError`

CD Lookups
^^^^^^^^^^

.. function:: metadata_lookup(musicbrainz_disc_id, freedb_disc_id, [musicbrainz_server], [musicbrainz_port], [freedb_server], [freedb_port], [use_musicbrainz], [use_freedb])

   Given a :class:`audiotools.musicbrainz.DiscID` and
   :class:`audiotools.freedb.DiscID`, returns a
   ``metadata[c][t]`` list of lists
   where ``c`` is a possible choice and ``t`` is the :class:`MetaData`
   for a given track (starting from 0).

   This will always return a list of :class:`MetaData` objects
   for at least one choice.
   In the event that no matches for the CD can be found,
   those objects will only contain ``track_number`` and ``track_total``
   fields.

.. function:: cddareader_metadata_lookup(cddareader, [musicbrainz_server], [musicbrainz_port], [freedb_server], [freedb_port], [use_musicbrainz], [use_freedb])

   Given a :class:`cdio.CDDAReader` object,
   returns ``metadata[c][t]`` list of lists
   where ``c`` is a possible choice and ``t`` is the :class:`MetaData`
   for a given track (starting from 0).

   This will always return a list of :class:`MetaData` objects
   for at least one choice.
   In the event that no matches for the CD can be found,
   those objects will only contain ``track_number`` and ``track_total``
   fields.

.. function:: track_metadata_lookup(audiofiles, [, musicbrainz_server][, musicbrainz_port][, freedb_server][, freedb_port][, use_musicbrainz][, use_freedb])

   Given a sorted list of :class:`AudioFile` objects,
   returns ``metadata[c][t]`` list of lists
   where ``c`` is a possible choice and ``t`` is the :class:`MetaData`
   for a given track (starting from 0).

   This will always return a list of :class:`MetaData` objects
   for at least one choice.
   In the event that no matches for the CD can be found,
   those objects will only contain ``track_number`` and ``track_total``
   fields.

.. function:: sheet_metadata_lookup(sheet, total_pcm_frames, sample_rate, [, musicbrainz_server][, musicbrainz_port][, freedb_server][, freedb_port][, use_musicbrainz][, use_freedb])

   Given a :class:`Sheet` object, total number of PCM frames
   and the disc's sample rate,
   returns ``metadata[c][t]`` list of lists
   where ``c`` is a possible choice and ``t`` is the :class:`MetaData`
   for a given track (starting from 0).

   This will always return a list of :class:`MetaData` objects
   for at least one choice.
   In the event that no matches for the CD can be found,
   those objects will only contain ``track_number`` and ``track_total``
   fields.

.. function:: accuraterip_lookup(sorted_tracks[, server][, port])

   Given a list of :class:`AudioFile` objects sorted by
   track number, returns a
   ``{track_number:[(confidence, checksum, alt), ...], ...}``
   dict of values retrieved from the AccurateRip database
   where ``track_number`` is an int starting from 1,
   ``confidence`` is the number of people with the same people
   with a matching ``checksum`` of the track.

   May return a dict of empty lists if no AccurateRip entry is found.

   May return :exc:`urllib2.HTTPError` if an error occurs
   querying the server.

.. function:: accuraterip_sheet_lookup(sheet, total_pcm_frames, sample_rate[, server][, port])

   Given a :class:`Sheet` object, total number of PCM frames and sample rate,
   returns a
   ``{track_number:[(confidence, checksum, alt), ...], ...}``
   dict of values retrieved from the AccurateRip database
   where ``track_number`` is an int starting from 1,
   ``confidence`` is the number of people with the same people
   with a matching ``checksum`` of the track.

   May return a dict of empty lists if no AccurateRip entry is found.

   May return :exc:`urllib2.HTTPError` if an error occurs
   querying the server.

Cuesheets
---------

Sheet Objects
^^^^^^^^^^^^^

These objects represent a CDDA layout such as provided
by a ``.cue`` or ``.toc`` file.
This can be used to recreate the exact layout of the disc
when burning a set of tracks back to CD.

.. class:: Sheet(sheet_tracks, [metadata])

   ``sheet_tracks`` is a list of :class:`SheetTrack` objects,
   one per track on the CD.
   ``metadata`` is a :class:`MetaData` object or None

.. classmethod:: Sheet.converted(sheet)

   Given a :class:`Sheet`-compatible object,
   returns a :class:`Sheet` object.

.. method:: Sheet.__len__()

   Returns the number of tracks in the sheet.

.. method:: Sheet.__getitem__(track_index)

   Given a track index (starting from 0), returns a
   :class:`SheetTrack` object.
   Raises :exc:`IndexError` if the track cannot be found.

.. method:: Sheet.track_numbers()

   Returns a list of all track numbers in the sheet.

.. method:: Sheet.track(track_number)

   Given a track number (often starting from 1),
   returns a :class:`SheetTrack` object with that number.
   Raises :exc:`KeyError` if the track cannot be found.

.. method:: Sheet.pre_gap()

   Returns the disc's pre-gap
   (the amount of empty samples before the first track)
   as a :class:`Fraction` number of seconds.
   This number is often zero.

.. method:: Sheet.track_offset(track_number)

   Given a track number (often starting from 1),
   returns the offset to that track as a :class:`Fraction` number
   of seconds.

   May raise :exc:`KeyError` if the track cannot be found.

.. method:: Sheet.track_length(track_number)

   Given a track number (often starting from 1),
   returns the length of that track as a :class:`Fraction` number
   of seconds.

   May return ``None`` if the track is to use the remainder
   of the samples in the stream.
   This is typical of the last track in an album.

   May raise :exc:`KeyError` if the track cannot be found.

.. method:: Sheet.get_metadata()

   Returns a :class:`MetaData` object containing metadata
   for the entire sheet such as catalog number or CD-TEXT information.
   May return ``None`` if there is no such metadata.

SheetTrack Objects
^^^^^^^^^^^^^^^^^^

These objects represent a track on a given cuesheet.

.. class:: SheetTrack(number, track_indexes, [metadata], [filename], [is_audio=True], [pre_emphasis=False], [copy_permitted=False])

   =============== ============ ======================================
   argument        type         value
   --------------- ------------ --------------------------------------
   number          int          track number, starting from 1
   track_indexes   [SheetIndex] list of SheetIndex objects
   metadata        MetaData     track's metadata, or None
   filename        unicode      track's filename on disc
   is_audio        boolean      whether track contains audio data
   pre_emphasis    boolean      whether track has pre-emphasis
   copy_permitted  boolean      whether copying is permitted
   =============== ============ ======================================

.. classmethod:: SheetTrack.converted(sheet_track)

   Given a :class:`SheetTrack`-compatible object,
   returns a :class:`SheetTrack`.

.. method:: SheetTrack.__len__()

   Returns the number of :class:`SheetIndex` objects in the track.

.. method:: SheetTrack.__getitem__(i)

   Given an index (starting from 0), returns a track's
   :class:`SheetIndex` object.
   Raises :exc:`IndexError` if the index cannot be found.

.. method:: SheetTrack.indexes()

   Returns a list of all index numbers in the track.

.. method:: SheetTrack.index(sheet_index)

   Given an index number (often starting from 1),
   returns a track's :class:`SheetIndex` object.
   Raises :exc:`KeyError` if the index is not present.

.. method:: SheetTrack.number()

   Returns the track's number, typically starting from 1.

.. method:: SheetTrack.get_metadata()

   Returns the track's metadata such as ISRC and CD-TEXT information
   as a :class:`MetaData` object.
   May return ``None`` if it has no metadata.

.. method:: SheetTrack.filename()

   Returns the track's filename as a Unicode string.

.. method:: SheetTrack.is_audio()

   Returns whether the track contains audio data.

.. method:: SheetTrack.pre_emphasis()

   Returns whether the track has pre-emphasis.

.. method:: SheetTrack.copy_permitted()

   Returns whether copying is permitted.

SheetIndex Objects
^^^^^^^^^^^^^^^^^^

.. class:: SheetIndex(number, offset)

   ``number`` is the number of the index in the track,
   often starting from 1.
   A number of 0 indicates a pre-gap index.
   ``offset`` is the index's offset from the start of the
   stream as a :class:`Fraction` number of seconds.

.. method:: SheetIndex.number()

   Returns the track's index as an integer.

.. method:: SheetIndex.offset()

   Returns the index point's offset from the start of the stream
   as a :class:`Fraction` number of seconds.

DVDAudio Objects
----------------

.. class:: DVDAudio(audio_ts_path[, device])

   This class is used to access a DVD-Audio.
   It contains a collection of titlesets.
   Each titleset contains a list of
   :class:`audiotools.dvda.DVDATitle` objects,
   and each :class:`audiotools.dvda.DVDATitle` contains a list of
   :class:`audiotools.dvda.DVDATrack` objects.
   ``audio_ts_path`` is the path to the DVD-Audio's
   ``AUDIO_TS`` directory, such as ``/media/cdrom/AUDIO_TS``.
   ``device`` is the path to the DVD-Audio's mount device,
   such as ``/dev/cdrom``.

   For example, to access the 3rd :class:`DVDATrack` object
   of the 2nd :class:`DVDATitle` of the first titleset,
   one can simply perform the following:

   >>> track = DVDAudio(path)[0][1][2]

.. note::

   If ``device`` is indicated *and* the ``AUDIO_TS`` directory
   contains a ``DVDAUDIO.MKB`` file, unprotection will be
   performed automatically if supported on the user's platform.
   Otherwise, the files are assumed to be unprotected.

ExecQueue Objects
-----------------

.. class:: ExecQueue()

   This is a class for executing multiple Python functions in
   parallel across multiple CPUs.

.. method:: ExecQueue.execute(function, args[, kwargs])

   Queues a Python function, list of arguments and optional
   dictionary of keyword arguments.

.. method:: ExecQueue.run([max_processes])

   Executes all queued Python functions, running ``max_processes``
   number of functions at a time until the entire queue is empty.
   This operates by forking a new subprocess per function,
   executing that function and then, regardless of the function's result,
   the child job performs an unconditional exit.

   This means that any side effects of executed functions have
   no effect on ExecQueue's caller besides those which modify
   files on disk (encoding an audio file, for example).

.. class:: ExecQueue2()

   This is a class for executing multiple Python functions in
   parallel across multiple CPUs and receiving results
   from those functions.

.. method:: ExecQueue2.execute(function, args[, kwargs])

   Queues a Python function, list of arguments and optional
   dictionary of keyword arguments.

.. method:: ExecQueue2.run([max_processes])

   Executes all queued Python functions, running ``max_processes``
   number of functions at a time until the entire queue is empty.
   Returns an iterator of the returned values of those functions.
   This operates by forking a new subprocess per function
   with a pipe between them, executing that function in the child process
   and then transferring the resulting pickled object back to the parent
   before performing an unconditional exit.

   Queued functions that raise an exception or otherwise exit uncleanly
   yield ``None``.
   Likewise, any side effects of the called function have no
   effect on ExecQueue's caller.

ExecProgressQueue Objects
-------------------------

.. class:: ExecProgressQueue(messenger)

   This class runs multiple jobs in parallel and displays their
   progress output to the given :class:`Messenger` object.

.. method:: ExecProgressQueue.execute(function[, progress_text[, completion_output[, *args[, **kwargs]]]])

   Queues a Python function for execution.
   This function is passed the optional ``args`` and ``kwargs``
   arguments upon execution.
   However, this function is also passed an *additional* ``progress``
   keyword argument which is a function that takes the current progress
   value as a :class:`Fraction` object between 0 and 1, inclusive.
   The executed function can then call that ``progress`` function
   at regular intervals to indicate its progress.

   If given, ``progress_text`` is a Unicode string to be displayed
   while the function is being executed.

   ``completion_output`` is displayed once the executed function is
   completed.
   It can be either a Unicode string or a function whose argument
   is the returned result of the executed function and which must
   output either a Unicode string or ``None``.
   If ``None``, no output text is generated for the completed job.

.. method:: ExecProgressQueue.run([max_processes])

   Executes all the queued functions, running ``max_processes`` number
   of functions at a time until the entire queue is empty.
   Returns the results of the called functions in the order
   in which they were added for execution.
   This operates by forking a new subprocess per function
   in which the running progress and function output are
   piped to the parent for display to the screen.

   If an exception occurs in one of the subprocesses,
   that exception will be raised by :meth:`ExecProgressQueue.run`
   and all the running jobs will be terminated.

   >>> def progress_function(progress, filename):
   ...   # perform work here
   ...   progress(Fraction(current, total))
   ...   # more work
   ...   result.a = a
   ...   result.b = b
   ...   result.c = c
   ...   return result
   ...
   >>> def format_result(result):
   ...    return u"%s %s %s" % (result.a, result.b, result.c)
   ...
   >>> queue = ExecProgressQueue(ProgressDisplay(Messenger("executable")))
   >>> queue.execute(function=progress_function,
   ...               progress_text=u"%s progress" % (filename1),
   ...               completion_output=format_result,
   ...               filename=filename1)
   ...
   >>> queue.execute(function=progress_function,
   ...               progress_text=u"%s progress" % (filename2),
   ...               completion_output=format_result,
   ...               filename=filename2)
   ...
   >>> queue.run()


Messenger Objects
-----------------

.. class:: Messenger(silent=False)

   This is a helper class for displaying program data,
   analogous to a primitive logging facility.
   If ``silent`` is ``True``, the output methods will not
   actually display any output to the screen.

.. method:: Messenger.output(string)

   Outputs Unicode ``string`` to stdout and adds a newline,
   unless ``verbosity`` level is ``"silent"``.

.. method:: Messenger.partial_output(string)

   Output Unicode ``string`` to stdout and flushes output
   so it is displayed, but does not add a newline.
   Does nothing if ``verbosity`` level is ``"silent"``.

.. method:: Messenger.info(string)

   Outputs Unicode ``string`` to stdout and adds a newline,
   unless ``verbosity`` level is ``"silent"``.

.. method:: Messenger.partial_info(string)

   Output Unicode ``string`` to stdout and flushes output
   so it is displayed, but does not add a newline.
   Does nothing if ``verbosity`` level is ``"silent"``.

.. note::

   What's the difference between :meth:`Messenger.output` and :meth:`Messenger.info`?
   :meth:`Messenger.output` is for a program's primary data.
   :meth:`Messenger.info` is for incidental information.
   For example, trackinfo uses :meth:`Messenger.output` for what it
   displays since that output is its primary function.
   But track2track uses :meth:`Messenger.info` for its lines of progress
   since its primary function is converting audio
   and tty output is purely incidental.

.. method:: Messenger.warning(string)

   Outputs warning text, Unicode ``string`` and a newline to stderr,
   unless ``verbosity`` level is ``"silent"``.

   >>> m = audiotools.Messenger()
   >>> m.warning(u"Watch Out!")
   *** Warning: Watch Out!

.. method:: Messenger.error(string)

   Outputs error text, Unicode ``string`` and a newline to stderr.

   >>> m.error(u"Fatal Error!")
   *** Error: Fatal Error!

.. method:: Messenger.os_error(oserror)

   Given an :class:`OSError` object, displays it as a properly formatted
   error message with an appended newline.

.. note::

   This is necessary because of the way :class:`OSError` handles
   its embedded filename string.
   Using this method ensures that filename is properly encoded when
   displayed.
   Otherwise, there's a good chance that non-ASCII filenames will
   be garbled.

.. method:: Messenger.output_isatty()

   Returns ``True`` if the output method sends to a TTY rather than a file.

.. method:: Messenger.info_isatty()

   Returns ``True`` if the info method sends to a TTY rather than a file.

.. method:: Messenger.error_isatty()

   Returns ``True`` if the error method sends to a TTY rather than a file.

.. method:: Messenger.ansi_clearline()

   Generates a ANSI escape codes to clear the current line.

   This works only if ``stdout`` is a TTY, otherwise is does nothing.

   >>> msg = Messenger()
   >>> msg.partial_output(u"working")
   >>> time.sleep(1)
   >>> msg.ansi_clearline()
   >>> msg.output(u"done")

.. method:: Messenger.ansi_uplines(self, lines)

   Moves the cursor upwards by the given number of lines.

.. method:: Messenger.ansi_cleardown(self)

   Clears all the output below the current line.
   This is typically used in conjunction with :meth:`Messenger.ansi_uplines`.

   >>> msg = Messenger()
   >>> msg.output(u"line 1")
   >>> msg.output(u"line 2")
   >>> msg.output(u"line 3")
   >>> msg.output(u"line 4")
   >>> time.sleep(2)
   >>> msg.ansi_uplines(4)
   >>> msg.ansi_cleardown()
   >>> msg.output(u"done")

.. method:: Messenger.terminal_size(fd)

   Given a file descriptor integer, or file object with a fileno() method,
   returns the size of the current terminal as a (``height``, ``width``)
   tuple of integers.

ProgressDisplay Objects
-----------------------

.. class:: ProgressDisplay(messenger)

   This is a class for displaying incremental progress updates to the screen.
   It takes a :class:`Messenger` object which is used for generating
   output.
   Whether or not :attr:`sys.stdout` is a TTY determines how
   this class operates.
   If a TTY is detected, screen updates are performed incrementally
   with individual rows generated and refreshed as needed using
   ANSI escape sequences such that the user's screen need not scroll.
   If a TTY is not detected, most progress output is omitted.

.. method:: ProgressDisplay.add_row(output_line)

   ``output_line`` is a Unicode string indicating what
   we're displaying the progress of.
   Returns a :class:`ProgressRow` object which can be updated
   with the current progress for display.

.. method:: ProgressDisplay.remove_row(row_index)

   Removes the given row index and frees the slot for reuse.

.. method:: ProgressDisplay.display_rows()

   Outputs the current state of all progress rows.

.. method:: ProgressDisplay.clear_row()

   Clears all previously displayed output rows, if any.

.. class:: ProgressRow(progress_display, row_index, output_line)

   This is used by :class:`ProgressDisplay` and its subclasses
   for actual output generation.
   ``progress_display`` is a parent :class:`ProgressDisplay` object.
   ``row_index`` is this row's index on the screen.
   ``output_line`` is a unicode string.
   It is not typically instantiated directly.

.. method:: ProgressRow.update(progress)

   Updates the current progress as a :class:`Fraction` between
   0 and 1, inclusive.

.. method:: ProgressRow.finish()

   Indicate output is finished and the row will no longer be needed.

.. method:: ProgressRow.unicode(width)

   Returns the output line and its current progress as a Unicode string,
   formatted to the given width in onscreen characters.
   Screen width can be determined from the :meth:`Messenger.terminal_size`
   method.

.. class:: SingleProgressDisplay(messenger, progress_text)

   This is a subclass of :class:`ProgressDisplay` used
   for generating only a single line of progress output.
   As such, one only specifies a single row of Unicode ``progress_text``
   at initialization time and can avoid the row management functions
   entirely.

.. method:: SingleProgressDisplay.update(progress)

   Updates the status of our output row with the current progress,
   which is a :class:`Fraction` between 0 and 1, inclusive.

.. class:: ReplayGainProgressDisplay(messenger, lossless_replay_gain)

   This is another :class:`ProgressDisplay` subclass optimized
   for the display of ReplayGain application progress.
   ``messenger`` is a :class:`Messenger` object and
   ``lossless_replay_gain`` is a boolean indicating whether
   ReplayGain is being applied losslessly or not
   (which can be determined from the :meth:`AudioFile.lossless_replay_gain`
   classmethod).
   Whether or not :attr:`sys.stdout` is a TTY determines how
   this class behaves.

.. method:: ReplayGainProgressDisplay.initial_message()

   If operating on a TTY, this does nothing since progress output
   will be displayed.
   Otherwise, this indicates that ReplayGain application has begun.

.. method:: ReplayGainProgressDisplay.update(progress)

   Updates the status of ReplayGain application with the current progress
   which is a :class:`Fraction` between 0 and 1, inclusive.

.. method:: ReplayGainProgressDisplay.final_message()

   If operating on a TTY, this indicates that ReplayGain application
   is complete.
   Otherwise, this does nothing.

   >>> rg_progress = ReplayGainProgressDisplay(messenger, AudioType.lossless_replay_gain())
   >>> rg_progress.initial_message()
   >>> AudioType.add_replay_gain(filename_list, rg_progress.update)
   >>> rg_Progress.final_message()

output_text Objects
^^^^^^^^^^^^^^^^^^^

This class is for displaying portions of a Unicode string to
the screen and applying formatting such as color via ANSI escape
sequences.

The reason this is needed is because not all Unicode characters
are the same width when displayed to the screen.
So, for example, if one wishes to display a portion of a Unicode string to
a screen that's 80 ASCII characters wide, one can't simply perform:

>>> messenger.output(unicode_string[0:80])

since some of those Unicode characters might be double width,
which would cause the string to wrap.

.. class:: output_text(unicode_string[, fg_color][, bg_color][, style])

   ``unicode_string`` is the text to display.
   ``fg_color`` and ``bg_color`` may be one of
   ``"black"``, ``"red"``, ``"green"``, ``"yellow"``,
   ``"blue"``, ``"magenta"``, ``"cyan"``, or ``"white"``.
   ``style`` may be one of
   ``"bold"``, ``"underline"``, ``"blink"`` or ``"inverse"``.

.. method:: output_text.__unicode__

   Returns the raw Unicode string.

.. method:: output_text.__len__

   Returns the width of the text in displayed characters.

.. method:: output_text.fg_color()

   Returns the foreground color as a string, or ``None``.

.. method:: output_text.bg_color()

   Returns the background color as a string, or ``None``.

.. method:: output_text.style()

   Returns the style as a string, or ``None``.

.. method:: output_text.set_format([fg_color][, bg_color][, style])

   Returns a new :class:`output_text` object with the given styles.

.. method:: output_text.format([is_tty])

   If formatting is present and ``is_tty`` is ``True``,
   returns a Unicode string with ANSI escape sequences applied.
   Otherwise, returns the Unicode string with no ANSI formatting.

.. method:: output_text.head(display_characters)

   Returns a new :class:`output_text` object that's been
   truncated up to the given number of display characters,
   but may return less.

   >>> s = u"".join(map(unichr, range(0x30a1, 0x30a1+25)))
   >>> len(s)
   25
   >>> u = unicode(output_text(s).head(40))
   >>> len(u)
   20
   >>> print repr(u)
   u'\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8\u30a9\u30aa\u30ab\u30ac\u30ad\u30ae\u30af\u30b0\u30b1\u30b2\u30b3\u30b4'

.. note::

   Because some characters are double-width, this method
   along with :meth:`output_text.tail` and :meth:`output_text.split`
   may not return strings that are the same length as requested
   if the dividing point in the middle of a character.

.. method:: output_text.tail(display_characters)

   Returns a new :class:`output_text` object that's been
   truncated up to the given number of display characters.

   >>> s = u"".join(map(unichr, range(0x30a1, 0x30a1+25)))
   >>> len(s)
   25
   >>> u = unicode(output_text(s).tail(40))
   >>> len(u)
   20
   >>> print repr(u)
   u'\u30a6\u30a7\u30a8\u30a9\u30aa\u30ab\u30ac\u30ad\u30ae\u30af\u30b0\u30b1\u30b2\u30b3\u30b4\u30b5\u30b6\u30b7\u30b8\u30b9'

.. method:: output_text.split(display_characters)

   Returns a tuple of :class:`output_text` objects.
   The first is up to ``display_characters`` wide,
   while the second contains the remainder.

   >>> s = u"".join(map(unichr, range(0x30a1, 0x30a1+25)))
   >>> (head, tail) = display_unicode(s).split(40)
   >>> print repr(unicode(head))
   u'\u30a1\u30a2\u30a3\u30a4\u30a5\u30a6\u30a7\u30a8\u30a9\u30aa\u30ab\u30ac\u30ad\u30ae\u30af\u30b0\u30b1\u30b2\u30b3\u30b4'
   >>> print repr(unicode(tail))
   u'\u30b5\u30b6\u30b7\u30b8\u30b9'

.. method:: output_text.join(output_texts)

   Given an iterable collection of :class:`output_text` objects,
   returns an :class:`output_list` joined by our formatted text.

output_list Objects
^^^^^^^^^^^^^^^^^^^

output_list is an :class:`output_text` subclass
for formatting multiple :class:`output_text` objects as a unit.

.. class:: output_list(output_texts[, fg_color][, bg_color][, style])

   ``output_texts`` is an iterable collection of
   :class:`output_text` or unicode objects.
   ``fg_color`` and ``bg_color`` may be one of
   ``"black"``, ``"red"``, ``"green"``, ``"yellow"``,
   ``"blue"``, ``"magenta"``, ``"cyan"``, or ``"white"``.
   ``style`` may be one of
   ``"bold"``, ``"underline"``, ``"blink"`` or ``"inverse"``.

.. warning::

   Formatting is unlikely to nest properly since
   ANSI is un-escaped to the terminal default.
   Therefore, if the :class:`output_list` has formatting,
   its contained :class:`output_text` objects should not have formatting.
   Or if the :class:`output_text` objects do have formatting,
   the :class:`output_list` container should not have formatting.

.. method:: output_list.fg_color()

   Returns the foreground color as a string, or ``None``.

.. method:: output_list.bg_color()

   Returns the background color as a string, or ``None``.

.. method:: output_list.style()

   Returns the style as a string, or ``None``.

.. method:: output_list.set_format([fg_color][, bg_color][, style])

   Returns a new :class:`output_list` object with the given formatting.

.. method:: output_list.format([is_tty])

   If formatting is present and ``is_tty`` is ``True``,
   returns a Unicode string with ANSI escape sequences applied.
   Otherwise, returns the Unicode string with no ANSI formatting.

.. method:: output_list.head(display_characters)

   Returns a new :class:`output_list` object that's been
   truncated up to the given number of display characters,
   but may return less.

.. method:: output_list.tail(display_characters)

   Returns a new :class:`output_list` object that's been
   truncated up to the given number of display characters.

.. method:: output_list.split(display_characters)

   Returns a tuple of :class:`output_text` objects.
   The first is up to ``display_characters`` wide,
   while the second contains the remainder.

.. method:: output_list.join(output_texts)

   Given an iterable collection of :class:`output_text` objects,
   returns an :class:`output_list` joined by our formatted text.

output_table Objects
^^^^^^^^^^^^^^^^^^^^

output_table is for formatting text into rows and columns.

.. class:: output_table()

.. method:: output_table.row()

   Adds new row to table and returns :class:`output_table_row` object
   which columns may be added to.

.. method:: output_table.blank_row()

   Adds empty row to table whose columns will be blank.

.. method:: output_table.divider_row(dividers)

   Takes a list of Unicode characters, one per column,
   and generates a row which will expand those characters
   as needed to fill each column.

.. method:: output_table.format([is_tty])

   Yields one formatted Unicode string per row.
   If ``is_tty`` is ``True``, rows may contain ANSI escape sequences
   for color and style.

output_table_row Objects
^^^^^^^^^^^^^^^^^^^^^^^^

output_table_row is a container for table columns
and is returned from :meth:`output_table.row()`
rather than instantiated directly.

.. class:: output_table_row()

.. method:: output_table_row.__len__()

   Returns the total number of columns in the table.

.. method:: output_table_row.add_column(text[, alignment="left"][, colspan=1])

   Adds text, which may be a Unicode string or
   :class:`output_text` object.
   ``alignment`` may be ``"left"``, ``"center"`` or ``"right"``.
   If `colspan` is greater than 1, the column is widened to span
   that many other non-spanning columns.

.. method:: output_table_row.column_width(column)

   Returns the width of the given column in printable characters.

.. method:: output_table_row.format(column_widths[, is_tty])

   Given a list of column widths, returns the table row
   as a Unicode string such that each column is padded to the
   corresponding width depending on its alignment.
   If ``is_tty`` is ``True``, columns may contain ANSI escape
   sequences for color and style.

Exceptions
----------

.. exception:: UnknownAudioType

   Raised by :func:`filename_to_type` if the file's suffix is unknown.

.. exception:: AmbiguousAudioType

   Raised by :func:`filename_to_type` if the file's suffix
   applies to more than one audio class.

.. exception:: DecodingError

   Raised by :class:`PCMReader`'s .close() method if
   a helper subprocess exits with an error,
   typically indicating a problem decoding the file.

.. exception:: DuplicateFile

   Raised by :func:`open_files` if the same file
   is included more than once and ``no_duplicates`` is indicated.

.. exception:: DuplicateOutputFile

   Raised by :func:`audiotools.ui.process_output_options`
   if the same output file is generated more than once.

.. exception:: EncodingError

   Raised by :meth:`AudioFile.from_pcm` and :meth:`AudioFile.convert`
   if an error occurs when encoding an input file.
   This includes errors from the input stream,
   a problem writing the output file in the given location,
   or EncodingError subclasses such as
   :exc:`UnsupportedBitsPerSample` if the input stream
   is formatted in a way the output class does not support.

.. exception:: InvalidFile

   Raised by :meth:`AudioFile.__init__` if the file
   is invalid in some way.

.. exception:: InvalidFilenameFormat

   Raised by :meth:`AudioFile.track_name` if the format string
   contains broken fields.

.. exception:: InvalidImage

   Raised by :meth:`Image.new` if the image cannot be parsed correctly.

.. exception:: OutputFileIsInput

   Raised by :func:`process_output_options` if an output file
   is the same as any of the input files.

.. exception:: SheetException

   A parent exception of :exc:`audiotools.cue.CueException`
   and :exc:`audiotools.toc.TOCException`,
   to be raised by :func:`read_sheet` if a .toc or .cue file
   is unable to be parsed correctly.

.. exception:: UnsupportedBitsPerSample

   Subclass of :exc:`EncodingError`, indicating
   the input stream's bits-per-sample is not supported
   by the output class.

.. exception:: UnsupportedChannelCount

   Subclass of :exc:`EncodingError`, indicating
   the input stream's channel count is not supported
   by the output class.

.. exception:: UnsupportedChannelMask

   Subclass of :exc:`EncodingError`, indicating
   the input stream's channel mask is not supported
   by the output class.

.. exception:: UnsupportedFile

   Raised by :func:`open` if the given file is not something
   identifiable, or we do not have the installed binaries to support.

.. exception:: UnsupportedTracknameField

   Raised by :meth:`AudioFile.track_name` if a track name
   field is not supported.
