Jump to content

ID3 UDF ID3v1 & ID3v2 MP3 Tags


joeyb1275
 Share

Recommended Posts

heart of the matter:

MP3 downloads from the Internet, then the tags are removed, then the right fit

removetag but not working

translate.google.ru

$sPath is valid

Edited by spf
Link to comment
Share on other sites

It's more helpful if you reply with what has been asked.

The path may indeed be valid, but to put our time and effort into troubleshooting, we need confirmation from what we read in your code. That is especially important, for the odd looking variable you are using. We need to see an example of the data for that variable as returned by the use of a Msgbox (as suggested), and not just what you think it should be returning (i.e. C:MusicDeep PurpleMachine HeadSmoke On The Water.mp3).

Further to that.

1. Are you reading the tags in from each file, with the read command?

2. After removing the tag from each file, with the remove command, are you then writing to each file with the write command?

3. Obviously you need to do each file individually. Are you doing that?

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Link to comment
Share on other sites

  • 2 weeks later...

1.txt:

_link_1.mp3

_link_2.mp3

_link_3.mp3

. . . . .

_link_n.mp3

for $a = 1 to _FileCountLines('1.txt')
    $sPath = @scriptdir & '\' & $a & '.mp3'
    inetget(filereadline('1.txt', $a), $sPath, 17)
    _ID3RemoveTag($sPath, 0)
next

and error allocate memory

Edited by spf
Link to comment
Share on other sites

1.txt:

_link_1.mp3

_link_2.mp3

_link_3.mp3

. . . . .

_link_n.mp3

for $a = 1 to _FileCountLines('1.txt')
$sPath = @scriptdir & '\' & $a & '.mp3'
inetget(filereadline('1.txt', $a), $sPath, 17)
_ID3RemoveTag($sPath, 0)
next

and error allocate memory

Can you try calling _ID3ReadTag() first and let me know what it returns to see what kind of tags exist in the files?

Have you tried calling _ID3RemoveTag() in a separate script? I would try files that already exist on the hard drive (not using inetget())

Have you tried removing each tag separately with _ID3RemoveTag()?

I believe the error you are getting is from a fileread() call but I am not sure where in the UDF it is coming from. If you remove each tag separately we can try to narrow it down.

I have not seen this error on any of my mp3 files that I have tested.

Link to comment
Share on other sites

@spf

Can you post your script and the 1.txt file, or at least a part of 1.txt file so that it can be tested with the same procedure that you're using? It would help troubleshoot the problem if we knew what you were trying to do, how you're doing it, and what you're trying to download so that we can run these commands on the same files that you're using.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

1.txt:

_link_1.mp3

_link_2.mp3

_link_3.mp3

. . . . .

_link_n.mp3

for $a = 1 to _FileCountLines('1.txt')
$sPath = @scriptdir & '\' & $a & '.mp3'
inetget(filereadline('1.txt', $a), $sPath, 17)
_ID3RemoveTag($sPath, 0)
next

and error allocate memory

That code doesn't look right to me.

We need some explanation for context.

As with all coding issues, you need to pair things back to the simplest conditions, get that working first, then build up from there step by step. We shouldn't even be dealing with the InetGet command at this point or a file list or any variables.

Put one of your mp3 files in the script directory and hard code the path to it in the remove tag command.

If that does the job of removal correctly, then put the full path in a variable and try again.

If that works, then put the full path as a single line in a text file, then open and read that line to the variable.

Then use the For ... Next and the $a variable.

And so forth.

Narrow down where the problem lies.

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Link to comment
Share on other sites

  • 5 months later...

Can edit 3gp, mp4, wma, m4a?

Did you read the first post of this thread? If you did, reread it, all will be answered within.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

  • 1 month later...

I also don't post here much and  I appreciate all the efforts by everyone.

i spent a couple of days unsuccessfully trying to get ID3_v3.4.au3 to work but It wouldn't write tags in a ID3v2 file.

(Sample error with ID3_v3.4.au3 -> ID3_v3.4.au3(1315,29) : ERROR: Dec() [built-in] called with wrong number of args.)

However, the ID3.au3 version modified by TheSaint in March 2012 worked instantly!

in this post:

Can someone crown TheSaint's ID3.au3 as the current working winner and place it in post #1 as the newest (working) version?

