Author Topic: Tags Library  (Read 63427 times)

none

  • Guest
Re: NEW: Tags Library
« Reply #25 on: 12 Jul '14 - 07:12 »
def file should then be

Quote
LIBRARY TagsLib

DESCRIPTION 'Tags reader-writer component for Delphi'

EXPORTS
    TagsLibrary_AddCoverArt
    TagsLibrary_AddTag
    TagsLibrary_AddTagEx
    TagsLibrary_ClearCARTPostTimer
    TagsLibrary_CoverArtCount
    TagsLibrary_Create
    TagsLibrary_DeleteCoverArt
    TagsLibrary_DeleteTag
    TagsLibrary_DeleteTagByIndex
    TagsLibrary_Free
    TagsLibrary_GetAudioAttributes
    TagsLibrary_GetCARTPostTimer
    TagsLibrary_GetConfig
    TagsLibrary_GetCoverArt
    TagsLibrary_GetTag
    TagsLibrary_GetTagByIndexEx
    TagsLibrary_GetTagData
    TagsLibrary_GetTagEx
    TagsLibrary_GetVendor
    TagsLibrary_Load
    TagsLibrary_LoadFromBASS
    TagsLibrary_Loaded
    TagsLibrary_RemoveTag
    TagsLibrary_Save
    TagsLibrary_SaveEx
    TagsLibrary_SetCARTPostTimer
    TagsLibrary_SetConfig
    TagsLibrary_SetCoverArt
    TagsLibrary_SetTag
    TagsLibrary_SetTagData
    TagsLibrary_SetTagEx
    TagsLibrary_SetTagLoadPriority
    TagsLibrary_SetVendor
    TagsLibrary_TagCount

do not Forget add the Bytes after any func

Sample:
TagsLibrary_Free@4 .... see my previous post

greets

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #26 on: 12 Jul '14 - 16:27 »
Thank you very much none, but couldn't progress. But as I understand you are writing about static linking the .dll but I would like dynamic linking.

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #27 on: 17 Jul '14 - 05:14 »
Ok, with help from Ian, we managed to create a C++ header file, which compiles fine, and also managed to make the contest.exe mini tutorial, which does nothing more than takes an argument (a file name) and prints to the console the tags.

So update 1.0.20.31:

  • Cover art 'PictureFormat' is now determined from the first 2 bytes of the picture data, so it will be more precise than checking the returned mimetype (which can occasionally report false values)
  • Fixed C++ header files
  • Added a simple console test tutorial app. with source code (C++)

Download in the first post.

The new C++ header file is as much tested as the new C++ contest.exe tutorial is using it, so very little, just the basic functions, but it should work as the Delphi .dll tutorial seems working fine and it also makes use of the same .dll functions.

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #28 on: 6 Sep '14 - 01:29 »
A little update: added support of multiple tags of the same field type (like multiple 'ARTIST' fields). In case of WAV LIST INFO tags they will be saved as a coma separated list.

Download link in the first post.

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #29 on: 9 Oct '14 - 20:41 »
Update:

  • Fixed memory leak in Ogg load tag function
  • Fixed memory leak in WMA load tag function
  • Fixed clearing TRACKNUMBER for ID3v1 tag

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #30 on: 17 Nov '14 - 01:03 »
A little update is available in the first post:

  • Fixed reading ID3v2 UTF-8 TXXX frames

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #31 on: 27 Nov '14 - 02:02 »
Hello,

I 'am currently trying your tagging lib with Delphi XE5... Works fine... But on some mp3 files I don't get a value for "Tags.ID3v2Tag.PlayTime". I checked the source and discovered that the function "CheckMPEG" looks for a "FF" at the stream. Many of my files have a 0 at this place. All other tag editors I tried works fine with this mp3 files.  A second topic is reading tags from an aiff file... IsLoaded returns false - Do you supoort aiff files? Can you please take a look to it? Thanks for your work!

An example of an problematic mp3: http://www.musican.net/data/bin/prob_mp3.zip

Sascha

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #32 on: 27 Nov '14 - 17:32 »
Hi again,

still working with your lib.. mainly with the ID3v2 part today... I use a PRIV Frame in my software for storing player related data. Your ID3V2 class can read the PRIV frame but handles it as a text frame and tries to read the encoding byte, which of course make problems. Some code i use:

a:=fTags.ID3v2Tag.FindCustomFrame('PRIV','www.musican.net'); 

This will always return -1 because it calls GetUnicodeUserDefinedTextInformation which tries to read the the text encoding byte.

for i := 0 to fTags.ID3v2Tag.FrameCount - 1 do
    begin
      if ID3v2Library.ConvertFrameID2String(fTags.ID3v2Tag.Frames.ID) = 'PRIV' then
      Begin
        tmp:=fTags.ID3v2Tag.GetUFID(i,msg);
      End;
    end;


