Lazycat 15 Posted August 21, 2004 Share Posted August 21, 2004 (edited) This is a rather raw version of UDF. Currently it's doesn't understand MPEG2 and MPEG2.5 files (need to add lookups for different types), but should work with most usual MP3's. I'm tried to do something with the script in this topic. Although some ideas are usefull, it seems a bit hard to understand and realize by this way Anyway, if you need it - please test it.Edited: Old code removed, latest version here: http://www.autoitscript.com/fileman/users/public/Kot/get_mp3_info.zip Edited August 28, 2004 by Kot Koda homepage ([s]Outdated Koda homepage[/s]) (Bug Tracker)My Autoit script page ([s]Outdated mirror[/s]) Link to post Share on other sites
Cape-City 0 Posted August 22, 2004 Share Posted August 22, 2004 (edited) Hi Kot, this is cool and if at least the TrackLengh Calculation will work that would be fantastic. Only to calculate like in the VB script is not that problem (me think), but what the hell is the mp3_pad ??? Greetz Cape-City Edited August 22, 2004 by Cape-City Link to post Share on other sites
Lazycat 15 Posted August 22, 2004 Author Share Posted August 22, 2004 this is cool and if at least the TrackLengh Calculation will work that would be fantastic. Only to calculate like in the vb script: now it should support any MP3 (even VBR ones). But now I have not idea how to get length of VBR file. expandcollapse popup$file = FileOpenDialog("Please select file", "", "MP3 files (*.mp3)"); if @error then Exit $aData = _GetMP3Info($file) if @error then Exit $aLabel = StringSplit("MPEG Version: |Layer: |Bitrate: |Frequency: |Channel Mode: |Have CRC: |Copyright: |Original: ", "|") Dim $out = "" for $i = 0 to UBound($aData)-1 $out = $out & $aLabel[$i+1] & $aData[$i] & @CR next MsgBox (0, "MP3 Data", $out) ;=============================================================================== ; ; Description: Retrieve MP3 basic information ; Parameter(s): File name ; Requirement(s): None ; Return Value(s): On Success - array with data: ; 0 - MPEG version ; 1 - Layer ; 2 - Bitrate ; 3 - Frequency ; 4 - Channel Mode ; 5 - CRC protected ; 6 - Copyrighted ; 7 - Original ; On Failure empty string and sets @ERROR: ; 1 - Info not found ; Author(s): YDY (Kot) <mpc@nm.ru> ; Version: 1.0.00 ; Date: 22.08.2004 ; Note(s): None ; ;=============================================================================== Func _GetMP3Info($file) Local $frame = "", $data[8], $offset = 1, $isVBR = 0 Local $aVersion = StringSplit("MPEG 2.5|Undefined|MPEG 2.5|MPEG 1", "|") Local $aLayer = StringSplit("Undefined|Layer III|Layer II|Layer I", "|") Local $sBitrate = "" Local $sFrequency = "" Local $aChanMode = StringSplit("Stereo|Joint stereo|Dual channel|Mono", "|") Local $aFlags = StringSplit("No|Yes", "|") If _FileReadAtOffsetHEX ($file, 1, 3) = "494433" Then; ID3v2 tag found $offset = BitShift(Dec(_FileReadAtOffsetHEX ($file, 7, 4)), 1); End of ID3v2 tag Endif For $ic = $offset to 2048 + $offset $marker = _FileReadAtOffsetHEX ($file, $ic, 2) $marker = StringLeft($marker, 3) If StringInStr("FFF,FFE", $marker) Then; Assume that is frame start $frame = _FileReadAtOffsetHEX ($file, $ic, 4) If _FileReadAtOffsetHEX ($file, $ic+36, 4) = "58696E67" Then $isVBR = 1; This is a right way?.. Exitloop Endif Next If $frame = "" Then SetError(1); Frame not found (not mp3 data?) Return ("") Endif Local $head = _HexToBin($frame) Local $nVer = _GetRBits($head, 19, 2) Local $nLay = _GetRBits($head, 17, 2) Select Case $nVer = 3 $sFrequency = "44100|48000|32000|Undefined" Case $nVer = 2 $sFrequency = "22050|24000|16000|Undefined" Case $nVer = 0 $sFrequency = "11025|12000|8000|Undefined" EndSelect Local $aFrequency = StringSplit($sFrequency, "|") If $isVBR Then $data[2] = "Variable" Else Select Case $nVer = 3 and $nLay = 3 $sBitrate = "Free|32|64|96|128|160|192|224|256|288|320|352|384|416|448|Undefined" Case $nVer = 3 and $nLay = 2 $sBitrate = "Free|32|48|56|64|80|96|112|128|160|192|224|256|320|384|Undefined" Case $nVer = 3 and $nLay = 1 $sBitrate = "Free|32|40|48|56|64|80|96|112|128|160|192|224|256|320|Undefined" Case $nVer = 2 and $nLay = 3 $sBitrate = "Free|32|48|56|64|80|96|112|128|144|160|176|192|224|256|Undefined" Case ($nVer = 2 and $nLay = 2) or ($nVer = 2 and $nLay = 1) $sBitrate = "Free|8|16|24|32|40|48|56|64|80|96|112|128|144|160|Undefined" EndSelect Local $aBitrate = StringSplit($sBitrate, "|") $data[2] = _GetData($aBitrate, _GetRBits($head, 12, 4)) Endif $data[0] = _GetData($aVersion, $nVer) $data[1] = _GetData($aLayer, $nLay) $data[3] = _GetData($aFrequency, _GetRBits($head, 10, 2)) $data[4] = _GetData($aChanMode, _GetRBits($head, 6, 2)) $data[5] = _GetData($aFlags, not _GetRBits($head, 16, 1)); CRC $data[6] = _GetData($aFlags, _GetRBits($head, 3, 1)); Private $data[7] = _GetData($aFlags, _GetRBits($head, 2, 1)); Original Return($data) EndFunc Func _GetRBits($str, $pos, $size) Local $ic, $res = 0, $bStr = StringMid($str, 33 - $pos - $size, $size) For $ic = 0 to $size-1 If StringMid($bStr, $size-$ic, 1) == "1" Then $res = $res + 2^$ic Next Return ($res) EndFunc Func _GetData(ByRef $array, $val) If $val > UBound($array)-1 Then Return("Undefined") Return ($array[$val+1]) EndFunc Func _HexToBin($str) Local $res="" While StringLen($str) > 0 $val = Dec(StringLeft($str, 1)) $str = StringTrimLeft($str, 1) For $i = 3 to 0 Step -1 $pw = 2^$i If $val - $pw < 0 Then $res = $res & "0" Else $res = $res & "1" $val = $val - $pw Endif Next Wend Return ($res) EndFunc Func _FileReadAtOffsetHEX ($file, $offset, $bytes) Local $tfile = FileOpen($file, 0) Local $tstr = "" FileRead($tfile, $offset-1) For $i = $offset To $offset + $bytes - 1 $tstr = $tstr & Hex(Asc(FileRead($tfile, 1)), 2) Next FileClose($tfile) Return ($tstr) Endfunc Koda homepage ([s]Outdated Koda homepage[/s]) (Bug Tracker)My Autoit script page ([s]Outdated mirror[/s]) Link to post Share on other sites
Cape-City 0 Posted August 22, 2004 Share Posted August 22, 2004 Hi, when i add the calculation from the VB script, it not exatly shows the duration, but it's more then nothing : expandcollapse popup$file = FileOpenDialog("Please select file", "", "MP3 files (*.mp3)"); if @error then Exit $Filesize = FileGetSize($file) $aData = _GetMP3Info($file) if @error then Exit $aLabel = StringSplit("MPEG Version: |Layer: |Bitrate: |Frequency: |Channel Mode: |Have CRC: |Copyright: |Original: |Duration (ms): ", "|") Dim $out = "" for $i = 0 to UBound($aData)-1 $out = $out & $aLabel[$i+1] & $aData[$i] & @CR next MsgBox (0, "MP3 Data", $out) ;=============================================================================== ; ; Description: Retrieve MP3 basic information ; Parameter(s): File name ; Requirement(s): None ; Return Value(s): On Success - array with data: ; 0 - MPEG version ; 1 - Layer ; 2 - Bitrate ; 3 - Frequency ; 4 - Channel Mode ; 5 - CRC protected ; 6 - Copyrighted ; 7 - Original ; 8 - Duration ; On Failure empty string and sets @ERROR: ; 1 - Info not found ; Author(s): YDY (Kot) <mpc@nm.ru> ; Version: 1.0.00 ; Date: 22.08.2004 ; Note(s): None ; ;=============================================================================== Func _GetMP3Info($file) Local $frame = "", $data[9], $offset = 1, $isVBR = 0 Local $aVersion = StringSplit("MPEG 2.5|Undefined|MPEG 2.5|MPEG 1", "|") Local $aLayer = StringSplit("Undefined|Layer III|Layer II|Layer I", "|") Local $sBitrate = "" Local $sFrequency = "" Local $aChanMode = StringSplit("Stereo|Joint stereo|Dual channel|Mono", "|") Local $aFlags = StringSplit("No|Yes", "|") If _FileReadAtOffsetHEX ($file, 1, 3) = "494433" Then; ID3v2 tag found $offset = BitShift(Dec(_FileReadAtOffsetHEX ($file, 7, 4)), 1); End of ID3v2 tag Endif For $ic = $offset to 2048 + $offset $marker = _FileReadAtOffsetHEX ($file, $ic, 2) $marker = StringLeft($marker, 3) If StringInStr("FFF,FFE", $marker) Then; Assume that is frame start $frame = _FileReadAtOffsetHEX ($file, $ic, 4) If _FileReadAtOffsetHEX ($file, $ic+36, 4) = "58696E67" Then $isVBR = 1; This is a right way?.. Exitloop Endif Next If $frame = "" Then SetError(1); Frame not found (not mp3 data?) Return ("") Endif Local $head = _HexToBin($frame) Local $nVer = _GetRBits($head, 19, 2) Local $nLay = _GetRBits($head, 17, 2) Select Case $nVer = 3 $sFrequency = "44100|48000|32000|Undefined" Case $nVer = 2 $sFrequency = "22050|24000|16000|Undefined" Case $nVer = 0 $sFrequency = "11025|12000|8000|Undefined" EndSelect Local $aFrequency = StringSplit($sFrequency, "|") If $isVBR Then $data[2] = "Variable" Else Select Case $nVer = 3 and $nLay = 3 $sBitrate = "Free|32|64|96|128|160|192|224|256|288|320|352|384|416|448|Undefined" Case $nVer = 3 and $nLay = 2 $sBitrate = "Free|32|48|56|64|80|96|112|128|160|192|224|256|320|384|Undefined" Case $nVer = 3 and $nLay = 1 $sBitrate = "Free|32|40|48|56|64|80|96|112|128|160|192|224|256|320|Undefined" Case $nVer = 2 and $nLay = 3 $sBitrate = "Free|32|48|56|64|80|96|112|128|144|160|176|192|224|256|Undefined" Case ($nVer = 2 and $nLay = 2) or ($nVer = 2 and $nLay = 1) $sBitrate = "Free|8|16|24|32|40|48|56|64|80|96|112|128|144|160|Undefined" EndSelect Local $aBitrate = StringSplit($sBitrate, "|") $data[2] = _GetData($aBitrate, _GetRBits($head, 12, 4)) Endif $data[0] = _GetData($aVersion, $nVer) $data[1] = _GetData($aLayer, $nLay) $data[3] = _GetData($aFrequency, _GetRBits($head, 10, 2)) $data[4] = _GetData($aChanMode, _GetRBits($head, 6, 2)) $data[5] = _GetData($aFlags, not _GetRBits($head, 16, 1)); CRC $data[6] = _GetData($aFlags, _GetRBits($head, 3, 1)); Private $data[7] = _GetData($aFlags, _GetRBits($head, 2, 1)); Original $Framesize = ((144 * $data[2]) / $data[3]) $Total_frames = $Filesize / $Framesize $Track_length = ($Total_frames / 38.5); / 1000 (to get sec) $data[8] = $Track_length; / 60 (to get min) Return($data) EndFunc Func _GetRBits($str, $pos, $size) Local $ic, $res = 0, $bStr = StringMid($str, 33 - $pos - $size, $size) For $ic = 0 to $size-1 If StringMid($bStr, $size-$ic, 1) == "1" Then $res = $res + 2^$ic Next Return ($res) EndFunc Func _GetData(ByRef $array, $val) If $val > UBound($array)-1 Then Return("Undefined") Return ($array[$val+1]) EndFunc Func _HexToBin($str) Local $res="" While StringLen($str) > 0 $val = Dec(StringLeft($str, 1)) $str = StringTrimLeft($str, 1) For $i = 3 to 0 Step -1 $pw = 2^$i If $val - $pw < 0 Then $res = $res & "0" Else $res = $res & "1" $val = $val - $pw Endif Next Wend Return ($res) EndFunc Func _FileReadAtOffsetHEX ($file, $offset, $bytes) Local $tfile = FileOpen($file, 0) Local $tstr = "" FileRead($tfile, $offset-1) For $i = $offset To $offset + $bytes - 1 $tstr = $tstr & Hex(Asc(FileRead($tfile, 1)), 2) Next FileClose($tfile) Return ($tstr) Endfunc Greetz Cape-City Link to post Share on other sites
Lazycat 15 Posted August 22, 2004 Author Share Posted August 22, 2004 (edited) when i add the calculation from the VB script, it not exatly shows the duration, but it's more then nothing :I'm suspect that calculation is very rough (what the strange divisor 38.5?) - it usually give 1-3 seconds error. Try new version: seems this is more accurate. expandcollapse popup$file = FileOpenDialog("Please select file", "", "MPEG files (*.mp3;*.mp2;*.mpa)"); if @error then Exit $aData = _GetMP3Info($file) if @error then Exit $aLabel = StringSplit("MPEG Version: |Layer: |Bitrate: |Frequency: |Channel Mode: |Duration: |Frames: |Have CRC: |Copyright: |Original: ", "|") Dim $out = "" for $i = 0 to UBound($aData)-1 $out = $out & $aLabel[$i+1] & $aData[$i] & @CR next MsgBox (0, "MPEG File Info", $out) ;=============================================================================== ; ; Description: Retrieve MP3 (MP2, MPA) basic information ; Parameter(s): File name ; Requirement(s): None ; Return Value(s): On Success - array with data: ; 0 - MPEG version ; 1 - Layer ; 2 - Bitrate ; 3 - Frequency ; 4 - Channel Mode ; 5 - Duration ; 6 - Frames ; 7 - CRC protected ; 8 - Copyrighted ; 9 - Original ; On Failure empty string and sets @ERROR: ; 1 - Info not found ; Author(s): YDY (Kot) <mpc@nm.ru> ; Version: 1.0.00 ; Date: 22.08.2004 ; Note(s): None ; ;=============================================================================== Func _GetMP3Info($file) Local $frame = "", $data[10], $offset = 1, $isVBR = 0 Local $aVersion = StringSplit("MPEG 2.5|Undefined|MPEG 2.5|MPEG 1", "|") Local $aLayer = StringSplit("Undefined|Layer III|Layer II|Layer I", "|") Local $sBitrate = "" Local $sFrequency = "" Local $aChanMode = StringSplit("Stereo|Joint stereo|Dual channel|Mono", "|") Local $aFlags = StringSplit("No|Yes", "|") If _FileReadAtOffsetHEX ($file, 1, 3) = "494433" Then; ID3v2 tag found $offset = BitShift(Dec(_FileReadAtOffsetHEX ($file, 7, 4)), 1); End of ID3v2 tag Endif For $ic = $offset to 2048 + $offset $marker = _FileReadAtOffsetHEX ($file, $ic, 2) $marker = StringLeft($marker, 3) If StringInStr("FFF,FFE", $marker) Then; Assume that is frame start $frame = _FileReadAtOffsetHEX ($file, $ic, 4) If _FileReadAtOffsetHEX ($file, $ic+36, 4) = "58696E67" Then $isVBR = 1; Is this a right way?.. Exitloop Endif Next If $frame = "" Then SetError(1); Frame not found (not mp3 data?) Return ("") Endif Local $head = _HexToBin($frame) Local $nVer = _GetRBits($head, 19, 2) Local $nLay = _GetRBits($head, 17, 2) Select Case $nVer = 3 $sFrequency = "44100|48000|32000|Undefined" Case $nVer = 2 $sFrequency = "22050|24000|16000|Undefined" Case $nVer = 0 $sFrequency = "11025|12000|8000|Undefined" EndSelect Local $aFrequency = StringSplit($sFrequency, "|") $data[3] = _GetData($aFrequency, _GetRBits($head, 10, 2)) Local $pad = 0, $bitrate, $framesize, $frames, $length, $fps If _GetRBits($head, 9, 1) Then $pad = 1 If $isVBR Then $data[2] = "Variable" Else Select Case $nVer = 3 and $nLay = 3 $sBitrate = "Free|32|64|96|128|160|192|224|256|288|320|352|384|416|448|Undefined" Case $nVer = 3 and $nLay = 2 $sBitrate = "Free|32|48|56|64|80|96|112|128|160|192|224|256|320|384|Undefined" Case $nVer = 3 and $nLay = 1 $sBitrate = "Free|32|40|48|56|64|80|96|112|128|160|192|224|256|320|Undefined" Case $nVer = 2 and $nLay = 3 $sBitrate = "Free|32|48|56|64|80|96|112|128|144|160|176|192|224|256|Undefined" Case ($nVer = 2 and $nLay = 2) or ($nVer = 2 and $nLay = 1) $sBitrate = "Free|8|16|24|32|40|48|56|64|80|96|112|128|144|160|Undefined" EndSelect Local $aBitrate = StringSplit($sBitrate, "|") $data[2] = _GetData($aBitrate, _GetRBits($head, 12, 4)) $bitrate = 1000 * $data[2] If $nLay = 3 Then $framesize = (((12 * $bitrate) / $data[3]) + $pad) * 4 $fps = $data[3]/384 Else $framesize = ((144 * $bitrate) / $data[3]) + $pad $fps = $data[3]/1152 Endif $frames = FileGetSize($file) / $framesize $length = $frames / $fps Endif $data[0] = _GetData($aVersion, $nVer) $data[1] = _GetData($aLayer, $nLay) $data[4] = _GetData($aChanMode, _GetRBits($head, 6, 2)) $data[5] = StringFormat("%d:%02d", Int($length / 60), $length - Int($length / 60) * 60) $data[6] = Int($frames) $data[7] = _GetData($aFlags, not _GetRBits($head, 16, 1)); CRC $data[8] = _GetData($aFlags, _GetRBits($head, 3, 1)); Private $data[9] = _GetData($aFlags, _GetRBits($head, 2, 1)); Original Return($data) EndFunc Func _GetRBits($str, $pos, $size) Local $ic, $res = 0, $bStr = StringMid($str, 33 - $pos - $size, $size) For $ic = 0 to $size-1 If StringMid($bStr, $size-$ic, 1) == "1" Then $res = $res + 2^$ic Next Return ($res) EndFunc Func _GetData(ByRef $array, $val) If $val > UBound($array)-1 Then Return("Undefined") Return ($array[$val+1]) EndFunc Func _HexToBin($str) Local $res="" While StringLen($str) > 0 $val = Dec(StringLeft($str, 1)) $str = StringTrimLeft($str, 1) For $i = 3 to 0 Step -1 $pw = 2^$i If $val - $pw < 0 Then $res = $res & "0" Else $res = $res & "1" $val = $val - $pw Endif Next Wend Return ($res) EndFunc Func _FileReadAtOffsetHEX ($file, $offset, $bytes) Local $tfile = FileOpen($file, 0) Local $tstr = "" FileRead($tfile, $offset-1) For $i = $offset To $offset + $bytes - 1 $tstr = $tstr & Hex(Asc(FileRead($tfile, 1)), 2) Next FileClose($tfile) Return ($tstr) Endfunc Edited August 22, 2004 by Kot Koda homepage ([s]Outdated Koda homepage[/s]) (Bug Tracker)My Autoit script page ([s]Outdated mirror[/s]) Link to post Share on other sites
Cape-City 0 Posted August 23, 2004 Share Posted August 23, 2004 Hi,38.5 frames per second (out of the VB script), but U're Version is muchbetter, that's right. Now there is only one problem left :http://www.autoitscript.com/forum/index.php?showtopic=4402When i call e.g. WinAMP, it just cut off after 40 parameters, but a AutoItscript always crashed with a stack overflow.GreetzCape-City Link to post Share on other sites
Cape-City 0 Posted August 24, 2004 Share Posted August 24, 2004 Hi, I got some errors with a few MP3 files, here the info out of winamp : Size: 3593219 bytes Header found at: 1723 bytes Length: 64 seconds MPEG 1.0 layer 1 448kbit, 1781 frames 32000Hz Stereo CRCs: No Copyrighted: No Original: No Emphasis: invalid --> Duration : Unidentified Size: 3477504 bytes Header found at: 3127 bytes Length: 217 seconds MPEG 1.0 layer 3 128kbit, 8334 frames 44100Hz Stereo CRCs: No Copyrighted: No Original: Yes Emphasis: None U're script end with error in this function : Func _GetData(ByRef $array, $val) If $val > UBound($array)-1 Then Return("Undefined") Return ($array[$val+1]) EndFunc Error: Array variable has incorrect number of substrings or subscript dimension range exceeded. Greetz Cape-City Link to post Share on other sites
Lazycat 15 Posted August 24, 2004 Author Share Posted August 24, 2004 Hmm... Maybe input value happened negative?.. Try to change this function with following code: Func _GetData(ByRef $array, $val) If ($val > UBound($array)-1) or ($val < 0) Then Return("Undefined") Return ($array[$val+1]) EndFunc Koda homepage ([s]Outdated Koda homepage[/s]) (Bug Tracker)My Autoit script page ([s]Outdated mirror[/s]) Link to post Share on other sites
Cape-City 0 Posted August 24, 2004 Share Posted August 24, 2004 (edited) Hi, I tried this : Func _GetData(ByRef $array, $val) If ($val > UBound($array)-1) or ($val < 0) Then Return("Undefined") MsgBox(0, "Val :", $val) Return ($array[$val+1]) EndFunc On a working MP3 I get e.g. this values : 0,9,3,1,0,0,0,1 or 3,15,3,3,3,0,1,1 or 0,9,3,1,0,0,1 At the special MP3 I got : 1 and then the script crashed ... Seems he had a prob with $array[2] ??? Greetz Cape-City Edited August 24, 2004 by Cape-City Link to post Share on other sites
Lazycat 15 Posted August 25, 2004 Author Share Posted August 25, 2004 I'm not figure where the problem is. Do you can to cut 80-100 kb of this MP3 and send me by email? Koda homepage ([s]Outdated Koda homepage[/s]) (Bug Tracker)My Autoit script page ([s]Outdated mirror[/s]) Link to post Share on other sites
Cape-City 0 Posted August 25, 2004 Share Posted August 25, 2004 It's on the way ... Greetz Cape-City Link to post Share on other sites
Cape-City 0 Posted August 27, 2004 Share Posted August 27, 2004 Hi, did U got it ? Greetz Cape-City Link to post Share on other sites
Lazycat 15 Posted August 27, 2004 Author Share Posted August 27, 2004 Nope Do you can to post this in the public file area? Koda homepage ([s]Outdated Koda homepage[/s]) (Bug Tracker)My Autoit script page ([s]Outdated mirror[/s]) Link to post Share on other sites
Cape-City 0 Posted August 28, 2004 Share Posted August 28, 2004 (edited) Hi,U can download it here :http://people.freenet.de/Cape-City/myHTPC/Downloads/MP3.zipGreetz Cape-City Edited August 28, 2004 by Cape-City Link to post Share on other sites
Lazycat 15 Posted August 28, 2004 Author Share Posted August 28, 2004 Thanks, I have revisited code.Strange file, the first frames after v2 tag looks like normal, but contain wrong info (frame corrupt?) I put new check into frame search loop, so now it will search until first correct (possibly) frame appear. Now limit of search distance is 4096 bytes, after that error will be return. I'm not sure that checking only MPEG version and layer will be enough for conclusion that frame is correct or corrupt, so please test it.New version is here: http://www.autoitscript.com/fileman/users/public/Kot/get_mp3_info.zip Koda homepage ([s]Outdated Koda homepage[/s]) (Bug Tracker)My Autoit script page ([s]Outdated mirror[/s]) Link to post Share on other sites
Cape-City 0 Posted August 31, 2004 Share Posted August 31, 2004 Hi, works fantastic until now ... thanx Cape-City Link to post Share on other sites
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now