Link to comment
Share on other sites

I also don't post here much and  I appreciate all the efforts by everyone.

i spent a couple of days unsuccessfully trying to get ID3_v3.4.au3 to work but It wouldn't write tags in a ID3v2 file.

(Sample error with ID3_v3.4.au3 -> ID3_v3.4.au3(1315,29) : ERROR: Dec() [built-in] called with wrong number of args.)

However, the ID3.au3 version modified by TheSaint in March 2012 worked instantly!

in this post:

Can someone crown TheSaint's ID3.au3 as the current working winner and place it in post #1 as the newest (working) version?

 

What version of AutoIt are you using?

I looked back at my previous releases and one big difference between ID3_v2.x.au3 and ID3_v3.x is that in the 3.x series I assume a newer version of Autoit is used (as stated in the first post) because the Dec() function changed.  In older versions the Dec() function could not handle 64bit numbers so in versions 2.x I had my own custom function to handle reading the TagSize (The version of ID3.au3 that TheSaint posted there is using this custom function), but when they (the awesome people behind AutoIt)  updated, they added more capability to the Dec() and so I use that now in 3.x versions.  

I think this is where this issue is, if not please let me know.  I would like to fix the 3.x version and not resort back to the 2.x series just to fix it.

Thanks for posting! 

 

Here is some more info;

ID3_v3.4.au3:  line 1315 -> Return Dec(Hex($bTagSize),2)

From the documentation on the Dec() function http://www.autoitscript.com/autoit3/docs/functions/Dec.htm two inputs are ok and if flag = 2 -> string is interpretted as 64bit integer

From the History of changes http://www.autoitscript.com/autoit3/docs/history.htm this change was made in 23rd December, 2011 - v3.3.8.0 AutoIt version.

     23rd December, 2011 - v3.3.8.0

AutoIt:

  • ......
  • Changed: COM Error handler passes error object as first parameter to user defined error function.
  • Changed: COM Error handler properties are read-only.
  • Changed: Dec() and Hex() work with 64bit integers.
  • Changed: Parentheses are required when invoking objects after all method names in order to have correct internal handling.
  • Changed: Dec(), Int(), Number() have second optional parameter defining non-default behavior.
  • Changed: Hex() detects doubles internally and processes them respecting binary format.
  • Changed: New visual style for the documetnation.
  • Changed: 64bit integers have 16 characters display by default.
  • .....
Edited by joeyb1275
Link to comment
Share on other sites

  • 2 weeks later...

I can't get the POPM to write, all it does is erase the rating I already have. This happens both in my script and the example script provided. I also tried to use the edited id3 from thesaint. I am using 0,1,64,128,196,255 as my values for input. Yes I verified the POPM is available under raw data. Im using autoit v3.3.8.1. What now?. Any other routes I can possibly take? File write properties or anything? Thanks.

Edited by Champak
Link to comment
Share on other sites

I can't get the POPM to write, all it does is erase the rating I already have. This happens both in my script and the example script provided. I also tried to use the edited id3 from thesaint. I am using 0,1,64,128,196,255 as my values for input. Yes I verified the POPM is available under raw data. Im using autoit v3.3.8.1. What now?. Any other routes I can possibly take? File write properties or anything? Thanks.

 

I have verified that this is a bug.  Thanks for letting me know about it Champak! I will get a fix out ASAP! 

Link to comment
Share on other sites

  • 4 weeks later...

Thanks you joeb1275 for this great UDF and thanks to all who helped make it better :thumbsup:

I noticed while using this UDF that it would take a long time(more than 10 seconds or so) to read the tags of 48 mp3 files (400 MB). Then I measured the time it takes for each mp3 and it turns out only a couple of mp3 files took around 3 seconds each while all rest were read in milliseconds.

I loaded one of the troublesome mp3 files in mp3tag it it showed up as corrupted so clearly this is not this UDFs fault. But I still wanted to figure out why I took so long and after some time measuring I tracked down the slowdown to the _h_ID3v2Tag_EnumerateFrameIDs() function.

Inside the function is the following For loop:

For $itest = 1 To ($iBytesRead + $iFrameSize + 20)
                    $bFrameHeader = BinaryMid($ID3v2_RawDataBinary,$iBytesRead + 1 + $itest,$iFrameHeaderLen)
                    $sFrameID = _h_ID3v2FrameHeader_GetFrameID($bFrameHeader)
                    If $sFrameID <> -1 Then
                        $iBytesRead += $itest
