Link to home
Start Free TrialLog in
Avatar of BETTY
BETTYFlag for Spain

asked on

Read info from MP3 file

Hi from Barcelona, Spain!

As "Music" section is still under study by EE responsibles, as VB is the language in which I'm developing my program, I've decided this is the correct place to put this question.

The matter is: is there any simple way to read the song time of playing from a MP3 file? Simple means open the file, perhaps look for a given tag ID, read it and it's done. I pray for not having to use C; anyway, VB can open and read from files, too.

If C programming is needed, I would use from VB via a DLL call. I have a freeware 32 bit C compiler, and I think it's not difficult to create a DLL. After, using my VB manual, I can implement the call (I suppose, as I never have done so). The problem then would be the code itself, as I'm a completely newbie to C.

By now my main problem is I don't know if there is any tag or stamp in the file structure to store the playing time, or if WinAmp makes a calculation from several parameters.

I wouldn't want urls as answers, because I've already visited some of them (www.id3.org, etc) and I haven't found nothing; furthermore, all is C-related. The only way to accept an url as answer is to find there the solution to my question (or nearly), not MP3 technical (very technical) stuff.
Avatar of Rheingold
Rheingold

Hi

you should try www.wotsit.org

This site contains descriptions of all possible file formats including MP3 - I downloaded information about it a while ago.

Regards
An MP3 audio file is separated in smaller parts called frames. Each frame is independent. It has its own header and audio informations. There is no file header. Therefore, you can cut any part of a MP3 file and play it correctly.

The BitRate for each frame can be found in the Frame Header. The Frame Header is 4 bytes long and is located at the beginning of each frame. The Data inside of it is BIT aligned, not byte aligned, as such the 4 bytes represent 32 bits of information. Low Order bits 12-15 of the Frame header, specify the BitRate Code, that then can be looked up in a table, to ascertain what the BitRate value is. Generally speaking, most MP3s are homogenous, which means that if you get the BitRate for the first Frame Header, then the BitRate will be the same for the rest of them. In this case, you can then use the following formula to derive a very close approximation of song length in seconds:

LengthInSeconds = (8 * fileSize) / (Bitrate * 1000)

Keep in mind there are Variable BitRate MP3s out there. In those cases, to get a playing time, you have to calculate it frame by frame. (If you notice the slight delay in loading MP3s with Winamp, this is because it is preprocessing the file to calculate play time).

The MP3 Frame Header, contains 13 Bitcoded fields. As they are all tabular in nature and EE comment entry does not support this (posting tables is a mess), I suggest you go to the Web and obtain a properly formatted Frame Header layout. Here is a good link to get you started:

http://home.swipnet.se/grd/mp3info/

Although it is written in C++, the CMP3INFO class offered there is chock full of information. Additionally, you will find other hyperlinks to peruse on this subject.

Calculates the duration in seconds of a .mp3 file. Also displays the associated layer, bitrate, sample rate of the file

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?lngWId=1&txtCodeId=4185



 
This code shows you how to read the ID3-Tag from MP3-Files

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?lngWId=1&txtCodeId=6326
 


ASKER CERTIFIED SOLUTION
Avatar of sharmon
sharmon

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Betty,
Im working on similar lines and i have developed a VB (BAS) module that will open up the mp3 file and tell you the exact playback length!
Yes, you're quite right VB can handle opening and reading the mp3 tag all by itself without VC having to cut in!
I'll email it to you.
All the best!

-headrush
http://kashalkar.tripod.com


Avatar of BETTY

ASKER

Rheingold: When I put this question I already had visited the site, and I found code in C++ following some links from there. Thanks.

wsh2: If mp3 files were "uniform" in bitrate, your formula would be genial: simple and fast. Unfortunately, as you say, some (or not so some) files are not bitrate-regular. And I'm so newbie in C++ I would have to spend (not waste if I learn something) lots of time navigating the code. Thanks for the link.

AzraSound and sharmon: I'm going to check your links, and to evaluate which one is better. Specially it's perfect to have a code directly from his author, as if a doubt appears, I expect to ask to perfect person. I'll tell you which one I choose and why.

headrush22m: I'm going to check your link too. But although it's fantastic to get the code directly in my e-mail, think people sometimes research the PAQ for an info through the title, and they will not be very happy if they spend their points in (correctly) answers that are not present. If you put an answer, think in it: if it's not suitable to put it here (length problems), you sould try to give an alternate solution to those who "pay" points after me for the info.
A snippet...

' These may not all be used.. I've just cut it from a program and all they really do is store it for global access.
Public HeaderData As String * 4
Public Artist As String, Song As String, Album As String, Notes As String, Year As String
Public Version As Single, Layer As Byte, Bitrate As Integer, SampleRate As Long, FrameLength As Integer, Stereo As Byte
Public Matrix, StereoMode

