Any appetite for a 'normalisation' layer over non-std tags?

Adam Szmigin adam.szmigin at xsco.net
Sun Apr 9 23:12:52 UTC 2017


Dear Michael,

Many thanks for your reply.  Code like the example you pasted would be 
most useful, but what version of TagLib actually has it?

The API docs don't mention any methods like composers():
http://taglib.org/api/classTagLib_1_1PropertyMap.html

Neither does the PropertyMap header:
https://github.com/taglib/taglib/blob/master/taglib/toolkit/tpropertymap.h

In fact, I just cloned master and can't find methods like that anywhere:
~/src/taglib-master$ grep -r composers *
~/src/taglib-master$



Additonally (not sure if relevant to the discussion), 
FileRef::Tag::properties() doesn't actually contain all properties. 
Instead, I have to use xx::File::properties():

     string path{"example.mp3"};

     TagLib::FileRef fr{path.c_str()};
     cout << "Props using FileRef:" << endl;
     for (auto &prop_kvp : fr.tag()->properties()) {
         for (auto &val : prop_kvp.second) {
             cout << "Prop: " << prop_kvp.first << " -> " << val << endl;
         }
     }
     cout << endl;

     TagLib::MPEG::File f{path.c_str()};
     cout << "Props using MPEG::File:" << endl;
     for (auto &prop_kvp : f.properties()) {
         for (auto &val : prop_kvp.second) {
             cout << "Prop: " << prop_kvp.first << " -> " << val << endl;
         }
     }

Prints:

Props using FileRef:
Prop: ALBUM -> Album field
Prop: ARTIST -> Artist field
Prop: COMMENT -> Comment field
Prop: DATE -> 2017
Prop: GENRE -> Pop
Prop: TITLE -> Title field
Prop: TRACKNUMBER -> 3

Props using MPEG::File:
Prop: ALBUM -> Album field
Prop: ALBUMARTIST -> Album artist field
Prop: ARTIST -> Artist field
Prop: COMMENT -> Comment field
Prop: COMPOSER -> Composer field
Prop: COPYRIGHT -> Copyright field
Prop: DATE -> 2017
Prop: DISCNUMBER -> 1/2
Prop: ENCODEDBY -> Encoded by field
Prop: GENRE -> Pop
Prop: ORIGINALARTIST -> Original artist field
Prop: TITLE -> Title field
Prop: TRACKNUMBER -> 03/04
Prop: URL -> URL field

Using xx::File::Tag::properties() similarly contains only a truncated 
list, not all properties that xx::File::properties() has.  Also note 
that some properties are expressed differently (e.g. TRACKNUMBER).  This 
behaviour is using version 1.9.1-2.4ubuntu1 (it doesn't look from 
initial glance like Debian/Ubuntu have contributed any patches that 
would cause this behaviour).


Many thanks,

--
Adam Szmigin


On 09/04/17 22:37, Michael Helmling wrote:
> Dear Adam,
>
> this functionality is already included in taglib - see
> Tag::properties(), e.g.:
> FileRef file("/path/to/file.mp3");
> auto props = file.tag().properties();
> for (auto &composer : props.composers())
>     std::cout << "composer: " << composer << std::endl;
>
>
> Best regards,
> Michael
>
> On 09.04.2017 11:54, Adam Szmigin wrote:
>> Dear TagLib devs,
>>
>> Firstly, many thanks to all the contributors on TagLib - it is an
>> excellent library and it has benefited me greatly in a number of
>> projects I've undertaken.
>>
>> For a TagLib user wishing to read "exotic" tags, i.e. those that are
>> not available via FileRef::tag(), it looks like the user has to
>> construct a specific File sub-class and work with the different tag()
>> (or ID3v2Tag() / xiphComment() etc!) methods to get what they want.
>> How to proceed varies based on the file format, and also to some
>> extent what tagging application was used that wrote the original tags.
>>
>> The issue I find is that the tags I often work with for music are not
>> so "exotic", but essential: they include things like album-artist,
>> disc number, composer.  There is no universal standard for these
>> fields across all file types that I know of.
>>
>>
>> So, I have found myself writing a normalisation layer over the top of
>> TagLib, which both instantiates the appropriate File sub-class given a
>> path, and also tries a few different approaches to get values for this
>> extended range of common but non-standardised tag fields.  Here is the
>> broad interface to give an idea:
>>
>> class metadata
>> {
>> public:
>>   metadata(const boost::filesystem::path &path);
>>   ~metadata();
>>
>>   bool has_tag() const;
>>
>>   std::string album() const;
>>   std::string album_artist() const;
>>   std::string artist() const;
>>   std::string comment() const;
>>   std::string composer() const;
>>   std::string copyright() const;
>>   std::string date() const;
>>   std::string disc_number() const;
>>   std::string disc_total() const;
>>   std::string encoded_by() const;
>>   std::string genre() const;
>>   std::string original_artist() const;
>>   std::string title() const;
>>   std::string track_number() const;
>>   std::string track_total() const;
>>   std::string url() const;
>>   ..
>> };
>>
>> Examples of format-specific manipulation include things like this:
>>
>> std::string disc_number() const
>> {
>>   auto val = prop("DISCNUMBER"); // Uses TagLib::xx::File::properties()
>>
>>   // Remove anything after forward slash, if format is "DISC/TOTAL".
>>   auto pos = val.find_first_of('/');
>>   if (pos != std::string::npos)
>>       val.erase(pos);
>>   // Remove leading zeroes
>>   val.erase(0, std::min(val.find_first_not_of('0'), val.size()-1));
>>   return val;
>> }
>>
>>
>> *My question is:* from a read-only perspective (and maybe read/write),
>> is there any appetite for a normalisation layer like this over the top
>> of TagLib?  It could either be a part of TagLib, or a separate project.
>>
>> (Ignore the use of boost and std::string vs String in the example..
>> It's just illustrative.  The example was taken from a recent project
>> I'm working on where the "normalisation" layer is not designed to be
>> separated out..)
>>
>>
>> I'd also appreciate any feedback from the TagLib gurus on whether I'm
>> "doing it right" regarding the above process of normalisation.
>>
>>
>> Many thanks,
>>
>
>


More information about the taglib-devel mailing list