;~                      MsgBox(0,"$iBytesRead Really in Frame",$itest)
                        $iFrameSize = _h_ID3v2FrameHeader_GetFrameSize($bFrameHeader)
;~                      MsgBox(0,"$FrameSize",$iFrameSize)
                        ExitLoop 1
                    Else
;~                      MsgBox(0,"Error Check Scan Frame",String($iBytesRead + 1 + $itest) & " => " & $FrameID)
                    EndIf
                Next

I think this loops through the tag after an invalid tagID is found until a frameheader is found. I think there is a problem in either the $itest condition value or the $sFrameHeader initialization in binarymid. You can see that in both of those $iBytesRead is added and $iBytesRead is added to $itest in binarymid.

This can lead to the for loop reading well beyond the tag size.

I changed the code to the following:

For $itest = 1 To ($iTagSize - $iBytesRead - $iFrameHeaderLen)
                    $iBinStart = $iBytesRead + $itest
                    $bFrameHeader = BinaryMid($ID3v2_RawDataBinary, $iBinStart, $iFrameHeaderLen)
;~                  MsgBox(0, "new $bFrameHeader", $bFrameHeader)
                    $sFrameID = _h_ID3v2FrameHeader_GetFrameID($bFrameHeader)
                    If $sFrameID <> -1 Then
                        $iBytesRead += $itest
;~                      MsgBox(0, "$iBytesRead Really in Frame", $itest)
                        $iFrameSize = _h_ID3v2FrameHeader_GetFrameSize($bFrameHeader)
;~                      MsgBox(0, "$FrameSize", $iFrameSize)
                        ExitLoop 1
                    Else
;~                      MsgBox(0, "Error Check Scan Frame", String($iBytesRead + 1 + $itest) & " => " & $sFrameID)
                    EndIf
Next

And the corrupted mp3 files are now read in about 300 milliseconds!

I think another thing to add to increase the speed even more is to check if the tag padding area is reached. Although this speeds up things with my corrupted mp3s this might not be a fix at all for other cases since I don't understand the reason behind the original loop condition value.

Edit:

It seems this UDF does not work with the latest AutoIt v3.3.10.0 – 23rd December, 2013. The UDF compiles correctly but _ID3GetTagField() functions return nothing.

And a link to one of the corrupt mp3s https://db.tt/g9xdTbU5 (Dropbox)

Another edit:

I did some debugging and noticed that the Dec() function that is used to convert hexadecimal frame size to decimal always returns 1 when the flag is set to 1(32 bit) or 2(64 bit)

$bTagSize = "0x00031160"

MsgBox(0, "", Dec(Hex($bTagSize), 1))     ;Returns 1
MsgBox(0, "", Dec(Hex($bTagSize), 2))     ;Returns 1
MsgBox(0, "", Dec(Hex($bTagSize)))     ;Returns the correct decimal representation

I removed the flag value from all the Dec() calls and it seems that fixed it, though I only tested it with ID3v2 tags because I removed v1 tags from my mp3s.

here is the updated UDF https://db.tt/Yz4GUF48

Edited by mvk25
Link to comment
Share on other sites

  • 3 weeks later...

Hi, :)

I found a bug in the _h_ID3v2_CreateFrameUSLT function

Func _h_ID3v2_CreateFrameUSLT($sLyricsFilename, $sDescription = "", $sLanguage = "eng", $iTextEncoding = 0)
    ;---------------------------------------------------------------------------------
    ;<Header for 'Unsynchronised lyrics/text transcription', ID: "USLT">
    ;Text encoding        $xx
    ;Language             $xx xx xx
    ;Content descriptor   <text string according to encoding> $00 (00)
    ;Lyrics/text          <full text string according to encoding>
    ;---------------------------------------------------------------------------------

    Local $sLyrics = ""
    If FileExists($sLyricsFilename) Then
        $sLyrics = FileRead($sLyricsFilename)
    Endif

    Local $bFrameData = Binary("0x0" & String($iTextEncoding))
    $bFrameData &= _h_ID3v2_EncodeStringToBinary($iTextEncoding, $sLanguage)
    $bFrameData &= _h_ID3v2_EncodeStringToBinary($iTextEncoding, $sDescription) & Binary("0x00")
    $bFrameData &= _h_ID3v2_EncodeStringToBinary($iTextEncoding, $sLyrics)

