Merge branch 'v0.22.x' into master

This commit is contained in:
Max Kellermann 2020-10-16 19:02:03 +02:00
commit 4f0e0af319
4 changed files with 57 additions and 18 deletions

3
NEWS
View File

@ -3,6 +3,9 @@ ver 0.23 (not yet released)
- new command "getvol"
ver 0.22.1 (not yet released)
* decoder
- opus: apply the OpusHead output gain even if there is no EBU R128 tag
- opus: fix track/album ReplayGain fallback
* output
- alsa: don't deadlock when the ALSA driver is buggy
- jack, pulse: reduce the delay when stopping or pausing playback

View File

@ -377,8 +377,8 @@ ffmpeg = FfmpegProject(
)
curl = AutotoolsProject(
'http://curl.haxx.se/download/curl-7.72.0.tar.xz',
'0ded0808c4d85f2ee0db86980ae610cc9d165e9ca9da466196cc73c346513713',
'http://curl.haxx.se/download/curl-7.73.0.tar.xz',
'7c4c7ca4ea88abe00fea4740dcf81075c031b1d0bb23aff2d5efde20a3c2408a',
'lib/libcurl.a',
[
'--disable-shared', '--enable-static',

View File

@ -63,6 +63,17 @@ IsOpusTags(const ogg_packet &packet) noexcept
return packet.bytes >= 8 && memcmp(packet.packet, "OpusTags", 8) == 0;
}
/**
* Convert an EBU R128 value to ReplayGain.
*/
constexpr float
EbuR128ToReplayGain(float ebu_r128) noexcept
{
/* add 5dB to compensate for the different reference levels
between ReplayGain (89dB) and EBU R128 (-23 LUFS) */
return ebu_r128 + 5;
}
bool
mpd_opus_init([[maybe_unused]] const ConfigBlock &block)
{
@ -76,10 +87,11 @@ class MPDOpusDecoder final : public OggDecoder {
opus_int16 *output_buffer = nullptr;
/**
* The output gain from the Opus header. Initialized by
* OnOggBeginning().
* The output gain from the Opus header in dB that should be
* applied unconditionally, but is often used specifically for
* ReplayGain. Initialized by OnOggBeginning().
*/
signed output_gain;
float output_gain;
/**
* The pre-skip value from the Opus header. Initialized by
@ -111,6 +123,14 @@ class MPDOpusDecoder final : public OggDecoder {
*/
ogg_int64_t granulepos;
/**
* Was DecoderClient::SubmitReplayGain() called? We need to
* keep track of this, because it will usually be called by
* HandleTags(), but if there is no OpusTags packet, we need
* to submit our #output_gain value from the OpusHead.
*/
bool submitted_replay_gain = false;
public:
explicit MPDOpusDecoder(DecoderReader &reader)
:OggDecoder(reader) {}
@ -170,10 +190,14 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
throw std::runtime_error("BOS packet must be OpusHead");
unsigned channels;
if (!ScanOpusHeader(packet.packet, packet.bytes, channels, output_gain, pre_skip) ||
signed output_gain_i;
if (!ScanOpusHeader(packet.packet, packet.bytes, channels, output_gain_i, pre_skip) ||
!audio_valid_channel_count(channels))
throw std::runtime_error("Malformed BOS packet");
/* convert Q7.8 fixed-point to float */
output_gain = float(output_gain_i) / 256.0f;
granulepos = 0;
skip = pre_skip;
@ -245,22 +269,22 @@ MPDOpusDecoder::HandleTags(const ogg_packet &packet)
ReplayGainInfo rgi;
rgi.Clear();
/**
* Output gain is a Q7.8 fixed point number in dB that should be,
* applied unconditionally, but is often used specifically for
* ReplayGain. Add 5dB to compensate for the different
* reference levels between ReplayGain (89dB) and EBU R128 (-23 LUFS).
*/
rgi.track.gain = float(output_gain) / 256.0f + 5;
rgi.album.gain = float(output_gain) / 256.0f + 5;
TagBuilder tag_builder;
AddTagHandler h(tag_builder);
if (!ScanOpusTags(packet.packet, packet.bytes, &rgi, h))
return;
client.SubmitReplayGain(&rgi);
if (rgi.IsDefined()) {
/* submit all valid EBU R128 values with output_gain
applied */
if (rgi.track.IsDefined())
rgi.track.gain += EbuR128ToReplayGain(output_gain);
if (rgi.album.IsDefined())
rgi.album.gain += EbuR128ToReplayGain(output_gain);
client.SubmitReplayGain(&rgi);
submitted_replay_gain = true;
}
if (!tag_builder.empty()) {
Tag tag = tag_builder.Commit();
@ -275,6 +299,18 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
{
assert(opus_decoder != nullptr);
if (!submitted_replay_gain) {
/* if we didn't see an OpusTags packet with EBU R128
values, we still need to apply the output gain
value from the OpusHead packet; submit it as "track
gain" value */
ReplayGainInfo rgi;
rgi.Clear();
rgi.track.gain = EbuR128ToReplayGain(output_gain);
client.SubmitReplayGain(&rgi);
submitted_replay_gain = true;
}
int nframes = opus_decode(opus_decoder,
(const unsigned char*)packet.packet,
packet.bytes,

View File

@ -61,7 +61,7 @@ ScanOneOpusTag(StringView name, StringView value,
const char *endptr;
const auto l = ParseInt64(value, &endptr, 10);
if (endptr > value.begin() && endptr == value.end())
rgi->track.gain += float(l) / 256.0f;
rgi->track.gain = float(l) / 256.0f;
} else if (rgi != nullptr &&
name.EqualsIgnoreCase("R128_ALBUM_GAIN")) {
/* R128_ALBUM_GAIN is a Q7.8 fixed point number in
@ -70,7 +70,7 @@ ScanOneOpusTag(StringView name, StringView value,
const char *endptr;
const auto l = ParseInt64(value, &endptr, 10);
if (endptr > value.begin() && endptr == value.end())
rgi->album.gain += float(l) / 256.0f;
rgi->album.gain = float(l) / 256.0f;
}
handler.OnPair(name, value);