Skip to content

feat: store tracklist as tag comment on recording - #13761

Merged
daschuer merged 1 commit into
mixxxdj:mainfrom
acolombier:feat/store-tracklist-as-comment
Mar 1, 2026
Merged

feat: store tracklist as tag comment on recording#13761
daschuer merged 1 commit into
mixxxdj:mainfrom
acolombier:feat/store-tracklist-as-comment

Conversation

@acolombier

@acolombier acolombier commented Oct 13, 2024

Copy link
Copy Markdown
Member

Closes #9134

Implemented for MP3 and Wave and tested with both.

ffprobe example with MP3

$ ffprobe ../2024-10-13_20h38m19s.mp3 
ffprobe [...]
   [...]
[mp3 @ 0x556661ba7b80] Skipping 339 bytes of junk at 813.
Input #0, mp3, from '/home/antoine/Music/Mixxx/Recordings/2024-10-13_20h38m19s.mp3':
  Metadata:
    encoder         : LAME 64bits version 3.100 (http://lame.sf.net)
    title           : Foo
    artist          : Bar
    album           : Baz
    comment         : 00:00:00: Twenty One Pilots - The Craving (single version)
                    : 00:00:09: Carnage - Psy Or Die
                    : 00:00:19: bbno$ - it boy
                    : 00:00:38: Armin van Buuren feat. Trevor Guthrie - This Is What It Feels Like
                    : 00:00:47: Armin van Buuren - Larger Than Life
                    : 00:01:06: Freestylers - Cracks - Flux Pavilion Remix
  Duration: 00:01:17.14, start: 0.023021, bitrate: 128 kb/s
  Stream #0:0: Audio: mp3, 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : LAME3.100

Note on MP3

After a long day of learning MP3 spec, it would appears that our implementation was somewhat flawed. My understanding is that the Xing frame that contains various parameter about the MP3 frames is expect in the beginning of the file, however we currently overwrite the first frames with it, leading to data loss. Since a frame is < 100ms, this is not something you can easily hear.

Second point is, we currently only write IDv1 (automatically supported by lame) but this limits the comment to 30 bytes. In order to lift this limit (and reach the hard limit of 2**32), we need to write ID3v2, but those are expected as header (unlike ID3v1 which can be appended in the footer when flushing the file.

In an ideal world, we would want to shift the file content to fit the ID3 header + the Xing frame. Because this basically requires to tear down the whole EncoderCallback mecanism, this instead adds a static header of 10K, which will be filled with the header, leading to a hard limit for comment (limit which depends of the artist, title and album size, as well the Xing frame size.

Appreciate this is far from optimal, but hopefully we can find an acceptable trade-off

@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch 3 times, most recently from 5108a46 to acc29fb Compare October 13, 2024 19:45
@acolombier
acolombier marked this pull request as ready for review October 13, 2024 22:04
@Swiftb0y
Swiftb0y requested a review from daschuer October 14, 2024 12:51
Comment thread src/encoder/encoder.cpp
@Swiftb0y

Copy link
Copy Markdown
Member

considering the complications and tradeoffs there are with writing large metadata, why not write this tracklist as a separate file like the cuesheet? Is there that much value to having it part of the file metadata?

@acolombier

acolombier commented Oct 14, 2024

Copy link
Copy Markdown
Member Author

considering the complications and tradeoffs there are with writing large metadata, why not write this tracklist as a separate file like the cuesheet? Is there that much value to having it part of the file metadata?

Because that's not the feature 😃

We already support the ability to generate a cue file, but there was a requested feature to have the ability to store the track. I think that's a fair request as the cue file isn't embedded.
I sometime copy recording of set I have made on my phone, and having a way to check the tracklist as comment metadata would be a great value

@Swiftb0y

Copy link
Copy Markdown
Member

fully agree, I just find it weird that its a different format from the cuesheet, so I figured these were two different features.

@Holzhaus

Holzhaus commented Oct 14, 2024

Copy link
Copy Markdown
Member

Didn't check the code, but I was wondering: Is this only for MP3/ID3?

For FLAC I think there is the CUESHEET tag block which is specifically for this purpose and might have proper support by audio players.

@Holzhaus

Copy link
Copy Markdown
Member

@acolombier

acolombier commented Oct 14, 2024

Copy link
Copy Markdown
Member Author

I was wondering: Is this only for MP3/ID3?

Yes - only for MP3/ID3 and Wave so far. Since the FLAC encoder inherits the Wave one, it would also support the COMMENT field to be filled up.

https://www.xiph.org/flac/format.html#metadata_block_cuesheet

Nice, I'm wondering how widely is this supported? It feels like some custom logic that could be added in the recordermanager to duplicate the sheets in the FLAC file before flushing. It sounds a bit hacky, but I don't think other format would support cuesheet within their tag's spec?

@JoergAtGithub JoergAtGithub added this to the 2.6-beta milestone Jan 4, 2025
@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch from bfe592c to d072fbc Compare February 14, 2025 01:05
@acolombier

acolombier commented Feb 23, 2025

Copy link
Copy Markdown
Member Author

(Edit: didn't work :( )
/softfix

@github-actions
github-actions Bot force-pushed the feat/store-tracklist-as-comment branch from d072fbc to 0a8ab06 Compare February 23, 2025 02:40
@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch 2 times, most recently from 0bfc6b4 to eba3cfd Compare February 23, 2025 02:57
@github-project-automation github-project-automation Bot moved this to In progress in Releases Mar 25, 2025
@acolombier acolombier moved this from In progress to Need testing in Releases Mar 25, 2025

@daschuer daschuer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I can confirm it works for mp3, but unfortunately not for wav.

Comment thread res/controllers/DummyDeviceDefaultScreen.qml
Comment thread src/encoder/encoder.cpp Outdated
Comment thread src/encoder/encoder.cpp Outdated
Comment thread src/encoder/encoder.h Outdated
Comment thread src/encoder/encoderfdkaac.h
Comment thread src/encoder/encodermp3.cpp Outdated
Comment thread src/encoder/encodermp3.cpp Outdated
Comment thread src/encoder/encodermp3.cpp Outdated
Comment thread src/encoder/encodermp3.cpp Outdated
Comment thread src/encoder/encodermp3.cpp Outdated
@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch from 4a1999d to ff291d2 Compare April 26, 2025 18:36
@acolombier

Copy link
Copy Markdown
Member Author

Could you share some more details @daschuer? Just tested locally with WAV and everything seems to work fine on my end.

@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch from 95315d7 to 2bd40a3 Compare February 3, 2026 22:42
@daschuer

daschuer commented Feb 4, 2026

Copy link
Copy Markdown
Member

pre-commit is complaining.

@daschuer daschuer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for coming back to this. It works like a charm for mp3 and wav. Left w view final comments.

Comment thread src/encoder/encoder.cpp Outdated
Comment thread src/encoder/encoderffmpegcore.cpp Outdated
// Currently this method is used before init() once to save artist, title and album
//
void EncoderFfmpegCore::updateMetaData(const QString& artist, const QString& title, const QString& album) {
void EncoderFfmpegCore::updateMetaData(const QString& artist,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This function does now only print a debug message. Is this desired? Is the comment outdated?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

For some reasons, the previously set values (m_strMetaData*) was never read so this appears to have no action. I have set it to a no-op now.

Comment thread src/encoder/encodermp3.cpp Outdated
Comment thread src/encoder/encodermp3.cpp Outdated
Comment thread src/encoder/encodermp3.cpp Outdated

<item row="6" column="0" colspan="3">
<widget class="QWidget" name="compressionGroup">
<layout class="QHBoxLayout" name="compressionHLayout">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The in indentation is broken. The UI editor has sometime its own ideas. It is probably best to revert all unrelated edits manually. Please keep also the extra new lines @ronso0 has introduced.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It is better to let the reviewer resolve the issue. I need to check anyway. In this case it is not resolved.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In this case it is not resolved

This was an accident.

It is better to let the reviewer resolve the issue

I'd be happy to find the few cases where you have said to new contributors that you didn't mind whether it was the reviewer or the author resolving the comment.
Some consistency on your ways of working would be appreciated to reduce as much as possible friction.

@acolombier
acolombier requested a review from daschuer February 8, 2026 22:40
@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch 2 times, most recently from 3b5e234 to 782f1ee Compare February 15, 2026 00:14
@acolombier

Copy link
Copy Markdown
Member Author

I took the initiative to already auto-squash the commits as all the feedback has been addressed now, so hopefully it can get a quick merge

@daschuer

Copy link
Copy Markdown
Member

Such early rebase, requires me to read the whole PR again. So it is not a receipt for a quick merge actually.

Comment thread src/preferences/dialog/dlgprefrecorddlg.ui Outdated

<item row="6" column="0" colspan="3">
<widget class="QWidget" name="compressionGroup">
<layout class="QHBoxLayout" name="compressionHLayout">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It is better to let the reviewer resolve the issue. I need to check anyway. In this case it is not resolved.

@daschuer

Copy link
Copy Markdown
Member

I can confirm it sitil works.

@acolombier

acolombier commented Feb 15, 2026

Copy link
Copy Markdown
Member Author

As you can see on Github, there is a Compare button that allows you to see that the rebase is strictly equivalent to what was there before, thus what you have already reviewed.

image

@acolombier

Copy link
Copy Markdown
Member Author

I can confirm it sitil works.

Aligned to my comment above, I made sure to squash my commit ensure a null diff so there was no risk of a regressing (and need for retesting)

@acolombier
acolombier requested a review from daschuer February 15, 2026 18:35

@daschuer daschuer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, unfortunately conflicts have developed.

I have also found some left over issues.

Comment thread src/encoder/encoderwave.cpp Outdated
void EncoderWave::flush() {
sf_write_sync(m_pSndfile);

auto trackList = getTrackList().join("\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I noticed you have only fixed the unknown auto issues for mp3

Suggested change
auto trackList = getTrackList().join("\n");
QString trackList = getTrackList().join("\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

do we also have length constrains here?

Comment thread src/encoder/encoderwave.cpp Outdated
tag.setAlbum(QStringToTString(m_metaDataAlbum));
tag.setComment(QStringToTString(trackList));

auto tagBuffer = tag.render();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
auto tagBuffer = tag.render();
TagLib::ByteVector tagBuffer = tag.render();

Comment thread src/encoder/encoderwave.cpp Outdated
tagBuffer.size());

// Update the file header with the new file size
auto fileSize = m_pCallback->tell();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
auto fileSize = m_pCallback->tell();
int fileSize = m_pCallback->tell();

Comment thread src/encoder/encoderwave.cpp
Comment thread src/encoder/encodervorbis.cpp Outdated

EncoderVorbis::~EncoderVorbis() {
if (m_bStreamInitialized) {
auto trackList = m_trackList.join("\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Another instance ...

Suggested change
auto trackList = m_trackList.join("\n");
QString trackList = m_trackList.join("\n");

@acolombier
acolombier requested a review from daschuer February 17, 2026 00:00

@daschuer daschuer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. Thank you. You can rebase this branch and we can merge.

@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch from f7c80f2 to 334663f Compare February 17, 2026 09:40
@acolombier
acolombier force-pushed the feat/store-tracklist-as-comment branch from 334663f to 548094e Compare February 17, 2026 09:43
@acolombier

Copy link
Copy Markdown
Member Author

Hi @daschuer, this should now be ready to merge

@daschuer
daschuer merged commit 8837b44 into mixxxdj:main Mar 1, 2026
15 checks passed
@github-project-automation github-project-automation Bot moved this from Need testing to Done in Releases Mar 1, 2026
@ronso0

ronso0 commented Mar 14, 2026

Copy link
Copy Markdown
Member

For some reason this makes my Flac reocrdings unusable, see errors below.

  • Flac, 16 bit, compression 5
  • "Create CUE file" unchecked

Admittedly, this is on outdated Ubuntu 20.04.5 with Qt 6.2.3.
But still, how does the disabled cue option affect the encoder?
Reverting 548094e fixes it.

ffprobe rec-broken.flac

$ ffprobe rec-broken.flac
ffprobe version 4.2.7-0ubuntu0.1 Copyright (c) 2007-2022 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
  configuration: --prefix=/usr --extra-version=0ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
broken.flac: Invalid data found when processing input

When I try to load such a Flac recording in Mixxx, I get these errors:

debug   [Main] SoundSourceProxy - SoundSourceProvider "Xiph.org libFLAC" created a SoundSource for file "/home/me/rec.flac" of type "flac"
warning [Main] TagLib - Cannot read audio properties from inaccessible/unreadable/invalid file: /home/me/rec.flac
info    [Main] MetadataSourceTagLib - No track metadata or cover art found in file "/home/me/rec.flac" of type "FLAC"
debug   [Main] BaseTrackCache(0x55dd18024d60) updateIndexWithQuery took 0 ms
debug   [CachingReaderWorker 1] SoundSourceProxy - SoundSourceProvider "Xiph.org libFLAC" created a SoundSource for file "/home/me/rec.flac" of type "flac"
warning [CachingReaderWorker 1] SoundSourceFLAC - Failed to process FLAC metadata: 4
warning [CachingReaderWorker 1] SoundSourceProxy - Failed to open file "/home/me/rec.flac" with provider "Xiph.org libFLAC" using mode Strict
debug   [CachingReaderWorker 1] SoundSourceProxy - SoundSourceProvider "libsndfile" created a SoundSource for file "/home/me/rec.flac" of type "flac"
warning [CachingReaderWorker 1] SoundSourceSndFile - Error opening libsndfile file: "file:///home/me/rec.flac" "File contains data in an unimplemented format."
warning [CachingReaderWorker 1] SoundSourceProxy - Failed to open file "/home/me/rec.flac" with provider "libsndfile" using mode Strict
debug   [CachingReaderWorker 1] SoundSourceProxy - SoundSourceProvider "Xiph.org libFLAC" created a SoundSource for file "/home/me/rec.flac" of type "flac"
warning [CachingReaderWorker 1] SoundSourceFLAC - Failed to process FLAC metadata: 4
warning [CachingReaderWorker 1] SoundSourceProxy - Failed to open file "/home/me/rec.flac" with provider "Xiph.org libFLAC" using mode Permissive
warning [CachingReaderWorker 1] CachingReaderWorker - "[Channel1]" Failed to open file QFileInfo(/home/me/rec.flac)
debug   [Main] Failed to load track QFileInfo(/home/me/rec.flac) "The file '/home/me/rec.flac' could not be loaded."

These are the decoders in use:

debug [Main] SoundSourceProviderRegistry - Registering file type "flac" for provider "libsndfile" with priority 2 (lower)
debug [Main] SoundSourceProviderRegistry - Registering provider "Xiph.org libFLAC"
debug [Main] SoundSourceProviderRegistry - Registering file type "flac" for provider "Xiph.org libFLAC" with priority 4 (higher)

info [Main] SoundSourceProxy - SoundSource providers for file type "flac"
info [Main] SoundSourceProxy - 4 (higher) : "Xiph.org libFLAC"

Opening In Audacity also fails.

@acolombier

Copy link
Copy Markdown
Member Author

Did you try to uncheck Store the tracklist as comment? Create CUE file is unrelated to this feature

@ronso0

ronso0 commented Mar 15, 2026

Copy link
Copy Markdown
Member

Oh, I didn't even spot that..
so Store the tracklist as comment is/was not checked. tracklist_as_comment is also 0 in mixxx.cfg

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

write list of tracks played to comments tag of recordings

6 participants