From a9fd03bb97f1bb08cd460f9a4a8d0c34334ece23 Mon Sep 17 00:00:00 2001
From: Moonbase59 <moonbase@quantentunnel.de>
Date: Sun, 29 Sep 2019 17:17:48 +0200
Subject: [PATCH 1/2] Add possible ReplayGain values for loudgain

---
 mediafile.py           | 143 +++++++++++++++++++++++++++++++++++++++++
 test/test_mediafile.py |   3 +
 2 files changed, 146 insertions(+)

diff --git a/mediafile.py b/mediafile.py
index 4ac373a..ae204fe 100644
--- a/mediafile.py
+++ b/mediafile.py
@@ -1437,6 +1437,30 @@ def __set__(self, mediafile, value):
         super(QNumberField, self).__set__(mediafile, q_num)
 
 
+class ReferenceLoudnessField(MediaField):
+    """Access loudness reference field
+
+    Access a floating point replaygain loudness reference field, which could be
+    negative (LUFS) or positive (dB). dB values will be converted to LUFS
+    so we get a uniform representation within beets. (LUFS = dB - 107.0)
+    """
+    def __init__(self, *args, **kwargs):
+        super(ReferenceLoudnessField, self).__init__(*args, **kwargs)
+
+    def __get__(self, mediafile, owner=None):
+        value = super(ReferenceLoudnessField, self).__get__(mediafile, owner)
+        if value is None:
+            return None
+        if value <= 0.0:
+            return value
+        return value - 107.0
+
+    def __set__(self, mediafile, value):
+        if value > 0.0:
+            value = value - 107.0
+        super(ReferenceLoudnessField, self).__set__(mediafile, value)
+
+
 class ImageListField(ListMediaField):
     """Descriptor to access the list of images embedded in tags.
 
@@ -1960,6 +1984,10 @@ def update(self, dict):
             index=0, desc=u'iTunNORM',
             id3_lang='eng'
         ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:REPLAYGAIN_TRACK_GAIN',
+            float_places=2, suffix=' dB'
+        ),
         MP4StorageStyle(
             '----:com.apple.iTunes:replaygain_track_gain',
             float_places=2, suffix=' dB'
@@ -1972,6 +2000,10 @@ def update(self, dict):
             u'REPLAYGAIN_TRACK_GAIN',
             float_places=2, suffix=u' dB'
         ),
+        ASFStorageStyle(
+            u'REPLAYGAIN_TRACK_GAIN',
+            float_places=2, suffix=u' dB'
+        ),
         ASFStorageStyle(
             u'replaygain_track_gain',
             float_places=2, suffix=u' dB'
@@ -1987,6 +2019,10 @@ def update(self, dict):
             u'replaygain_album_gain',
             float_places=2, suffix=u' dB'
         ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:REPLAYGAIN_ALBUM_GAIN',
+            float_places=2, suffix=' dB'
+        ),
         MP4StorageStyle(
             '----:com.apple.iTunes:replaygain_album_gain',
             float_places=2, suffix=' dB'
@@ -1995,6 +2031,10 @@ def update(self, dict):
             u'REPLAYGAIN_ALBUM_GAIN',
             float_places=2, suffix=u' dB'
         ),
+        ASFStorageStyle(
+            u'REPLAYGAIN_ALBUM_GAIN',
+            float_places=2, suffix=u' dB'
+        ),
         ASFStorageStyle(
             u'replaygain_album_gain',
             float_places=2, suffix=u' dB'
@@ -2015,6 +2055,10 @@ def update(self, dict):
             index=1, desc=u'iTunNORM',
             id3_lang='eng'
         ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:REPLAYGAIN_TRACK_PEAK',
+            float_places=6
+        ),
         MP4StorageStyle(
             '----:com.apple.iTunes:replaygain_track_peak',
             float_places=6
@@ -2024,6 +2068,7 @@ def update(self, dict):
             index=1
         ),
         StorageStyle(u'REPLAYGAIN_TRACK_PEAK', float_places=6),
+        ASFStorageStyle(u'REPLAYGAIN_TRACK_PEAK', float_places=6),
         ASFStorageStyle(u'replaygain_track_peak', float_places=6),
         out_type=float,
     )
@@ -2036,14 +2081,112 @@ def update(self, dict):
             u'replaygain_album_peak',
             float_places=6
         ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:REPLAYGAIN_ALBUM_PEAK',
+            float_places=6
+        ),
         MP4StorageStyle(
             '----:com.apple.iTunes:replaygain_album_peak',
             float_places=6
         ),
         StorageStyle(u'REPLAYGAIN_ALBUM_PEAK', float_places=6),
+        ASFStorageStyle(u'REPLAYGAIN_ALBUM_PEAK', float_places=6),
         ASFStorageStyle(u'replaygain_album_peak', float_places=6),
         out_type=float,
     )
+    rg_track_range = MediaField(
+        MP3DescStorageStyle(
+            u'REPLAYGAIN_TRACK_RANGE',
+            float_places=2, suffix=u' dB'
+        ),
+        MP3DescStorageStyle(
+            u'replaygain_track_range',
+            float_places=2, suffix=u' dB'
+        ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:REPLAYGAIN_TRACK_RANGE',
+            float_places=2, suffix=' dB'
+        ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:replaygain_track_range',
+            float_places=2, suffix=' dB'
+        ),
+        StorageStyle(
+            u'REPLAYGAIN_TRACK_RANGE',
+            float_places=2, suffix=u' dB'
+        ),
+        ASFStorageStyle(
+            u'REPLAYGAIN_TRACK_RANGE',
+            float_places=2, suffix=u' dB'
+        ),
+        ASFStorageStyle(
+            u'replaygain_track_range',
+            float_places=2, suffix=u' dB'
+        ),
+        out_type=float
+    )
+    rg_album_range = MediaField(
+        MP3DescStorageStyle(
+            u'REPLAYGAIN_ALBUM_RANGE',
+            float_places=2, suffix=u' dB'
+        ),
+        MP3DescStorageStyle(
+            u'replaygain_album_range',
+            float_places=2, suffix=u' dB'
+        ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:REPLAYGAIN_ALBUM_RANGE',
+            float_places=2, suffix=' dB'
+        ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:replaygain_album_range',
+            float_places=2, suffix=' dB'
+        ),
+        StorageStyle(
+            u'REPLAYGAIN_ALBUM_RANGE',
+            float_places=2, suffix=u' dB'
+        ),
+        ASFStorageStyle(
+            u'REPLAYGAIN_ALBUM_RANGE',
+            float_places=2, suffix=u' dB'
+        ),
+        ASFStorageStyle(
+            u'replaygain_album_range',
+            float_places=2, suffix=u' dB'
+        ),
+        out_type=float
+    )
+    rg_reference = ReferenceLoudnessField(
+        MP3DescStorageStyle(
+            u'REPLAYGAIN_REFERENCE_LOUDNESS',
+            float_places=2, suffix=u' LUFS'
+        ),
+        MP3DescStorageStyle(
+            u'replaygain_reference_loudness',
+            float_places=2, suffix=u' LUFS'
+        ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:REPLAYGAIN_REFERENCE_LOUDNESS',
+            float_places=2, suffix=' LUFS'
+        ),
+        MP4StorageStyle(
+            '----:com.apple.iTunes:replaygain_reference_loudness',
+            float_places=2, suffix=' LUFS'
+        ),
+        StorageStyle(
+            u'REPLAYGAIN_REFERENCE_LOUDNESS',
+            float_places=2, suffix=u' LUFS'
+        ),
+        ASFStorageStyle(
+            u'REPLAYGAIN_REFERENCE_LOUDNESS',
+            float_places=2, suffix=u' LUFS'
+        ),
+        ASFStorageStyle(
+            u'replaygain_reference_loudness',
+            float_places=2, suffix=u' LUFS'
+        ),
+        out_type=float
+    )
 
     # EBU R128 fields.
     r128_track_gain = QNumberField(
diff --git a/test/test_mediafile.py b/test/test_mediafile.py
index 8d1ea8b..6bec55b 100644
--- a/test/test_mediafile.py
+++ b/test/test_mediafile.py
@@ -375,8 +375,11 @@ class ReadWriteTestBase(ArtTestMixin, GenreListTestMixin,
         'label',
         'rg_track_peak',
         'rg_track_gain',
+        'rg_track_range',
         'rg_album_peak',
         'rg_album_gain',
+        'rg_album_range',
+        'rg_reference',
         'r128_track_gain',
         'r128_album_gain',
         'albumartist',

From 51a08ae3af686434850d1c7d566acfcfea55f127 Mon Sep 17 00:00:00 2001
From: Moonbase59 <moonbase@quantentunnel.de>
Date: Sun, 29 Sep 2019 17:37:43 +0200
Subject: [PATCH 2/2] Make unit test work (rg_reference=1.0 evaluates to -106.0

---
 test/test_mediafile.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/test_mediafile.py b/test/test_mediafile.py
index 6bec55b..39832f9 100644
--- a/test/test_mediafile.py
+++ b/test/test_mediafile.py
@@ -702,6 +702,8 @@ def _generate_tags(self, base=None):
                 tags[key] = -1
             else:
                 tags[key] = 'value\u2010%s' % key
+        # rg_reference = 1.0 would evaluate to -106.0
+        tags['rg_reference'] = -18.0
 
         for key in ['disc', 'disctotal', 'track', 'tracktotal', 'bpm']:
             tags[key] = 1