Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Bs1770gainBackend to handle bs1770gain v0.6.0 XML output #3480

Merged
merged 10 commits into from
Feb 5, 2020

Conversation

ybnd
Copy link
Contributor

@ybnd ybnd commented Jan 30, 2020

Fixes #3479.

ybnd added 2 commits January 30, 2020 16:13
* Remove `0%\x08\x08` from output (backspace code doesn't resolve; progress percentages get spliced in)

* Handle changed attributes/fields:
  * `sample-peak` attribute `factor` is called `amplitude` instead
  * Album summary is not included in a `summary` tag now, but in two separate `integrated` and `sample-peak` tags

* Handle `lu` attribute

* Get bs1770gain version
  * If v0.6.0 or later, add `--unit=ebu` flag to convert `db` attributes to LUFS
  * May be useful later on

### Output examples

Track:
```
<!-- analyzing ... -->
<bs1770gain norm="-18.00">
  <track total="1" number="1" file="02 tïtle 0.mp3">
    <integrated lufs="-70.00" lu="52.00"/>
    <sample-peak spfs="-72.28" amplitude="0.00"/>
  </track>
  <integrated lufs="-70.00" lu="52.00"/>
  <sample-peak spfs="-72.28" amplitude="0.00"/>
</bs1770gain>
<!-- done. -->
```

Album:
```
<!-- analyzing ... -->
<bs1770gain norm="-18.00">
  <track total="2" number="1" file="02 tïtle 0.mp3">
    <integrated dbfs="-70.00" db="52.00"/>
    <sample-peak dbfs="-72.28" amplitude="0.00"/>
  </track>
  <track total="2" number="2" file="02 tïtle 1.mp3">
    <integrated dbfs="-70.00" db="52.00"/>
    <sample-peak dbfs="-72.28" amplitude="0.00"/>
  </track>
  <integrated dbfs="-70.00" db="52.00"/>
  <sample-peak dbfs="-72.28" amplitude="0.00"/>
</bs1770gain>
<!-- done. -->
```
@ybnd ybnd changed the title Bs1770gain v0.6.0 parsing Update Bs1770gainBackend parsing to handle bs1770gain v0.6.0 XML output Jan 30, 2020
* Fix unspecified `gain_adjustment` when method defined in config

* Fix difference between dB and LUFS values in case of mismatched `target_level`/`method`:

  ```
  db_to_lufs( target_level <dB> ) - lufs_to_dB( -23 <LUFS> )
  ```

* Ignore single assertion in case of bs1770gain

(cherry picked from commit 2395bf2)
@ybnd ybnd changed the title Update Bs1770gainBackend parsing to handle bs1770gain v0.6.0 XML output Update Bs1770gainBackend to handle bs1770gain v0.6.0 XML output Jan 30, 2020
ybnd added a commit to ybnd/beets that referenced this pull request Jan 30, 2020
* With `bs1770gain` installed the `Bs1770gainBackend` tests fail, but this should be fixed by beetbox#3480.
Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool; thanks for attacking this! Here are a few ideas.

'([0-9]+.[0-9]+.[0-9]+), ',
call([cmd, '--version']).stdout.decode('utf-8')
).group(1)
except AttributeError:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m a little confused—what is the potential AttributeError here? Is it the stdout attribute of the call result?

Maybe it would be nicer to just do a single call to check both whether the command exists and to get its version. Then we’d just need to handle OSError, I think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's the stdout attribute.
Ok, I suppose there's no real chance that some weird version bs1770gain doesn't handle --version.

if type(text) == bytes:
text = text.decode('utf-8')
while '\x08' in text:
text = re.sub('[^\x08]\x08', '', text)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This replacement is somewhat surprising! Maybe a comment would be useful here to describe what’s going wrong?

parser.StartElementHandler = start_element_handler
parser.EndElementHandler = end_element_handler

try:
if type(text) == bytes:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if type(text) == bytes:
if isinstance(text, bytes):

parser.StartElementHandler = start_element_handler
parser.EndElementHandler = end_element_handler

try:
if type(text) == bytes:
text = text.decode('utf-8')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to do this conversion, or shall we perhaps just do the substitution directly on the bytes (with a bytes pattern)? That would avoid hard-coding an encoding, for example...

parser.StartElementHandler = start_element_handler
parser.EndElementHandler = end_element_handler

try:
if type(text) == bytes:
text = text.decode('utf-8')
while '\x08' in text:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be safer to loop until the string stops changing. Otherwise, this runs the risk of this character being present but the pattern not matching (e.g., if it occurs at the beginning of the string).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it seems more readable to cover that case in the pattern by also replacing \x08 at the start of the string

b'[^\x08]\x08|^\x08'

then I can just explain it in a comment since I should write a bit about what's going on here anyway (:

ybnd added 2 commits January 30, 2020 19:21
* safer version comparison

* regex bytes directly

* handle b'\x08 ...' case

* test_replaygain.py: injected command output should match the type of the actual output
Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! I have a couple of questions within, but I think this is basically ready to go. Would you mind adding a quick changelog entry?

except OSError:
raise FatalReplayGainError(
u'Is bs1770gain installed?'
)
except AttributeError:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reorganization, but I'm still not 100% sure when this exception can be raised. Isn't it the case that the command_output object will always have a stdout member if the call was successful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an edge case in test_replaygain where the backend is tested while bypassing calls to bs1770gain.
It was patching None to stdout there, I made it patch bs1770gain 0.0.0, instead.

@ybnd ybnd requested a review from sampsyo February 5, 2020 08:07
Copy link
Member

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks lovely; thank you for your persistence!

@sampsyo sampsyo merged commit 817bef2 into beetbox:master Feb 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

replaygain: bs1770gain v0.6.0 XML output can't be parsed
2 participants