Code archives/Audio/Length of mp3

This code has been declared by its author to be Public Domain code.

Download source code

Length of mp3 by Sonari Eclipsi Onimari2006
Okay, this has been a butt for anyone trying to devolp a media player that shows time. This works perfect on any mp3 file. Thanks to Floppy, and Bram32 on www.codersworkshop.com and the Mp3 tags archive here in the codearcs, this function is now a reality!!!
;def

Global looser

Dim mp3_bri$(16)
mp3_bri$(0) = "free"
mp3_bri$(1) = "32"
mp3_bri$(2) = "40"
mp3_bri$(3) = "48"
mp3_bri$(4) = "56"
mp3_bri$(5) = "64"
mp3_bri$(6) = "80"
mp3_bri$(7) = "96"
mp3_bri$(8) = "112"
mp3_bri$(9) = "128"
mp3_bri$(10) = "160"
mp3_bri$(11) = "192"
mp3_bri$(12) = "224"
mp3_bri$(13) = "256"
mp3_bri$(14) = "320"
mp3_bri$(15) = "bad"

Dim mp3_sri$(4)
mp3_sri(0) = "44100"
mp3_sri(1) = "48000"
mp3_sri(2) = "32000"
mp3_sri(3) = "reserved"

Dim mp3_chi$(4)
mp3_chi(0) = "Stereo"
mp3_chi(1) = "Joint Stereo"
mp3_chi(2) = "Dual"
mp3_chi(3) = "Mono"

Dim mp3_emi$(4)
mp3_emi(0) = "None"
mp3_emi(1) = "50/15"
mp3_emi(2) = "reserved"
mp3_emi(3) = "CCIT J.17"

Dim mp3_mvi$(4)
mp3_mvi$(0) = "MPEG Version 2.5 (not an official standard)"
mp3_mvi$(1) = "reserved"
mp3_mvi$(2) = "MPEG Version 2"
mp3_mvi$(3) = "MPEG Version 1"

Dim mp3_mli$(4)
mp3_mli$(0) = "reserved"
mp3_mli$(1) = "Layer III"
mp3_mli$(2) = "Layer II"
mp3_mli$(3) = "Layer I"

