mirror of
https://github.com/beetbox/beets.git
synced 2025-12-15 21:14:19 +01:00
fix bs1770gain for windows and exceptionally big albums
This commit is contained in:
parent
51cd6ad90e
commit
f1f7094938
2 changed files with 77 additions and 28 deletions
|
|
@ -94,7 +94,10 @@ class Bs1770gainBackend(Backend):
|
|||
def __init__(self, config, log):
|
||||
super(Bs1770gainBackend, self).__init__(config, log)
|
||||
cmd = b'bs1770gain'
|
||||
|
||||
try:
|
||||
self.chunk_at = config['chunk_at'].as_number()
|
||||
except:
|
||||
self.chunk_at = 5000
|
||||
try:
|
||||
self.method = b'--' + config['method'].get(str)
|
||||
except:
|
||||
|
|
@ -132,6 +135,21 @@ class Bs1770gainBackend(Backend):
|
|||
|
||||
return AlbumGain(output[-1], output[:-1])
|
||||
|
||||
def isplitter(self, items, chunk_at):
|
||||
iterable = iter(items)
|
||||
while True:
|
||||
result = []
|
||||
for i in range(chunk_at):
|
||||
try:
|
||||
a = next(iterable)
|
||||
except StopIteration:
|
||||
break
|
||||
else:
|
||||
result.append(a)
|
||||
if result:
|
||||
yield result
|
||||
else:
|
||||
break
|
||||
def compute_gain(self, items, is_album):
|
||||
"""Computes the track or album gain of a list of items, returns
|
||||
a list of TrackGain objects.
|
||||
|
|
@ -142,6 +160,24 @@ class Bs1770gainBackend(Backend):
|
|||
if len(items) == 0:
|
||||
return []
|
||||
|
||||
albumgaintot = 0.0
|
||||
albumpeaktot = 0.0
|
||||
returnchunks = []
|
||||
|
||||
if len(items) > self.chunk_at:
|
||||
i = 0
|
||||
for chunk in self.isplitter(items, self.chunk_at):
|
||||
i += 1
|
||||
returnchunk = self.compute_chunk_gain(chunk, is_album)
|
||||
albumgaintot += returnchunk[-1].gain
|
||||
albumpeaktot += returnchunk[-1].peak
|
||||
returnchunks = returnchunks + returnchunk[0:-1]
|
||||
returnchunks.append(Gain(albumgaintot/i, albumpeaktot/i))
|
||||
return returnchunks
|
||||
else:
|
||||
return self.compute_chunk_gain(items, is_album)
|
||||
|
||||
def compute_chunk_gain(self, items, is_album):
|
||||
"""Compute ReplayGain values and return a list of results
|
||||
dictionaries as given by `parse_tool_output`.
|
||||
"""
|
||||
|
|
@ -149,14 +185,18 @@ class Bs1770gainBackend(Backend):
|
|||
cmd = [self.command]
|
||||
cmd = cmd + [self.method]
|
||||
cmd = cmd + [b'-it']
|
||||
cmd = cmd + [syspath(i.path) for i in items]
|
||||
|
||||
self._log.debug(u'analyzing {0} files', len(items))
|
||||
self._log.debug(u"executing {0}", " ".join(map(displayable_path, cmd)))
|
||||
output = call(cmd)
|
||||
self._log.debug(u'analysis finished')
|
||||
# workaround for windows MAX_PATH prefix, will get problems
|
||||
# when path is too long on windows
|
||||
try:
|
||||
output = call(cmd + [syspath(i.path) for i in items])
|
||||
if not output:
|
||||
output = call(cmd + [syspath(i.path, prefix=False) for i in items])
|
||||
except:
|
||||
self._log.debug(u'bsgain1770 failed')
|
||||
self._log.debug(u'analysis finished:{0}', output)
|
||||
results = self.parse_tool_output(output,
|
||||
len(items) + is_album)
|
||||
self._log.debug(u'{0} items/ {1} results', len(items), len(results))
|
||||
return results
|
||||
|
||||
def parse_tool_output(self, text, num_lines):
|
||||
|
|
@ -166,25 +206,23 @@ class Bs1770gainBackend(Backend):
|
|||
"""
|
||||
out = []
|
||||
data = text.decode('utf8', errors='ignore')
|
||||
regex = ("(\s{2,2}\[\d+\/\d+\].*?|\[ALBUM\].*?)(?=\s{2,2}\[\d+\/\d+\]"
|
||||
"|\s{2,2}\[ALBUM\]:|done\.$)")
|
||||
|
||||
results = re.findall(regex, data, re.S | re.M)
|
||||
for ll in results[0:num_lines]:
|
||||
parts = ll.split(b'\n')
|
||||
if len(parts) == 0:
|
||||
regex = re.compile(ur'(\s{2,2}\[\d+\/\d+\].*?|\[ALBUM\].*?)(?=\s{2,2}\[\d+\/\d+\]|\s{2,2}\[ALBUM\]:|done\.\s)', re.DOTALL | re.UNICODE)
|
||||
results = re.findall(regex, data)
|
||||
for parts in results[0:num_lines]:
|
||||
part = parts.split(b'\n')
|
||||
if len(part) == 0:
|
||||
self._log.debug(u'bad tool output: {0!r}', text)
|
||||
raise ReplayGainError('bs1770gain failed')
|
||||
|
||||
d = {
|
||||
'file': parts[0],
|
||||
'gain': float((parts[1].split('/'))[1].split('LU')[0]),
|
||||
'peak': float(parts[2].split('/')[1]),
|
||||
}
|
||||
|
||||
self._log.info('analysed {}gain={};peak={}',
|
||||
d['file'].rstrip(), d['gain'], d['peak'])
|
||||
out.append(Gain(d['gain'], d['peak']))
|
||||
try:
|
||||
song = {
|
||||
'file': part[0],
|
||||
'gain': float((part[1].split('/'))[1].split('LU')[0]),
|
||||
'peak': float(part[2].split('/')[1]),
|
||||
}
|
||||
except IndexError:
|
||||
self._log.info(u'bs1770gain reports(faulty file?):{}', parts)
|
||||
else:
|
||||
out.append(Gain(song['gain'], song['peak']))
|
||||
return out
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -78,10 +78,11 @@ On OS X, most of the dependencies can be installed with `Homebrew`_::
|
|||
bs1770gain
|
||||
``````````
|
||||
|
||||
In order to use this backend, you will need to install the bs1770gain command-line tool. Here are some hints:
|
||||
In order to use this backend, you will need to install the bs1770gain command-line tool.
|
||||
Here are some hints:
|
||||
|
||||
* goto `bs1770gain`_ and follow the download instructions
|
||||
* make sure it is in your $PATH
|
||||
* make sure it is in your $PATH
|
||||
|
||||
.. _bs1770gain: http://bs1770gain.sourceforge.net/
|
||||
|
||||
|
|
@ -91,6 +92,14 @@ backend in your configuration file::
|
|||
replaygain:
|
||||
backend: bs1770gain
|
||||
|
||||
IMPORTANT for windows users:
|
||||
Untill bs1770gain accepts very long Paths, you will get problems if your
|
||||
Pathname exceeds the windows-limit.
|
||||
AND to avoid other problems with paths...untill further notice ...please use
|
||||
|
||||
asciify_paths: true
|
||||
|
||||
in your config.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
|
@ -117,13 +126,15 @@ These options only work with the "command" backend:
|
|||
would keep clipping from occurring.
|
||||
Default: ``yes``.
|
||||
|
||||
This option only works with the "bs1770gain" backend:
|
||||
These options only works with the "bs1770gain" backend:
|
||||
|
||||
- **method**: The loudness scanning standard: either `replaygain` for
|
||||
ReplayGain 2.0, `ebu` for EBU R128, or `atsc` for ATSC A/85. This dictates
|
||||
the reference level: -18, -23, or -24 LUFS respectively. Default:
|
||||
`replaygain`
|
||||
|
||||
- **chunk_at**: Splits an album in groups of tracks of this amount.
|
||||
Usefull when running into memory problems when analysing albums with
|
||||
an exceptionally large amount of tracks. Default:5000
|
||||
|
||||
Manual Analysis
|
||||
---------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue