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

[question] Noise when playing 16-bit files and using default sample format #542

Open
edio opened this issue Apr 30, 2019 · 17 comments

Comments

Projects
None yet
2 participants
@edio
Copy link

commented Apr 30, 2019

When listening to 16-bit files on a sound-card that supports 24-bit, while having audio_output_format commented out, mpd produces quiet, but yet audible noise. Subjectively I would characterize the noise as having line spectrum, with the base frequency quite low (up to tens of Hz) but certainly having lots of higher harmonics. I could try to record it if necessary, but would be happy to avoid this activity :)

  • the issue reproduced on multiple computers with multiple different sound cards: e-mu 0404, audinst usb hud mini.
  • the issue reproduced both with ALSA and PulseAudio
  • when using software volume control in mpd, noise level does not depend on the volume level. This one suggests, that perhaps the noise is an artifact of sample conversion (maybe some dithering or some weird noise shaping) somewhere either in player, or in ALSA, or in HW of both soundcards I used
  • other players (cmus, deadbeef) do not have this issue

Today I discovered, that if I explicitly set sample format to

audio_output_format "*:24:2"

the noise disappears.

Since the workaround is found and I'm no longer impacted, I wouldn't say, that this is something requiring immediate attention.

But out of pure curiousity I'd like to understand what's going on, why MPD has noise for 16-bit files in its output if output format is not configured.

Please let me know if any additional information is required on this or if you'd like me to perform some tests or to attempt recording the noise.

P.S. I reported this before on an old Mantis tracker, however, couldn't provide good steps to reproduce back in the time.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Apr 30, 2019

Post verbose log of start of playback, and tell me your MPD version number.

@edio

This comment has been minimized.

Copy link
Author

commented Apr 30, 2019

With audio_output_format *:24:2

$ mpd --no-daemon --stderr /etc/mpd.conf 
...
client: [0] process command "playid "1""
playlist: play 0:"Silversun Pickups/2006 - Carnavas/08 Rusted Wheel.flac"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
decoder_thread: probing plugin flac
decoder: audio_format=44100:16:2, seekable=true
decoder: converting to 44100:24:2
exception: OutputThread could not get realtime scheduling, continuing anyway: sched_setscheduler failed: Operation not permitted
output: opened "Local PulseAudio server" (pulse) audio_format=44100:24:2
replay_gain: replay gain mode has changed off->album
replay_gain: scale=0.707946
replay_gain: scale=0.295461
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "stop"
playlist: stop
player: played "Silversun Pickups/2006 - Carnavas/08 Rusted Wheel.flac"
output: closed "Local PulseAudio server" (pulse)

With audio_output_format commented out

$ mpd --no-daemon --stderr /etc/mpd.conf 
...
client: [0] process command "playid "1""
playlist: play 0:"Silversun Pickups/2006 - Carnavas/08 Rusted Wheel.flac"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
decoder_thread: probing plugin flac
decoder: audio_format=44100:16:2, seekable=true
exception: OutputThread could not get realtime scheduling, continuing anyway: sched_setscheduler failed: Operation not permitted
output: opened "Local PulseAudio server" (pulse) audio_format=44100:16:2
replay_gain: replay gain mode has changed off->album
replay_gain: scale=0.707946
replay_gain: scale=0.295461
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "status"
client: [0] command returned 0
client: [0] process command "idle"
client: [0] command returned 1
client: [0] process command "stop"
playlist: stop
player: played "Silversun Pickups/2006 - Carnavas/08 Rusted Wheel.flac"
output: closed "Local PulseAudio server" (pulse)
...

Config with stripped comments

music_directory         "/mnt/sigma/media/music"
playlist_directory              "~/mpd.playlists"
db_file                 "~/mpd.db"
log_file                        "~/mpd.log"
pid_file                        "~/mpd.pid"
state_file                      "~/mpd.state"
user                            "mpd"
auto_update     "yes"
input {
        plugin "curl"
}
audio_output_format "*:24:2"
audio_output {
        type            "alsa"
        name            "Default ALSA Device"
}
audio_output {
        type            "pulse"
        name            "Local PulseAudio Server"
}
replaygain                      "album"
replaygain_preamp               "0"
replaygain_missing_preamp       "-6"
filesystem_charset              "UTF-8"

version

$ mpd --version
mpd --version
Music Player Daemon 0.21.7 (0.21.7)

Copyright 2003-2007 Warren Dukes <warren.dukes@gmail.com>
Copyright 2008-2018 Max Kellermann <max.kellermann@gmail.com>
This is free software; see the source for copying conditions.  There is NO
warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Database plugins:
 simple proxy upnp

Storage plugins:
 local smbclient udisks nfs curl

Neighbor plugins:
 smbclient upnp udisks

Decoders plugins:
 [mad] mp3 mp2
 [mpg123] mp3
 [vorbis] ogg oga
 [oggflac] ogg oga
 [flac] flac
 [opus] opus ogg oga
 [sndfile] wav aiff aif au snd paf iff svx sf voc w64 pvf xi htk caf sd2
 [audiofile] wav au aiff aif
 [dsdiff] dff
 [dsf] dsf
 [hybrid_dsd] m4a
 [faad] aac
 [mpcdec] mpc
 [wavpack] wv
 [modplug] 669 amf ams dbm dfm dsm far it med mdl mod mtm mt2 okt s3m stm ult umx xm
 [mikmod] amf dsm far gdm imf it med mod mtm s3m stm stx ult uni xm
 [wildmidi] mid
 [fluidsynth] mid
 [ffmpeg] 16sv 3g2 3gp 4xm 8svx aa3 aac ac3 adx afc aif aifc aiff al alaw amr anim apc ape asf atrac au aud avi avm2 avs bap bfi c93 cak cin cmv cpk daud dct divx dts dv dvd dxa eac3 film flac flc fli fll flx flv g726 gsm gxf iss m1v m2v m2t m2ts m4a m4b m4v mad mj2 mjpeg mjpg mka mkv mlp mm mmf mov mp+ mp1 mp2 mp3 mp4 mpc mpeg mpg mpga mpp mpu mve mvi mxf nc nsv nut nuv oga ogm ogv ogx oma ogg omg opus psp pva qcp qt r3d ra ram rl2 rm rmvb roq rpl rvc shn smk snd sol son spx str swf tak tgi tgq tgv thp ts tsp tta xa xvid uv uv2 vb vid vob voc vp6 vmd wav webm wma wmv wsaud wsvga wv wve
 [gme] ay gbs gym hes kss nsf nsfe sap spc vgm vgz
 [pcm]

Filters:
 libsamplerate soxr

Tag plugins:
 id3tag

Output plugins:
 shout null fifo pipe alsa ao oss openal solaris pulse jack httpd recorder

Encoder plugins:
 null vorbis opus lame twolame wave flac

Archive plugins:
 [bz2] bz2
 [zzip] zip
 [iso] iso

Input plugins:
 file archive alsa tidal qobuz curl ffmpeg smbclient nfs mms cdio_paranoia

Playlist plugins:
 extm3u m3u pls xspf asx rss soundcloud flac cue embcue

Protocols:
 file:// alsa:// tidal:// qobuz:// http:// https:// gopher:// rtp:// rtsp:// rtmp:// rtmpt:// rtmps:// smb:// nfs:// mms:// mmsh:// mmst:// mmsu:// cdda://

Other features:
 avahi dbus udisks epoll icu inotify ipv6 systemd tcp un
@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Apr 30, 2019

Does it work if you use the "alsa" output instead of "pulse"?

@edio

This comment has been minimized.

Copy link
Author

commented Apr 30, 2019

I just tried to force 16 bit output (I should've tried this in the very begginning), and I hear similar noise with 24-bit files.

So the issue is with 16-bit output.

@edio

This comment has been minimized.

Copy link
Author

commented Apr 30, 2019

@MaxKellermann , yes, with ALSA I have the same noise, as with PulseAudio. With ALSA though, the noise is much louder (at least on E-MU 0404 USB, I don't have Audinst on me right now)

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Apr 30, 2019

Try two more things:

  • configure an ALSA "hw:" device instead of using ALSA dmix (libasound's bad default)
  • disable ReplayGain
@edio

This comment has been minimized.

Copy link
Author

commented Apr 30, 2019

  • with hw0:0 reproduced
  • with replaygain "off" NOT reproduced
@edio

This comment has been minimized.

Copy link
Author

commented Apr 30, 2019

Another note, with replaygain "off" and audio_output_format "*:16:2" 24-bit files have similar noise (but subjectively with few times higher base frequency).
I'd expect downsampling to impact sound quality, but I frankly would not expect the result to be this severe.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Apr 30, 2019

Applying software volume (which ReplayGain does, unless you configure it to use a hardware mixer) and converting 24 bit to 16 bit both uses dithering. So the problem may be MPD's dithering code.

@edio

This comment has been minimized.

Copy link
Author

commented Apr 30, 2019

Should we qualify this issue as a bug then? (I'll remove the [quesiton] part from the title in this case).

Is there anything else I can do to help fixing the issue? (except for preparing a PR 😅 , I haven't ever written a line of production-grade C or C++ code)

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Apr 30, 2019

Not yet - we don't know for sure if it's a bug. You can't do anything right now, thanks for the information so far, that was useful. (Unless you want to dig into MPD source code, see https://github.com/MusicPlayerDaemon/MPD/blob/master/src/pcm/PcmDither.cxx for the heart of the dithering code)

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented Apr 30, 2019

I checked the dithering code back and forth, and found no problem. Manipulating the volume on 16 bit samples works just fine, no noise (except for the floor noise caused by dithering, which is the very point of dithering). Same for converting 24 bit to 16 bit.

There is a unit test for this; you can run it with ninja test (Meson needs to be configured with -Dtest=true).

Can you record MPD's digital audio from a PulseAudio monitor? I'd like to see the noise.

@edio

This comment has been minimized.

Copy link
Author

commented May 3, 2019

Sorry making you wait.

Here's how the noise looks like.
image

Recordings are not exactly accurate because monitor, it seems, always records in 44100 Hz (which is also obvious from file sizes)

command I used to record

$ timeout 2 bash -c 'parec -d mpd.monitor > 16_44.pcm' & bash -c 'mpc play && sleep 2 && mpc stop'

In mpd config I have audio_output_format "*:16:2" and replaygain "album"
mpd_dithering.zip

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented May 3, 2019

Your file shows dithering as expected. It's just that the levels of "non-silence" audio are extremely low; how can you even hear anything? If you pull your amp's volume knob high enough to be able to hear the actual music, then your amp will have amplified the dithering as well, making it audible as noise (which dithering is, by design). Usually, dithering is not audible.

@edio

This comment has been minimized.

Copy link
Author

commented May 3, 2019

@MaxKellermann , do you think it would make sense to adjust dithering algorithm so the output is limited by the amplitude of the original sample? In other words, don't do dithering, if there's silence in original audio.

BTW, this change does not require an excessive C++ knowledge, so I would be able to prepare a PR if you're open to the idea.

My last argument here would be that other players do not have this issue. Either they do not use dithering or they do some sort of normalization.

@MaxKellermann

This comment has been minimized.

Copy link
Member

commented May 3, 2019

cmus and deadbeef both don't dither at all.
While I would agree with making dithering a configuration option, I don't think MPD should determine this automatically.
I rather think that there's something wrong with your setup - why is the volume level so extremely low? Of those 16 bits, you're only actually using 10 bits, the rest goes to the trash can. The dithering noise is just the most audible symptom of this problem.

@edio

This comment has been minimized.

Copy link
Author

commented May 3, 2019

@MaxKellermann , dithering noise is only audible on high volume levels - true.
I can only notice it on some tracks, that have sort of "fade in" in them - true.
I also use replaygain with no pregain, so usually dynamic range on my setup is a little bit narrower - true.

But I wouldn't say the setup is wrong. And also I've never noticed anything similar with any other player. So I'm blaming MPD here ;)

I personally didn't expect to see dithering in MPD. Hence, making dithering configurable is of course an option I'd like to see.

The other option I see is revising dithering algorithm.
I'm not familiar with standard approach in this field, but let's think this way: the purpose of dithering is to mask quantization error, if dithering introduces an audible artifact which you can hear better than the quantization error, then something is wrong.
Again, I'm not familiar with any existing open-source dithering algorithms for audio, but if we are to improve the one implemented in MPD already, I would consider limiting the amplitude of the dithering introduced. If on some interval of time our signal only occupies 3 bits, then my bet would be that by introducing 3 bit dithering we only make it worse. Of course we can perform measurements/calculations to prove that (and I'd be happy to do this over some weekend if needed).

Finally, setting output format to 24-bit resolves the issue for me, so I would be fine with leaving things as they are. But this issue is an interesting issue to tackle, so if you're open to changing this, I'd be eager to offer my help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.