simon-weber / gmusicapi

An unofficial client library for Google Music.
https://unofficial-google-music-api.readthedocs.io
BSD 3-Clause "New" or "Revised" License
2.48k stars 257 forks source link

FLAC uploaded through musicmanager cannot be played gapless #363

Open RadBadMark opened 9 years ago

RadBadMark commented 9 years ago

I'm not sure why yet but transcoding and uploading FLAC files through the gmusicapi result in gaps between tracks where there should be none, gapless music is no longer gapless. Uploading exactly the same FLAC tracks with the official Google Music Manager gives perfectly gapless audio.

My uneducated guess would be missing lame mp3 info tags which provide the delay and padding info for each track, although I have no idea how the API works right now so this may be nonsense!

Playback is through the Play Music Android app, the browser interface doesn't support gapless playback (for me at least).

thebigmunch commented 9 years ago

Your uneducated guess is correct. The format used for transcoding in gmusicapi results in no ID3 tags. The same transcoding function is used for creating scan-and-match samples as well as transcoding songs for upload. I don't see why this would be a requirement for either, but maybe @simon-weber will have more insight into that.

simon-weber commented 9 years ago

Hm. As a heads up, I don't know much about how gapless playback works.

@RadBadMark if you download your tracks via the web interface, do they have gapless tags in them? And are they exactly the same length as before? I wonder if Google is moving the tags over or just truncating the transcoded output.

thebigmunch commented 9 years ago

I would test changing the format to mp3 rather than s16le in the transcoding function. It doesn't seem to fail on matching or uploading and may or may not be a simple fix. There may or may not be a need to use the map_metadata option.

@simon-weber: Lossless files are inherently gapless. Gaps are artifacts introduced in the encoding process. They are silence at the start and end of an encoded file. Formats or, in the case of MP3, a specific encoder (LAME) allow gapless playback by adding metadata indicating the length of those gaps. It's then up to players to support it by reading that metadata and skipping the indicated silence.

RadBadMark commented 9 years ago

I've done some more digging, unfortunately just changing the output format doesn't seem to be enough - I'm assuming the calculation of the gapless information is done after the entire file has been encoded, with the info being written to the header at the start of the file as a final step in the transcode - this is of course a problem when the output is a pipe.

By modifying the transcode_to_mp3 function to transcode to a temp file before piping, I can see the gapless info is written to the header correctly, and once uploaded gapless playback through Google music works great. Downloading the files from the web interface I can see the gapless info present and correct.

In the end I had to use flac and pipe it to lame directly, avconv just wasn't writing the correct header even when going via a tempoaray file no matter what command options I tried.

thebigmunch commented 9 years ago

@RadBadMark Try it both with a pipe and temp file while adding -map_metadata 0 to the argument list in the transcoding function.

Edited for typo in option name.

RadBadMark commented 9 years ago

Using -map_metadata 0 still doesn't write the header even when using a temp file - I think this may be a bug in avconv https://bugzilla.libav.org/show_bug.cgi?id=853. It's strange because the default behaviour in libmp3lame is to write them, I can only assume avconv pipes the output from lame and attempting to write header info to the start of the file after the encode has finished fails in the same way as described above.

thebigmunch commented 9 years ago

Have you tried with ffmpeg instead of avconv?

RadBadMark commented 9 years ago

Have just tried and it seems to work better than avconv, at least after transcoding to a temporary file I can see the header is present. When outputting to a pipe there's still no header though but I think this is to be expected. Adding the -map_metadata flag had no effect.

So ffmpeg can be used for the transcode, but if gapless is required it has to be go via a temp file instead of being piped.

RadBadMark commented 9 years ago

..I replied too soon, when using ffmpeg (going via a temporary file) the mp3 info header is present but the contents are junk.

The only way I've been able to get correct gapless info at the transcoded output is still to pipe the FLAC decode into LAME, and have this output to a temp file before uploading.