polyfloyd / rust-id3

A rust library for reading and writing ID3 metadata
MIT License
245 stars 47 forks source link

Support for WAV files #63

Closed gahag closed 3 years ago

gahag commented 3 years ago

Does this crate support ID3 tags in WAV files?

polyfloyd commented 3 years ago

Yes, although only if the ID3 tag is preceding the WAV itself. I have seen ID3 tags being contained in the WAV as a separate chunk, but that is not supported (yet)

gahag commented 3 years ago

I'm implementing WAV metadata support for Polaris, which uses rust-id3. I considered contributing support for ID3 tags inside chunks for this crate, but managing WAV chunks when writing tags would require some work beyond what I can do. I guess I'll try to extract the the ID3 chunk payload in Polaris, and pass it to this crate. Thanks for the quick response.

gahag commented 3 years ago

Actually, it might be simpler than I thought. I have 342 WAV files in my music library, and all of them have the same chunk pattern:

RIFF(WAVE)->
            fmt ;
            data;
            <some other chunks>
            ID3 ;

Some notable examples:

RIFF(WAVE)-> (76796826 Bytes)
            fmt ; (16 Bytes)
            data; (74880000 Bytes)
            LIST(INFO)-> (78 Bytes)
                        IPRD; (7 Bytes)
                        IART; (8 Bytes)
                        INAM; (14 Bytes)
                        ITRK; (2 Bytes)
                        ICRD; (5 Bytes)
            id3 ; (1916695 Bytes)
RIFF(WAVE)-> (76769030 Bytes)
            fmt ; (16 Bytes)
            bext; (602 Bytes)
            minf; (16 Bytes)
            elm1; (214 Bytes)
            data; (70272000 Bytes)
            regn; (92 Bytes)
            umid; (24 Bytes)
            DGDA; (412973 Bytes)
            iXML; (1525 Bytes)
            _PMX; (5916 Bytes)
            ID3 ; (6075561 Bytes)
RIFF(WAVE)-> (67376330 Bytes)
            fmt ; (16 Bytes)
            data; (67212508 Bytes)
            id3 ; (163686 Bytes)
            LIST(INFO)-> (84 Bytes)
                        IART; (16 Bytes)
                        INAM; (37 Bytes)
                        IGNR; (6 Bytes)

If we consider that the ID3 chunk will always be a direct child of the RIFF root chunk, we just need to update the root chunk's size, and shift trailing data accordingly. I noticed there is already code for shifting trailing data left or right for mp3 files, so it should only be a matter of refactoring the code and implementing the chunk size update. Please let me know if you find this reasonable, as I would be willing send in a pull request.

polyfloyd commented 3 years ago

Yes, that storage solution was initially made to be adaptable to WAV files, so please go ahead :)

There are also a few things to take into consideration:

gahag commented 3 years ago

Regarding the conflict between chunk and header tags, I don't really know what we should do. I checked my library, and none of my wav files have header tags, just chunk tags. The wav spec states that the file must start with a RIFF header, so I'm not sure if header tags are actually supported. What do you think?

gahag commented 3 years ago

I'll try to manually craft a wav file with header tags and see if it works.

gahag commented 3 years ago

So, I managed to produce a wav file with a mp3 header. While my tag editor doesn't recognize the tags, my music player (smplayer) recognizes both the tags and the audio. Vlc on the other hand, recognizes only the audio, but not the tag.

gahag commented 3 years ago

@polyfloyd I've been thinking about it, and I've come up with this:

  1. If the file starts with a RIFF WAV header (and therefore has no header tag), use the ID3 chunk. Create this chunk at the end of the file if it doesn't exists.
  2. Otherwise, use a header ID3 tag. Create one if it doesn't exists.

I believe it will handle most cases correctly this way. Please let me know what you think about it.

polyfloyd commented 3 years ago

Let's worry about just WAV files for now, we will most likely have a separate API like we already do for AIFF.

If I interpret your answer correctly we should prefer ID3 tags as a WAV chunk? So what should we do in a situation where we encounter a WAV file with both ID3 chunk and ID3 as header?

gahag commented 3 years ago

Oh, that's great. I believe a separate API will make things easier.

Regarding using chunk or header tags, I've found that header tags in WAV files are invalid. While some players recognize them, most don't (including VLC). The specification states that extra contents in WAV files should be placed inside non-standard chunks, which is the case of the commonly used ID3 chunk. Therefore, I believe we should only support chunk tags in this separate API.

I've started working on the implementation, and will submit a pull request soon.

gahag commented 3 years ago

@polyfloyd I have created a pull request addressing this issue. Please let me know of any suggestions.