Skip to content

Commit

Permalink
Added support for preserving existing album gain via CLI argument
Browse files Browse the repository at this point in the history
  • Loading branch information
maszaa committed May 28, 2020
1 parent da64115 commit 4efc230
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 11 deletions.
4 changes: 4 additions & 0 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ tags are already present in the files. If you have files which had loudness
levels calculated using the old ReplayGain algorithm, you can use this option
to recalculate using the EBU R128 algorithm.

`-p`/`--preserve-album-gain` causes regainer to preserve existing album gain.
This is useful if you for example have multi-disc albums that have discs mastered
at different loudness levels. NOTE: Using `-f` overrides this argument.

`-j N` specifies the number of parallel jobs to run. By default it will
use all CPUs available on the system. You can use this to reduce the amount
of CPU that regainer will use.
Expand Down
40 changes: 29 additions & 11 deletions regainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def format_opus_gain(self, value):
if value < -32768 or value > 32767:
raise ValueError('Opus gain value out of range')
return "{:d}".format(value)


def read_gain_id3(self):
need_update = False
Expand Down Expand Up @@ -730,13 +730,18 @@ async def scan_album_gain(self):
gain_scanner = GainScanner()
self.gain = await gain_scanner.scan_album(included)

async def scan_gain(self):
album_task = asyncio.ensure_future(self.scan_album_gain())
track_tasks = [track.scan_gain() for track in self.tracks]
async def scan_gain(self, skip_album_scan=False):
tasks = [track.scan_gain() for track in self.tracks]

if not skip_album_scan:
album_task = asyncio.ensure_future(self.scan_album_gain())
tasks.append(album_task)

await asyncio.gather(album_task, *track_tasks)
await asyncio.gather(*tasks)

if not skip_album_scan:
self.gain.album_peak = max([t.gain.peak for t in self.tracks])

self.gain.album_peak = max([t.gain.peak for t in self.tracks])
for track in self.tracks:
track.gain.album_loudness = self.gain.album_loudness
track.gain.album_peak = self.gain.album_peak
Expand All @@ -745,30 +750,35 @@ async def write_tags(self):
track_tasks = [track.write_tags() for track in self.tracks]
await asyncio.gather(*track_tasks)

async def scan(self, force=False, skip_save=False):
async def scan(self, force=False, skip_save=False, preserve_album_gain=False):
await self.read_tags()

need_scan = False
skip_album_scan = False
for track in self.tracks:
if track.gain.loudness is None or track.gain.peak is None:
need_scan = True
if self.gain.album_loudness is None:
self.gain.album_loudness = track.gain.album_loudness
if self.gain.album_loudness != track.gain.album_loudness:
need_scan = True
need_scan = need_scan or not preserve_album_gain
skip_album_scan = preserve_album_gain
if self.gain.album_peak is None:
self.gain.album_peak = track.gain.album_peak
if self.gain.album_peak != track.gain.album_peak:
need_scan = True
need_scan = need_scan or not preserve_album_gain
skip_album_scan = preserve_album_gain
if self.gain.album_loudness is None or self.gain.album_peak is None:
need_scan = True
skip_album_scan = False
if force:
need_scan = True
skip_album_scan = False

need_save = any([track.tagger.need_album_update for track in self.tracks])

if need_scan:
await self.scan_gain()
await self.scan_gain(skip_album_scan)
need_save = True

if need_save:
Expand All @@ -781,6 +791,8 @@ async def scan(self, force=False, skip_save=False):
print(track.gain)
if need_scan:
print("Rescanned loudness")
if skip_album_scan:
print("Preserving missmatching album gains")
if need_save:
if not skip_save:
print("Updated tags")
Expand Down Expand Up @@ -808,6 +820,12 @@ def main(argv=None):
Recalculate the ReplayGain values even if valid tags are already
present in the files.
''')
parser.add_argument('-p', '--preserve-album-gain', default=False, action='store_true',
help='''
Preserve existing album ReplayGain values even if they missmatch within files.
Using this option will preserve different album gain values for given files.
Using -f/--force overrides this arguments.
''')
parser.add_argument('-j', '--jobs', type=int,
default=multiprocessing.cpu_count(),
help='''
Expand Down Expand Up @@ -855,7 +873,7 @@ def main(argv=None):

tasks = []
albums = [Album(album, job_sem) for album in args.album]
tasks += [album.scan(force=args.force, skip_save=args.dry_run)
tasks += [album.scan(force=args.force, skip_save=args.dry_run, preserve_album_gain=args.preserve_album_gain)
for album in albums]
tracks = [Track(track, job_sem) for track in args.track]
tasks += [track.scan(force=args.force, skip_save=args.dry_run)
Expand Down

0 comments on commit 4efc230

Please sign in to comment.