This works as a workaround but I'm not sure if GetUFID is made for reading in private frames.  Is there an easier way to get the data from an private frame?
Can I get the size of the mp3 file? ID3v2Tag.MPEGInfo.Bytes is alway 0...

Sascha

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #33 on: 27 Nov '14 - 22:17 »
Yes AIFF/AIFC files should be supported. If you have a problem with a particular file please post a download link for the file!

That MP3 you linked has an invalid ID3v2 tag size (the tag is much smaller then it's size in the file), as far as I see the padding is much larger, so the lib will seek to the end of the tag and try to identify a MPEG frame. Please try this update, which scans 4096 bytes after the ID3v2 tag for a valid MPEG frame: ID3v2Library.zip

Regarding the PRIV frame: frames that have no parsing functions, like the PRIV frame, needs to be processed manually.

Code: [Select]
    Index := ID3v2Tag.FrameExists('PRIV');
    ID3v2Tag.Frames[Index].Stream.Seek(0, soBeginning);
    ID3v2Tag.Frames[Index].Stream.Read(...);

...and do the processing you want. FrameExists() will return the first PRIV frame it finds, or - 1 if not, to check all the PRIV frames use:

Code: [Select]
    for i := 0 to ID3v2Tag.FrameCount - 1 do begin
        if IsSameFrameID(ID3v2Tag.Frames[i].ID, 'PRIV') then begin
            //... do what you want here
        end;
    end;

MPEGInfo.Bytes only has value if the MPEG file contains a 'Xing' or an 'Info' frame, the value is copied from there.

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #34 on: 28 Nov '14 - 19:22 »
Hi,

Thanks for the new version... ID3V2.PlayTime works now fine and I got reading AIFF too. Currently I have checked all Tag classes in reading mode. Writing tags will follow these days.

The remaining problems while reading tags are:

- Getting the file size. It would be enough for me to get the file size on the disk. Sure, I could get it manualy, but a simple property in each class returning the file size would make it more handy.
- Song length in MP4Tag, Ape and Wave. This returns still 0 or a wrong value at WaveTag.
- Sample rate in MP4Tag, Ape and WMA. Is always 0
- Bitrate in MP4Tag and APE is 0 too.

Thanks again for this great set of librarys!

regards
Sascha




3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #35 on: 28 Nov '14 - 21:33 »
File size: it's much more simple to use a separate function for this, or you have to type multiple times the same thing (for every tag format). Use this function for example:

Code: [Select]
function NGetFileSize(FileName: String): Int64;
var
  f: TSearchRec;
begin
    Result := -1;
    if FileExists(FileName) then begin
    try
            if FindFirst(FileName, faAnyFile, f) = 0 then begin
                Result := f.Size;
            end;
        finally
            SysUtils.FindClose(f);
        end;
    end;
end;

Getting song length, play time, bit rate or any other audio attributes is again much simpler with BASS. Use BASS_ChannelGetLength() with BASS_ChannelBytes2Seconds() and BASS_ChannelGetInfo() for this. You'll have to type that only once and will work with all supported audio file formats. :)

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #36 on: 29 Nov '14 - 03:29 »
Hi,

I get a mem leak using wma tag. Did nothing else as
Code: [Select]
fWmaTag.LoadFromFile(Fname);
---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:

21 - 28 bytes: TMemoryStream x 35, TWMATagFrame x 35, UnicodeString x 4
29 - 36 bytes: UnicodeString x 14
37 - 44 bytes: UnicodeString x 9
45 - 52 bytes: UnicodeString x 4
53 - 60 bytes: UnicodeString x 3
61 - 68 bytes: UnicodeString x 1

The sizes of unexpected leaked medium and large blocks are: 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236, 8236

Sascha

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #37 on: 29 Nov '14 - 05:47 »
Sorry, there was no Destructor for TWMATag. :)

Please try this update: WMATagLibrary.zip

Please check if this solves the memory leaks, no idea those 'UnicodeString' what could be. If they are the TWMATagFrame.Name values, it should be fixed too.

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #38 on: 29 Nov '14 - 15:21 »
Yes, this fixes it...Thank you!   :)

I did a simple benchmark reading tags on different audio types because this is quite time critical scanning a library of 10000+ songs... I discoverd that the VorbisOpusTag lib is most of the time factor 6-10 slower than all other tag libs. Is that tag type more complex as the others?

happy weekend!

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #39 on: 29 Nov '14 - 19:10 »
Ok cool then.

Yes, the slowness is because the data is in Ogg container. And it's true my code is not optimized for speed, there is an Ogg class which reads the data from file to a stream, then the tag data is extracted from this stream to another stream, and there's also an overhead to process the Ogg stream.

