diff --git a/beetsplug/replaygain.py b/beetsplug/replaygain.py index ba57481ea..82d8893a6 100644 --- a/beetsplug/replaygain.py +++ b/beetsplug/replaygain.py @@ -464,10 +464,21 @@ class GStreamerBackend(object): class AudioToolsBackend(Backend): + """ + ReplayGain backend that uses `Python Audio Tools + `_ and its capabilities to read more + file formats and compute ReplayGain values using it replaygain module. + """ def __init__(self, config): self._import_audiotools() def _import_audiotools(self): + """ + Checks if it's possible the necessary modules. There is no check on the + file formats at runtime. + + :raises :exc:`ReplayGainError`: if the modules cannot be imported + """ try: import audiotools import audiotools.replaygain @@ -479,6 +490,14 @@ class AudioToolsBackend(Backend): self._mod_replaygain = audiotools.replaygain def open_audio_file(self, item): + """ + Open the file to read the PCM stream from the using ``item.path`` + + :return: the audiofile instance + :rtype: :class:`audiotools.AudioFile` + :raises :exc:`ReplayGainError`: if the file is not found or the file format is + not supported + """ try: audiofile = self._mod_audiotools.open(item.path) except IOError: @@ -493,6 +512,16 @@ class AudioToolsBackend(Backend): return audiofile def init_replaygain(self, audiofile, item): + """ + Returns an initialized :class:`audiotools.replaygain.ReplayGain` + instance, which requires the sample rate of the song(s) on which + the ReplayGain values will be computed. The item is passed in case + the sample rate is invalid to log the stored item sample rate. + + :return: initialized replagain object + :rtype: :class:`audiotools.replaygain.ReplayGain` + :raises: :exc:`ReplayGainError` if the sample rate is invalid + """ try: rg = self._mod_replaygain.ReplayGain(audiofile.sample_rate()) except ValueError: @@ -503,11 +532,24 @@ class AudioToolsBackend(Backend): return rg def compute_track_gain(self, items): + """ + Compute ReplayGain values for the requested items. + + :return list: list of :class:`Gain` objects + """ return [self._compute_track_gain(item) for item in items] def _compute_track_gain(self, item): + """ + Compute ReplayGain value for the requested item. + + :rtype: :class:`Gain` + """ audiofile = self.open_audio_file(item) rg = self.init_replaygain(audiofile, item) + #each call to title_gain on a replaygain object return peak and gain of + #the track. Note that the method need an audiotools.PCMReader instance + #that can be obtained from an audiofile instance rg_track_gain, rg_track_peak = rg.title_gain(audiofile.to_pcm()) log.debug( @@ -521,6 +563,11 @@ class AudioToolsBackend(Backend): return Gain(gain=rg_track_gain, peak=rg_track_peak) def compute_album_gain(self, album): + """ + Compute ReplayGain values for the requested album and its items. + + :rtype: :class:`AlbumGain` + """ log.debug( u'Analysing album {0} - {1}'.format( album.albumartist, @@ -528,6 +575,9 @@ class AudioToolsBackend(Backend): ) ) + #the first item is taken and opened to get the sample rate to + #initialize the replaygain object. The object is used for all the + #tracks in the album to get the album values. item = list(album.items())[0] audiofile = self.open_audio_file(item) rg = self.init_replaygain(audiofile, item) @@ -548,6 +598,8 @@ class AudioToolsBackend(Backend): ) ) + #after getting the values for all tracks, it's possible to get the + #album values rg_album_gain, rg_album_peak = rg.album_gain() log.debug( u'ReplayGain for Album {0} - {1}: {2:.2f}, {3:.2f}'.format(