Dim mp3_genre$(128)
mp3_genre( 0)= "Blues"
mp3_genre( 1)= "Classic Rock"
mp3_genre( 2)= "Country"
mp3_genre( 3)= "Dance"
mp3_genre( 4)= "Disco"
mp3_genre( 5)= "Funk"
mp3_genre( 6)= "Grunge"
mp3_genre( 7)= "Hip-Hop"
mp3_genre( 8)= "Jazz"
mp3_genre( 9)= "Metal"
mp3_genre(10)= "New Age"
mp3_genre(11)= "Oldies"
mp3_genre(12)= "Other"
mp3_genre(13)= "Pop"
mp3_genre(14)= "R&B"
mp3_genre(15)= "Rap"
mp3_genre(16)= "Reggae"
mp3_genre(17)= "Rock"
mp3_genre(18)= "Techno"
mp3_genre(19)= "Industrial"
mp3_genre(20)= "Alternative"
mp3_genre(21)= "Ska"
mp3_genre(22)= "Death Metal"
mp3_genre(23)= "Pranks"
mp3_genre(24)= "Soundtrack"
mp3_genre(25)= "Euro-Techno"
mp3_genre(26)= "Ambient"
mp3_genre(27)= "Trip-Hop"
mp3_genre(28)= "Vocal"
mp3_genre(29)= "Jazz+Funk"
mp3_genre(30)= "Fusion"
mp3_genre(31)= "Trance"
mp3_genre(32)= "Classical"
mp3_genre(33)= "Instrumental"
mp3_genre(34)= "Acid"
mp3_genre(35)= "House"
mp3_genre(36)= "Game"
mp3_genre(37)= "Sound Clip"
mp3_genre(38)= "Gospel"
mp3_genre(39)= "Noise"
mp3_genre(40)= "AlternRock"
mp3_genre(41)= "Bass"
mp3_genre(42)= "Soul"
mp3_genre(43)= "Punk"
mp3_genre(44)= "Space"
mp3_genre(45)= "Meditative"
mp3_genre(46)= "Instrumental Pop"
mp3_genre(47)= "Instrumental Rock"
mp3_genre(48)= "Ethnic"
mp3_genre(49)= "Gothic"
mp3_genre(50)= "Darkwave"
mp3_genre(51)= "Techno-Industrial"
mp3_genre(52)= "Electronic"
mp3_genre(53)= "Pop-Folk"
mp3_genre(54)= "Eurodance"
mp3_genre(55)= "Dream"
mp3_genre(56)= "Southern Rock"
mp3_genre(57)= "Comedy"
mp3_genre(58)= "Cult"
mp3_genre(59)= "Gangsta"
mp3_genre(60)= "Top 40"
mp3_genre(61)= "Christian Rap"
mp3_genre(62)= "Pop/Funk"
mp3_genre(63)= "Jungle"
mp3_genre(64)= "Native American"
mp3_genre(65)= "Cabaret"
mp3_genre(66)= "New Wave"
mp3_genre(67)= "Psychadelic"
mp3_genre(68)= "Rave"
mp3_genre(69)= "Showtunes"
mp3_genre(70)= "Trailer"
mp3_genre(71)= "Lo-Fi"
mp3_genre(72)= "Tribal"
mp3_genre(73)= "Acid Punk"
mp3_genre(74)= "Acid Jazz"
mp3_genre(75)= "Polka"
mp3_genre(76)= "Retro"
mp3_genre(77)= "Musical"
mp3_genre(78)= "Rock & Roll"
mp3_genre(79)= "Hard Rock"

Global mp3_FileSize

Type id3v1
	Field key$
	Field Dat$
End Type

Type id3v2
	Field key$
	Field flags
	Field Dat$
	Field size
	Field start
End Type

Type AudioFrame
	Field mpegVersion$
	Field mpegLayer$
	Field CRCprotection
	Field Bitrate
	Field samplerate
	Field padding
	Field PrivateBit
	Field Channel$
	Field ModeExtension_intensity
	Field ModeExtension_MS
	Field copyright
	Field Original
	Field Emphasis$
	
	Field num
	Field framelen
	Field framestart
End Type


Global filename$ = RequestFile$("","mp3")

; "Anlysing: "+filename
; "----"
readTagv1(filename)
file = mp3_openFile(filename)
analyseMP3(file)
file = mp3_closeFile(filename)

; "----"
mp3_printAudioFrame(Last AudioFrame)

; "----"
For t1.id3v1 = Each id3v1
	mp3_printID3v1(t1)
Next

; "----"
For t2.id3v2 = Each id3v2
	mp3_printID3v2(t2)
Next


Function mp3_printID3v1(t.id3v1)
	If t\key = "Genre"
		; t\key+": "+mp3_genre(Int(t\dat))
	Else
		; t\key+": "+t\dat
	EndIf
End Function

Function mp3_printID3v2(t.id3v2)
	; t\key+": "+t\dat
End Function

Function mp3_openFile(filename$)
	If Not FileType(filename) = 1 Then Return False

	file = ReadFile(filename)
	mp3_FileSize = FileSize(filename)
	Return file
End Function

Function mp3_closeFile(filename$)
	If Not FileType(filename) = 1 Then Return False

	file = ReadFile(filename)
	Return file
End Function

Function analyseMP3(file)
	SeekFile(file,0)
	readTagv2(file)

	While Not Eof(file)
		a.audioframe = mp3_readAudioFrame.AudioFrame(file,count)
		If a = Null
			; "interupt by "+FilePos(file)
			Exit
		Else
			lastvalid.Audioframe = a
		EndIf
		count = count + 1
	Wend
	
	; "Analysed "+count+" Audioframes"