BTW. the slowest thing is when extracting cover art which is Base64 encoded. If you avoid that then you gain the most speed.

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #40 on: 29 Nov '14 - 21:50 »
It's a real mess with all this different types of tags... First I relesead my app as an mp3 player only but all ask for multi audio format... If they get it they will probably ask for more speed at scanning the music library :)
While scanning I only read the basic tags. Covers on demand only... Ogg is even slow on reading if the file has not a tag in it... Strange to see that most codes need about 2ms (with cache effect) and ogg takes about 40ms... Its just a number but it shows the factor... Personally I don't need other codes than mp3 to get transparent sound...
I'm suprised about the incredible speed of bass... I followed your advice to use BASS to get audio attributes from file - I ever thought this will be terrible slow, but it isn't. If I knew this before I could save a lot of time... ;)
Yes... no question open at this point :) Thank you!

Sascha

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #41 on: 30 Nov '14 - 00:59 »
I hate all those tagging formats too. :) I would think that ID3v2 should be used for all the audio file formats. I was using an old, only Delphi 7, .dcu ID3v2 tag unit, then when moving to newer Delphi made a .dll with that unit. Then Delphi 2009 came out and I needed unicode, so I made another .dll which was using a TFileStream created from unicode file name, given to the previous .dll. It was a complete mess, so I decided to make my own ID3v2 unit, and that was ID3v2 Library. After that, made all the other tagging libraries one-by-one. And finally Tags Library. :)

I'll see if I can improve the Ogg loading, it's a rather difficult thing, at least for me, I was happy it worked at all, so I didn't want to temper with it. Maybe there are some other simpler speedup options I didn't notice.

BTW. Tags Library has been updated with the recent fixes. Thank you for the suggestions!

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #42 on: 2 Dec '14 - 15:47 »
Hi,

okay, now I'm at writing the tags with your lib... Following pseudo code does not work. The freeware app MP3Tag don't detect this written tags.

Code: [Select]

s:='MUSC';                     // by the way - MP4Tag writes only 4 bytes as Atomname
dataToWrite:='"data'";      // Data has double quotes!

if fMP4.LoadFromFile(Fname) <> MP4TAGLIBRARY_SUCCESS then Exit;
Atom:=fMP4.FindAtom(s);
If Atom = nil then
Begin
  Atom:=fMP4.AddAtom(s);
  Res:=Atom.AddData.SetAsText(dataToWrite);
End
else
Begin
  fMP4.SetText(s,dataToWrite);
End;
if fMP4.SaveToFile(Fname) <> MP4TAGLIBRARY_SUCCESS then Exit;

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #43 on: 2 Dec '14 - 17:03 »
Hi,

again me... Writing with OggVorbis produces a mem leak...

---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:

301 - 316 bytes: TOGGStream x 10


PS: The MP4 AddAtom topic: MP4Tag can read its own written tags. But no other tag editor I have.

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #44 on: 2 Dec '14 - 19:35 »
Adding a POPM Tag to ID2 doesn't work as expected...

Code: [Select]
   
    Index:=fID2.AddFrame('POPM');
    if Index=-1 then Exit;
    fID2.SetPopularimeter(Index,coRatingID,Rating,Counter);
    fID2.SaveToFile(Fname);

The tag will be added, but again Mp3Tag doesn't detect it. Looking in the file directly shows that the new tag will be added behind a PRIV tag.

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #45 on: 2 Dec '14 - 22:06 »
Hi,

regarding POPM forget it, I got it work! :)

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #46 on: 3 Dec '14 - 23:37 »
Sorry, indeed there was a memory leak in Ogg writing. Please try this update: OggVorbisAndOpusTagLibrary.zip

Regarding mp4 tags. Can you reproduce the problem with the mp4 tag tutorial? I checked just now, and writing tags to an mp4 file, does show up in iTunes and in mp3tag also. Or do you have problems with only the code you posted?
I don't know about this MUSC atom. Unknown atom probably won't show up in other software. List of iTunes atoms: iTunes Metadata atom list and their data formats

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #47 on: 4 Dec '14 - 13:58 »
Hi,

The mp4tag tutorial can not create new atoms. So testing the same topic with the demo app is not fully possible.
I use two different tag editors for testing - Mp3Tag and Godfather. If I create a custom field in this tools both tools can detect the new field from each other.

MP4Taglib can read its own created atoms but no other tool.

Quite complex thing..

I get really strange results sometimes... I did following:

- Created a tag free clean m4a file
- tagged it with mp3tag
- added a custom field "MPTG" with "Mp3Tag" as data.

Your demo exe read:

trkn 32 bytes = 4294967296
disk 30 bytes = 1441792
gnre 26 bytes = Pop
©alb 26 bytes = pm
aART 33 bytes = albArtist
©ART 26 bytes = rw
©cmt 28 bytes = komm
©wrt 32 bytes = Composer
---- 74 bytes = mp3tag
©nam 29 bytes = bless
©day 28 bytes = 1971