' Reads various MP3 details from the first packet...
Public Sub ReadHeader(Filename As String)
  Dim Byte1 As Byte, Byte2 As Byte, Byte3 As Byte, Byte4 As Byte, BitRateArray, SampleRateArray
  Dim hFrameSync As Integer, hVersion As Byte, hLayer As Byte, hProtect As Byte, hBitRate As Byte, hSampleRate As Byte
  Dim hPadding As Byte, hPrivate As Byte, hChannel As Byte, hModeExt As Byte, hCopyright As Byte, hOriginal As Byte, hEmphasis As Byte
  Open Filename For Binary Access Read As #3
  Get #3, , HeaderData
  Close #3
  Byte1 = Asc(Mid$(HeaderData, 1, 1))
  Byte2 = Asc(Mid$(HeaderData, 2, 1))
  Byte3 = Asc(Mid$(HeaderData, 3, 1))
  Byte4 = Asc(Mid$(HeaderData, 4, 1))
  hFrameSync = Byte1 * &H8 + (Byte2 And &HE0) / &H20
  hVersion = (Byte2 And &H18) / &H8     ' 0=v2.5, 2=v2, 3=v1
  Version = 4 - hVersion
  If hVersion = 0 Then Version = 2.5
  hLayer = (Byte2 And &H6) / &H2        ' 1=l3, 2=l2, 3=l1
  Layer = 4 - hLayer
  hProtect = Byte2 And &H1              ' 0=CRC, 1=No
  hBitRate = (Byte3 And &HF0) / &H10    ' ---
  Select Case Int(Version) * 10 + Layer
    Case 11
      BitRateArray = Array(0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 999)
    Case 12
      BitRateArray = Array(0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 999)
    Case 13
      BitRateArray = Array(0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 999)
    Case 21
      BitRateArray = Array(0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 999)
    Case 22, 23
      BitRateArray = Array(0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 999)
  End Select
  Bitrate = BitRateArray(hBitRate)
  hSampleRate = (Byte3 And &HC) / &H4   ' ---
  Select Case Version
    Case 1
      SampleRateArray = Array(44100, 48000, 32000)
    Case 2
      SampleRateArray = Array(22050, 24000, 16000)
    Case 2.5
      SampleRateArray = Array(11025, 12000, 8000)
  End Select
  SampleRate = SampleRateArray(hSampleRate)
  hPadding = (Byte3 And &H2) / &H2      ' 0=No, 1=Yes
  hPrivate = Byte3 And &H1              ' ???
  hChannel = (Byte4 And &HC0) / &H40    ' 0=Stereo, 1=JSt, 2=Dual, 3=Mono
  Stereo = hChannel
  hModeExt = (Byte4 And &H30) / &H10    ' (JSt only) ---
  hCopyright = (Byte4 And &H8) / &H8    ' 0=No, 1=Yes
  hOriginal = (Byte4 And &H4) / &H4     ' 0=Copy, 1=Original
  hEmphasis = Byte4 And &H3             ' 0=None, 1=50/15ms, 3=CCIT J.17
  If Layer = 1 Then FrameLength = Fix((12000 * Bitrate / SampleRate + hPadding) * 4) Else FrameLength = Fix(144000 * Bitrate / SampleRate + hPadding)
End Sub


' Inits a couple of arrays
Public Sub InitMP3s()
  Matrix = Array("Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip -Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&b", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro -Techno", "Ambient", "Trip -Hop", "Vocal", "Jazz Funk", "Fusion", "Trance", "Classical", _
    "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno -Industrial", "Electronic", "Pop -Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", _
    "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo -Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", _
    "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A Capela", "Euro-House", "Dance Hall")
  StereoMode = Array("Stereo", "Joint Stereo", "Dual Channel", "Mono")
End Sub
Avatar of BETTY

ASKER

headrush22m: Your site only leads to your e-mail, so I'm not capable to check anything. This is the cause for me to reject your answer. Anyway, I'm among people here in EE that think no one would have to answer anymore, as the new layout in EE allows to accept a comment as answer. This is due to the fact that some experts don't check locked questions, and this leads to a loss of range of answers.

Note: yor SoundGarden software layout looks great!
Thanks Betty! yeah i agree with you on the EE front!
Avatar of BETTY

ASKER

Cloud 1: This code is similar to the others, perhaps a little more easy as it does not involve lots of Kb or classes. Thanks.

And the winner is... sharmon!!!! Yes, thus AzraSound's ones are near, I think yours is the most complete. Below are the changes needed to work under VB5, VB6 works as is in the link.

prjID3Class.vbp:

Delete the line:
Retained=0

cIDV3.cls:

Between BEGIN y END, in General:Declarations, it's not accepted:

  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject


In Function GenreText

Change:
Dim aGenre() As Variant
with:
Dim aGenre
Well thanks!  I wrote it a while back, while it's mostly complete, I haven't really looked through it in a while, I am sure there are things that need tidied up but I am glad you got it all working.  Overall it's pretty complete and does most everything.  Now you got me wanting to go back and work on it more:)  Take care, thanks.

Shannon Harmon