;~  MsgBox(0,"$bFrameData",$bFrameData)
    Return $bFrameData

EndFunc   ;==>_h_ID3v2_CreateFrameUSLT

The function assumes that is will be provided a file as the first parameter but internally it is called with the lyrics string itself so it never executes because the file does not exist

changing the code to this will make it work:

If FileExists($sLyricsFilename) Then
    $sLyrics = FileRead($sLyricsFilename)
Else
    $sLyrics = $sLyricsFilename
EndIf
Link to comment
Share on other sites

  • 2 weeks later...

Hi,

Is it possible to use this code to change the character encoding on MP3s? I'd like to change some MP3s from ID3v2.4, UTF-8 encoding to ID3v2.3, ISO-8859-1 encoding. (This is so my in-car MP3 player will recognise them correctly.) Your code seems to read ISO-8859-1 encoded MP3s correctly, but I couldn't see how to set the encoding manually. Is this possible?

Thanks - an excellent UDF by the way!

Link to comment
Share on other sites

Never mind: I managed to work it out...

;set tags to ISO-8859-1 encoding (for compatibility with car MP3 CD player)
Func setISO88591Tags ($fileName)
;~  ConsoleWrite($fileName & @LF)
    $sTagInfo = _ID3ReadTag($Filename, 2) ;ID3v2 only - no encoding issue with ID3v1
;~  ConsoleWrite($sTagInfo & @LF)
    $sTagInfo = StringSplit ($sTagInfo, @CRLF, 1)
    If $sTagInfo[0] > 1 Then ;tag definitely present
        $sTagInfo = StringSplit ($sTagInfo[2], "|")
        For $i = 2 To $sTagInfo[0]
    ;~      ConsoleWrite($sTagInfo[$i] & @LF)
            $tagSplit = StringSplit ($sTagInfo[$i], ":")
            $tagName = $tagSplit[1]
            For $j = 1 To $tagSplit[2]
                $tagFields = _ID3v2Frame_GetFields ($tagName, $j, 1)
    ;~          _ArrayDisplay($tagFields)
                If $tagFields[$tagFields[0]] > 0 Then
                    $tagFields[$tagFields[0]] = 0 ;set encoding to ISO-8859-1
                    $tagChanged = True
                    _ID3SetTagField ($tagName, $tagFields, $j)
                EndIf
            Next
        Next
        if $tagChanged Then
            _ID3WriteTag ($Filename)
            ConsoleWrite("--Updated " & $fileName & " tag encoding to ISO-8859-1" & @LF)
        EndIf
    EndIf
    Return FileGetSize ($fileName) ;may have changed
EndFunc

That seems to get the job done; I just need to check now that the files created using this can be read by my car's MP3 player.

Link to comment
Share on other sites

  • 1 month later...

I have verified that this is a bug.  Thanks for letting me know about it Champak! I will get a fix out ASAP! 

 

Does anybody know how to fix the POPM tagging issue in post 133?  I've tried all the different versions of the UDF in this thread and none of them write the POPM tag.

Link to comment
Share on other sites

  • 2 weeks later...

Just read this and remembered a PM exchange I had a while ago with Champak:

 

The reason seems that the POPM call is not implemented in the UDF.

_AudioGenie.zip

Download the documentation for the dll here:

http://sourceforge.net/projects/audiogenie/files/V2.0.4.0/doc/

#include <AudioGenie3_v1.au3>

$sFile_Org = @ScriptDir & "\218_deichkind_-_remmidemmi_(yippie_yippie_yeah).mp3"
$sFile = StringReplace($sFile_Org, ".mp3", "_copy.mp3")
FileCopy($sFile_Org, $sFile, 1)

_AudioGenie3_Start()