Checked in Godfather tagger. It detects the custom field MPTAG fine.

Use my code to add custom field "m_ra" and "m_lp" and "m_cn"

Demo App says:
trkn 32 bytes = 4294967296
disk 30 bytes = 1441792
gnre 26 bytes = Pop
©alb 26 bytes = pm
aART 33 bytes = albArtist
©ART 26 bytes = rw
©cmt 28 bytes = komm
©wrt 32 bytes = Composer
---- 74 bytes = mp3tag
©nam 29 bytes = bless
©day 28 bytes = 1971
m_ra 25 bytes = 255
m_cn 28 bytes = 1
m_lp 43 bytes = 04.12.2014 14:22:08

Add a custom field "GODF" with data "Godfather" using Godfather tagger. Mp3Tag detects this new field.
DemoApp:
trkn 32 bytes = 4294967296
©ART 26 bytes = rw
©nam 29 bytes = bless
©wrt 32 bytes = Composer
©alb 26 bytes = pm
©cmt 28 bytes = komm
©gen 27 bytes = Pop
©day 28 bytes = 1971
---- 74 bytes = mp3tag
---- 77 bytes = Godfather
aART 33 bytes = albArtist
m_lp 43 bytes = 04.12.2014 14:22:08
m_ra 26 bytes = 50111   //Whats this now?? I didn't change the value. Before it was 255 (Its a rating field)
m_cn 28 bytes = 1


Changed my code to use uppercase string for atom names: MURA,MUCN,MULP
DemoApp:
trkn 32 bytes = 4294967296
©ART 26 bytes = rw
©nam 29 bytes = bless
©wrt 32 bytes = Composer
©alb 26 bytes = pm
©cmt 28 bytes = komm
©gen 27 bytes = Pop
©day 28 bytes = 1971
---- 74 bytes = mp3tag
---- 77 bytes = Godfather
aART 33 bytes = albArtist
m_lp 43 bytes = 04.12.2014 14:22:08
m_ra 26 bytes = 50111
m_cn 28 bytes = 1
MURA 25 bytes = 175
MUCN 28 bytes = 1
MULP 43 bytes = 04.12.2014 14:25:40

Still mp3tag and godfather doesn't detect my custom fields.


Would be really great if this topic can be solved. Producing tags that are invisible for all other sounds not like standard...
My created m4a file is here: http://www.musican.net/data/bin/test.zip

Thanks for helping!

Sascha

Sascha

  • Guest
Re: NEW: Tags Library
« Reply #48 on: 4 Dec '14 - 16:36 »
Hey,

I just tried to get more clear information about this and did some additional tests...

Creating custom atoms with mp4 looks different in Hex than other taggers do it. I added two atoms "MPTA" and "GODF" with both data set to "test" with the tag editors. Then added an atom "MUSC" with data "test" from my code with MP4Tag. Looking in a hex viewer shows a difference how the atom names are added. Probably this is the reason why no other tool can read the MP4Tag created atoms. The file with this three atoms is on http://www.musican.net/data/bin/test2.zip

If you use Mp3-Tag and delete the complete tag the atoms created with MP4Tag still remains in the file.

Sascha

3delite

  • Posts: 907
Re: NEW: Tags Library
« Reply #49 on: 4 Dec '14 - 20:18 »
From your tests it seems the custom atoms created by other taggers have an atom name of '----'. What happens if you create an atom with MP4 Tag Library with that name? Can they read that then?

EDIT: Ok, I understand now, those taggers create these '----' atoms with a 'mean' and a 'name' sub-atoms.

Modified the tutorial and MP4 Tag Library to handle these sub-atoms.
Listing now shows:

---- 74 bytes = MPTG = com.apple.iTunes = mp3tag
---- 77 bytes = GODF = com.apple.iTunes = Godfather

So to read these use:

Code: [Select]
    MP4Tag.Atoms[i].name.GetAsText

this should return the atom name ('name' sub-atom content), which is what you set as 'MPTG' or 'GODF'.

The 'mean' seems to be always "com.apple.iTunes", to get this use:

Code: [Select]
    MP4Tag.Atoms[i].mean.GetAsText

So if you want to set such an atom with MP4 Tag Library, add a '----' atom, and set these sub-atoms with:

Code: [Select]
    MP4Tag.Atoms[i].name.SetAsText('MPTG');
    MP4Tag.Atoms[i].mean.SetAsText('com.apple.iTunes');
    MP4Tag.Atoms[i].SetAsText('The value here to set');

Please download the update: MP4TagLibrary.zip
Not tested, please try this.
« Last Edit: 4 Dec '14 - 20:55 by 3delite »