End Function

Function mp3_readAudioFrame.AudioFrame(file,count)
	
	pos = FilePos(file)
	
	b1 = ReadByte(file)
	b2 = ReadByte(file)
	b3 = ReadByte(file)
	b4 = ReadByte(file)
	
	If b1 <> $ff And (b2 And 224) <> 224
		; "Frame syncronizer not found"
		SeekFile(file,FilePos(file)-4)
		Return Null
	EndIf
	
	a.AudioFrame = New AudioFrame
	a\framestart = pos
	a\num = count
	
	MPEGversionID = (b2 And 24) Shr 3
	a\mpegVersion = mp3_mvi(MPEGversionID)

	MPEGlayerID = (b2 And 6) Shr 1
	a\mpegLayer = mp3_mli(MPEGlayerID)
	
	a\CRCprotection = (b2 And $1)
	
	BitrateID = (b3 And $f0) Shr 4
	a\BitRate = Int(mp3_bri(BitrateID)) * 1000
	
	SamplerateID = (b3 And $c) Shr 2
	a\SampleRate = Int(mp3_sri(SamplerateID))
	
	a\Padding = (b3 And $2) Shr 1

	a\privateBit = (b3 And 1)

	channelID = (b4 And $C0) Shr 6
	a\channel = mp3_chi(channelID)

	a\ModeExtension_intensity = (b4 And $10) Shr 5
	a\ModeExtension_MS = (b4 And $20) Shr 6
	
	a\copyright = (b4 And $8)

	a\original = (b4 And $4)
	
	emphasisID = (b4 And $3)
	a\emphasis = mp3_emi(emphasisID)
	
	a\FrameLen = Floor((144.0 * Float(a\BitRate) / Float(a\SampleRate) ) + a\Padding)
	
	SeekFile(file,FilePos(file)+a\framelen-4)
	Return a
End Function

Function mp3_printAudioFrame(a.audioframe)
	; "Audioframe "+a\num
	; "MPEG Version: " + a\mpegVersion
	; "MPEG Layer: " + a\mpegLayer
	If a\CRCprotection
		; "NOT Protected by CRC"
	Else
		; "Protected by CRC"
	EndIf
	
	looser= + a\BitRate + " bps"	
	; "Samplig rate frequency: " + a\SampleRate+" hz"
	
	If a\Padding
		; "Frame is padded"
	Else
		; "Frame is not padded"
	EndIf

	If a\privateBit 
		; "private bit is set"
	Else
		; "private bit is not set"
	EndIf

	; "Channel: " + a\channel+" mode"

	; "Mode Extension: "
	If a\ModeExtension_intensity
		; "Intensity Stereo on"
	Else
		; "Intensity Stereo off"
	EndIf
	If a\ModeExtension_MS
		; "MS Stereo on"
	Else
		; "MS Stereo off"
	EndIf

	If a\copyright
		; "Audio is copyrighted"
	Else
		; "Audio is not copyrighted"
	EndIf

	If a\original
		; "Original media"
	Else
		; "Copy of original media"
	EndIf
	
	; "Emphasis: " + a\emphasis
	
	; "Framelength: "+a\FrameLen
End Function