ConsoleWrite("! Read #1 " & @crlf & "==========" & @crlf)
$rc = DllCall($_AudioGenie3DLLHandle, "int", "AUDIOAnalyzeFileW", "wstr", $sFile) ; open the file and ensure its a mp3 (returns 1)
$icounter = 0
While 1
    $icounter += 1
    $rc = DllCall($_AudioGenie3DLLHandle, "int", "ID3V2GetPopularimeterCounterW", "short", $icounter)
    If $rc[0] = -1 Then ExitLoop
    ConsoleWrite(@crlf & "-Enum #" & $icounter & @CRLF)
    ConsoleWrite("Count" & @tab & $rc[0] & @CRLF)
    $rc = DllCall($_AudioGenie3DLLHandle, "wstr", "ID3V2GetPopularimeterEmailW", "short", $icounter)
    ConsoleWrite("Email" & @tab & $rc[0] & @CRLF)
    $rc = DllCall($_AudioGenie3DLLHandle, "short", "ID3V2GetPopularimeterRatingW", "short", $icounter)
    ConsoleWrite("Rating (1-255)" & @tab & $rc[0] & @CRLF)
WEnd
ConsoleWrite("----------" & @crlf & @crlf)

ConsoleWrite("+ Write #1" & @crlf & "==========" & @crlf)
$rc = DllCall($_AudioGenie3DLLHandle, "int", "AUDIOAnalyzeFileW", "wstr", $sFile) ; open the file and ensure its a mp3 (returns 1)
ConsoleWrite($rc[0] & @CRLF)
DllCall($_AudioGenie3DLLHandle, "short", "ID3V2AddPopularimeterW", "wstr", "kafu@amt.cc", "short", 255, "int", 999)
$rc = DllCall($_AudioGenie3DLLHandle, "int", "ID3V2SaveChangesW")
ConsoleWrite($rc[0] & @CRLF & @crlf)

ConsoleWrite("+ Write #2" & @crlf & "==========" & @crlf)
$rc = DllCall($_AudioGenie3DLLHandle, "int", "AUDIOAnalyzeFileW", "wstr", $sFile) ; open the file and ensure its a mp3 (returns 1)
ConsoleWrite($rc[0] & @CRLF)
DllCall($_AudioGenie3DLLHandle, "short", "ID3V2AddPopularimeterW", "wstr", "kafu2@amt.cc", "short", 155, "int", 333)
$rc = DllCall($_AudioGenie3DLLHandle, "int", "ID3V2SaveChangesW")
ConsoleWrite($rc[0] & @CRLF & @crlf)


ConsoleWrite("! Read #2 " & @crlf & "==========" & @crlf)
$rc = DllCall($_AudioGenie3DLLHandle, "int", "AUDIOAnalyzeFileW", "wstr", $sFile) ; open the file and ensure its a mp3 (returns 1)
$icounter = 0
While 1
    $icounter += 1
    $rc = DllCall($_AudioGenie3DLLHandle, "int", "ID3V2GetPopularimeterCounterW", "short", $icounter)
    If $rc[0] = -1 Then ExitLoop
    ConsoleWrite(@crlf & "-Enum #" & $icounter & @CRLF)
    ConsoleWrite("Count" & @tab & $rc[0] & @CRLF)
    $rc = DllCall($_AudioGenie3DLLHandle, "wstr", "ID3V2GetPopularimeterEmailW", "short", $icounter)
    ConsoleWrite("Email" & @tab & $rc[0] & @CRLF)
    $rc = DllCall($_AudioGenie3DLLHandle, "short", "ID3V2GetPopularimeterRatingW", "short", $icounter)
    ConsoleWrite("Rating (1-255)" & @tab & $rc[0] & @CRLF)
WEnd
ConsoleWrite("----------" & @crlf & @crlf)

Re: Value of ID3v2 POPM field and MM's Rating

icon_post_target.gifby MrSinatra » Fri Dec 14, 2012 9:31 pm

i do not use MM, but here is what windows explorer uses:

>>
224-255 = 5 stars when READ with windows explorer, writes 255
160-223 = 4 stars when READ with windows explorer, writes 196
096-159 = 3 stars when READ with windows explorer, writes 128
032-095 = 2 stars when READ with windows explorer, writes 64
001-031 = 1 stars when READ with windows explorer, writes 1

windows explorer uses this syntax:

Windows Media Player 9 Series | 255 | 0

(the 0 is playcounts as per POPM id3 spec. note the ID string isn't even an email address)

Edited by KaFu
Link to comment
Share on other sites

  • 2 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...