Function readTagv1(filename$)
	If Not FileType(filename) = 1 Then Return False

	file = ReadFile(filename)
	SeekFile(file,FileSize(filename)-128)
	
	For i=0 To 2
		txt$ = txt$ + Chr(ReadByte(file))
	Next
	
	If txt = "TAG"
		; "ID3 v1 Tag present"
				
		txt = ""
		For i=0 To 29
			songname$ = songname$ + Chr(ReadByte(file))
		Next
		t.id3v1 = New id3v1
		t\key = "Songname"
		t\dat = Trim(songname)
		
		For i=0 To 29
			Artist$ = Artist$ + Chr(ReadByte(file))
		Next
		t.id3v1 = New id3v1
		t\key = "Artist"
		t\dat = Trim(artist)

		For i=0 To 29
			Album$ = Album$ + Chr(ReadByte(file))
		Next
		t.id3v1 = New id3v1
		t\key = "Album"
		t\dat = Trim(album)

		txt = ""
		For i=0 To 3
			year$ = year$ + Chr(ReadByte(file))
		Next
		t.id3v1 = New id3v1
		t\key = "Year"
		t\dat = Trim(year)

		For i=0 To 29
			Comment$ = Comment$ + Chr(ReadByte(file))
		Next
		t.id3v1 = New id3v1
		t\key = "Comment"
		t\dat = Trim(comment)

		For i=0 To 0
			genre = ReadByte(file)
		Next
		t.id3v1 = New id3v1
		t\key = "Genre"
		t\dat = Trim(genre)
		
	EndIf
End Function

Function readTagv2(file)		
	For i=0 To 2
		txt$ = txt$ + Chr(ReadByte(file))
	Next
	
	If txt = "ID3"
		
		;read TAG version
		hiVersion = ReadByte(file)
		lowVersion = ReadByte(file)
		; "ID3 v2 Tag present (version: "+hiVersion+"/"+lowVersion+")"
		
		;read flags
		flags = ReadByte(file)

		
		;read size of tag
		b = ReadInt(file)
		
		size = syncsafeInt(b)

		While tagpos < size
			;read frame TAG
			txt = ""

			b1 = ReadByte(file)
			tagpos = tagpos + 1
			If b1
				t.id3v2 = New id3v2
				t\start = FilePos(file)-1
				
				b2 = ReadByte(file)
				b3 = ReadByte(file)
				b4 = ReadByte(file)
				tagpos = tagpos + 3

				txt$ = Chr(b1) + Chr(b2) + Chr(b3) + Chr(b4)
				t\key = txt
				
				framesize = syncsafeInt(ReadInt(file))
				tagpos = tagpos + 4
				t\size = framesize
				
				flags = ReadShort(file)
				tagpos = tagpos + 2
				t\flags = flags
								
				txt$ = ""
				For i= 1 To framesize
					txt = txt + Chr(ReadByte(file))
					tagpos = tagpos + 1
				Next
				t\dat$ = Trim(txt)
			EndIf
			;WaitKey
		Wend
	Else
		SeekFile(file,0)
	EndIf
End Function

Function syncsafeInt(b)
	
	b1 = b And $ff000000
	b2 = b And $00ff0000
	b3 = b And $0000ff00
	b4 = b And $000000ff
	
	b1 = (b And $ff000000) Shr 24
	b2 = (b And $00ff0000) Shr 8
	b3 = (b And $0000ff00) Shr 8 
	b4 = (b And $000000ff) Shr 24

	b4 = b4 Shr 3
	b3 = b3 Shr 2
	b2 = b2 Shr 1
	
	size = b4 Or b3 Or b2 Or b1
	Return size
End Function




y=looser/1000
Print "Bitrate: "+y



z#=FileSize(filename$)/1024.0
bits  = z*1024*8
time# = (bits/(y*1000)) ;this is in seconds

;calculate min/secs
min% = Floor(time/60)
sec% = time Mod 60

Print min + " minutes " + sec + " seconds"

WaitKey()

End

Comments

Sonari Eclipsi Onimari2006
I had to take out all the other stuff I didn't need...


_PJ_2009
Need to change:

Global filename$ = RequestFile$("","mp3")


For this to run without extraneous files.

Substituting in a valid path&filename, however works fine.


_PJ_2010
Calculations with the floating poitns are somewhat inaccurate.
Here I have devised a method to read the duration (And much more) from the ID V2 TAGs.

http://www.blitzbasic.com/logs/userlog.php?log=1719&user=2370


Code Archives Forum