Länge von Musik: CD, WAV und MP3

Übersicht BlitzBasic FAQ und Tutorials

Neue Antwort erstellen

 

sdjh

Betreff: Länge von Musik: CD, WAV und MP3

BeitragMi, Sep 26, 2007 12:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Ahoi.

Da irgendwo letzte Woche die Frage aufkam, wie man die Länge von MP3s ausliest und irgendwie keiner darauf geantwortet hat und irgendwann vielleicht wieder jemand solche Fragen stellt weil aus irgend einem Grund keiner nach den alten Threats sucht, noch mal alles kompakt auf einem Punkt.

Wenn sich jetzt jemand fragt "Boah ej, wie hat der dat denn jemacht?". Auch darauf gibt es eine Antwort von mir: http://www.wotsit.org/

Weitere Formate werden wahrscheinlich folgen (aac, mp4, m4p, wma, mid, mod, etc)
Wenn jetzt jemand rummeckert, weil das Dateiformat Soundso Version 0.02 alpha von 1963 auf Comodore, dass nach keinen 4 Wochen wieder aus dem Umlauf genommen wurde, werde ich böse. Dann folgen keine weitere Formate mehr.
Gleiches gilt, wenn ich heute abend sehe, dann meine PN-Box explodiert, weil man ja bereits "5 Stunden gewartet" hat. Gutes Hacken braucht eben seine Zeit und der Programmierer seinen Tee.

Wenn sich jetzt einer ertappt fühlt: bitte SOFORT die "Zurück"-Naviagtion im Browser klicken!

Für alle anderen: wir legen los, hurra! Einmal strecken und räkeln, Rollos hochziehen und tief Luft holen.


Schritt 1: unsere Standartbibliothek zum Konvertieren der Zeit und sonstigem Schabernack (standart.bb)
Code: [AUSKLAPPEN]

;die absolut wichtigste Funktion um nachher das errechnete Zahlenwirrwar wieder in lesbare Ziffern zu formatieren.
;gibt Zeiten in Millisekunden in MM:SS.ms aus (gut ist das)
Function milli2min$(i)
   t=i/1000
   t2=t*1000
   m2$=Str(i-t2)
   
   If Len(m2$)=2 Then m2$="0"+m2$
   If Len(m2$)=1 Then m2$="00"+m2$
   
   mt=t/60
   t2=mt*60
   m$=Str(mt)
   s$=Str(t-t2)
   
   If Len(s$)=1Then s$="0"+s$
   
   Return m$+":"+s$+"."+m2$
End Function

;wird später für MP3s benötigt. Lest selber nach, wenn's euch interessiert
Function readchars$(f,l)
   r$=""
   For x=1To l
      r$=r$+Chr(ReadByte(f))
   Next
   Return Trim(r$)
End Function

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


diese Funktion (WICHTIG) bitte immer in den nachfolgenden Codes einfügen.

Alle warm geworden? Dann weiter! Eine leichte Fingerübung... und CD nicht vergessen!

Schritt 2: Titellänge einer Audio-CD lesen
Code: [AUSKLAPPEN]

Include "./standart.bb"  ;wie gesagt: WICHTIG
filename$=""  ;hier den Titel eingeben (sowas wie: D:\Track01.cda)

Print milli2min(getCDAlength(filename$)*1000)
Input
End

Function getCDAlength(f$)
   file=ReadFile(f$)
   If Not file Then Return
   SeekFile(file,41)  ;uns interessieren die Infos an dieser Stelle
   sec=ReadByte(file)  ;... namentlich Sekunde
   min=ReadByte(file)*60  ;... und Minute - aber bitte gleich in Sekunden formatiert
   Return min+sec  ;und ab damit
End Function


Jaja, wie gut, dass uns Herr Microsoft da Dateien suggeriert, wo eigendlich keine sind. Deshalb ausnahmsweise, sowas tu ich wirklich nicht häuft: Danke, danke, danke nach Redmont.

Ziel schon erreicht? Pah, gerade erst angezogen. Also: Ab unter die Dusche

Schritt 3: Ich liebe Wavedateien - wenn sie zerlegt sind
Code: [AUSKLAPPEN]

Include "./standart.bb"

; Eins nach dem anderen:
;1) Einen Pfad in 'filename$' angeben:
filename$="C:\..."

;2) Laenge ermitteln (unsere eigendlich Aufgabe):

Print milli2min(getwavelength(filename$)*1000)

;3) Input und End wegnehmen und ein Wunder erleben:
Input
End

;4) blah, blah, blah

Type wave
   Field size
   Field fsize
   Field format
   Field compressed
   Field channels
   Field samplessec
   Field avgbytessec
   Field blockalign
   Field bitssample
   Field length#
   Field img
   Field w,h,midpos
End Type

Graphics 640,480,32,2
SetBuffer BackBuffer()

;5) oh, interessant...
img=visualizewave(filename$,640,480)
w.wave=First wave
pxsec#=Float(640)/(w\length#*1000)


PlayMusic(filename$)
oldtime=MilliSecs()



While Not KeyDown(1)
   diff=MilliSecs()-oldtime
   Color 0,255,0
   Rect 0,0,pxsec#*diff,1024
   DrawImage img,0,0

   Color 0,0,0
   w.wave=First wave
   Text 0,0,"Hz: "+w\samplessec
   Text 0,15,"Ch: "+w\channels
   Text 0,30,"Bt: "+w\bitssample*8
   Text 0,45,"Ps: "+pxsec#
   Flip
Wend
End

Function getwavelength#(f$)
   file=ReadFile(f$)
   If Not file Then Return
   pos=0
   s$="    "
   Repeat
      s$=Right(s$,3)
      b=ReadByte(file)
      s$=s$+Chr(b)
      
      If s$="fmt "
         size=ReadInt(file)
         Print "SZ: "+size
         format=ReadShort(file)
         Print "FT: "+format
         compressed=True
         If format=1Then compressed=False
         channels=ReadShort(file)
         Print "CH: "+channels
         samplessec=ReadShort(file)
         Print "SS: "+samplesec
         avgbytessec=ReadShort(file)
         blockalign=ReadShort(file)
         bitssample=ReadShort(file)
         Print "BS: "+bitssample
         If bitssample=0Then bitssample=1
      EndIf
      If s$="data"
         fsize=FileSize(f$)
         length#=(Float(fsize)-FilePos(file))/bitssample/2/44100
         CloseFile(file)
         Return length#
      EndIf
   Until Eof(file)
   CloseFile(file)
   Return 0
End Function

Function visualizewave(f$,wh,h)
   
   w.wave=New wave
   w\w=wh
   w\h=h
   w\midpos=w\h/2
   
   w\img=CreateImage(wh,h)
   SetBuffer ImageBuffer(w\img)
   For y=0To w\midpos
      Color 255-y*128/w\midpos,64,64
      Line 0,w\midpos+y,640,w\midpos+y
      Line 0,w\midpos-y,640,w\midpos-y
   Next   
   
   Color 0,0,0
   Line 0,240,800,240
   
   file=ReadFile(f$)
   
   pos=0
   s$="    "
   Repeat
   
   s$=Right(s$,3)
   b=ReadByte(file)
   s$=s$+Chr(b)
   If s$="fmt "
      w\size=ReadInt(file)
      w\format=ReadShort(file)
      w\compressed=True
      If w\format=1Then w\compressed=False
      w\channels=ReadShort(file)
      w\samplessec=ReadShort(file)
      w\avgbytessec=ReadShort(file)
      w\blockalign=ReadShort(file)
      w\bitssample=ReadShort(file)
      If w\bitssample=0Then w\bitssample=1
   EndIf
   If s$="data"
      Color 0,0,0
      w\fsize=FileSize(f$)
      w\length#=(Float(w\fsize)-FilePos(file))/w\bitssample/2/44100
      Text 640-100,20,w\length#
      ;yfaktor=128/w\midpos
      yfaktor=5
      If w\bitssample=2Then yfaktor=32768/w\midpos
      
      maxpix=w\fsize/4
      div#=maxpix/w\w
      v=0
      oyp=-1
      oyn=-1

      Repeat
         For x=1To w\channels
            If w\bitssample=1   ;8Bit
               d=ReadByte(file)
            EndIf
            If w\bitssample=2   ;16Bit
               d=32768-ReadShort(file)
               If d<0
                  d=d+32768
               ElseIf d>0
                  d=d-32768
               EndIf
            EndIf
            Color 255,255,255
            If Float(d)/Float(yfaktor)<0
            ;   If oyn>=0Then Line v/4,w\midpos+Float(d)/Float(yfaktor)-1,(v-1)/4,oyn
               oyn=w\midpos+Float(d)/Float(yfaktor)-1
            EndIf
            If Float(d)/Float(yfaktor)>0
            ;   If oyp>=0Then Line v/4,w\midpos+Float(d)/Float(yfaktor)+1,(v-1)/4,oyp
               oyp=w\midpos+Float(d)/Float(yfaktor)+1
            EndIf
            Color 0,0,0
            Line v/4,w\midpos+Float(d)/Float(yfaktor),v/4,w\midpos
            If w\channels=1
               Line v/4,w\midpos-Float(d)/Float(yfaktor),v/4,w\midpos
            EndIf         

         Next
            v=v+1
            SeekFile file,40+div*v-(div*v Mod 4)
      Until Eof(file)
      CloseFile(file)
      SetBuffer BackBuffer()
      Return w\img
   EndIf
   If s$="cue "
      Print "Cuechunk found"
   EndIf
   If s$="plst"
      Print "Playlistchunk found"
   EndIf
   If s$="list"
      Print "Listchunk found"
   EndIf
   If s$="labl"
      Print "Labelchunk found"
   EndIf
   If s$="note"
      Print "Notechunk found"
   EndIf
   If s$="smpl"
      Print "Sampelchunk found"
   EndIf
   If s$="inst"
      Print "Instrumentchunk found"
   EndIf
   If s$="labl"
      Print "Labelchunk found"
   EndIf
   Until Eof(file)
   CloseFile(file)
End Function


Aha, aha, das kann man ja schon gebrauchen. Bitte schön, dafür ist es da.

Aber bei Napstar werden wir damit ausgelacht. Wer tauscht denn auch schon Waves? Also kopfüber in unser Lieblingsformat: der MP3

Schritt 4: Wie lang ist denn bitte meine Festplatte?
Code: [AUSKLAPPEN]

Include "./standart.bb"
filename$=""

Print milli2min(getmp3laenge(filename$))
Input()
End


Function mp3version$(i)
   Select i
      Case 1: Return "1"
      Case 2: Return "2"
      Case 3: Return "2.5"
   End Select
End Function

;Romanzahlen? Was soll das denn?
Function romannb$(i)
   Select i
      Case 1: Return "I"
      Case 2: Return "II"
      Case 3: Return "III"
      Case 4: Return "IV"
      Case 5: Return "V"
      
   End Select
End Function

Function getmp3laenge(f$,h=0)
   vbr=0
   f1=ReadFile(f$)
   x=0
   p=0
   start=0
   
   Repeat
   b=ReadByte(f1)
   If b=255
      b=ReadByte(f1)
      c=b And 224
      If c=224
         error=0
         
         d=b And 24
         d=d Shr 3
         If d=0Then version=3
         If d=1Then error=1
         If d=2Then version=2
         If d=3Then version=1
         
         
         d=b And 6
         d=d Shr 1
         If d=0Then error=1
         If d=1Then layer=3
         If d=2Then layer=2
         If d=3Then layer=1
   
   
         b=ReadByte(f1)
         
         d=b Shr 4
         bitrate=0
         If version=1
            If layer=3
               If d=0 Then bitrate=-1
               If d=1 Then bitrate=32
               If d=2 Then bitrate=40
               If d=3 Then bitrate=48
               If d=4 Then bitrate=56
               If d=5 Then bitrate=64
               If d=6 Then bitrate=80
               If d=7 Then bitrate=96
               If d=8 Then bitrate=112
               If d=9 Then bitrate=128
               If d=10 Then bitrate=160
               If d=11 Then bitrate=192
               If d=12 Then bitrate=224
               If d=13 Then bitrate=256
               If d=14 Then bitrate=320
               If d=15 Then bitrate=-1
            EndIf
         EndIf
         
         d=b And 12
         d=d Shr 2
         If version=1
            If d=0Then frequenz=44100
            If d=1Then frequenz=48000
            If d=2Then frequenz=32000
         EndIf
         
         d=b And 2
         d=d Shr 1
         padding=d
         
         If bitrate<=0 Or error=1
            x=x-1
         Else
            If x=0 Then start=FilePos(f1)-3
            totbit=totbit+bitrate
            SeekFile(f1,FilePos(f1)-8+(bitrate*1000*144/frequenz+padding))
         EndIf
         
         x=x+1
      EndIf
   EndIf
   
   Until Eof(f1)
   CloseFile(f1)
   vbr=totbit/x
   
   Return (FileSize(f$)-start)*8/vbr
End Function

Function getid3tags$(f$)
   f1=ReadFile(f$)
   If Not f1 Then Return

   start=0
   
   Repeat
   b=ReadByte(f1)
   If b=255
      b=ReadByte(f1)
      c=b And 224
      If c=224
         error=0
         
         d=b And 24
         d=d Shr 3
         If d=0Then version=3
         If d=1Then error=1
         If d=2Then version=2
         If d=3Then version=1
         
         
         d=b And 6
         d=d Shr 1
         If d=0Then error=1
         If d=1Then layer=3
         If d=2Then layer=2
         If d=3Then layer=1
   
   
         b=ReadByte(f1)
         
         d=b Shr 4
         bitrate=0
         If version=1
            If layer=3
               If d=0 Then bitrate=-1
               If d=1 Then bitrate=32
               If d=2 Then bitrate=40
               If d=3 Then bitrate=48
               If d=4 Then bitrate=56
               If d=5 Then bitrate=64
               If d=6 Then bitrate=80
               If d=7 Then bitrate=96
               If d=8 Then bitrate=112
               If d=9 Then bitrate=128
               If d=10 Then bitrate=160
               If d=11 Then bitrate=192
               If d=12 Then bitrate=224
               If d=13 Then bitrate=256
               If d=14 Then bitrate=320
               If d=15 Then bitrate=-1
            EndIf
         EndIf
         
         d=b And 12
         d=d Shr 2
         If version=1
            If d=0Then frequenz=44100
            If d=1Then frequenz=48000
            If d=2Then frequenz=32000
         EndIf
         
         d=b And 2
         d=d Shr 1
         padding=d
         
         If bitrate<=0 Or error=1
            x=x-1
         Else
            If x=0 Then start=FilePos(f1)-3
            totbit=totbit+bitrate
            SeekFile(f1,FilePos(f1)-8+(bitrate*1000*144/frequenz+padding))
         EndIf
         
         x=x+1
      EndIf
   EndIf
   
   Until Eof(f1)
   
   ;  Anmerkung:
   ;Die Variable 'start' wird wie in 'getmp3laenge' ermittelt
   ;Wer also die Infos eh in einem Type speichert, kann sich deie Function bishierhin sparen.

   For p=1To start            
      b=ReadByte(f1)
      If b=73
         If ReadByte(f1)=68 And ReadByte(f1)=51
            ReadInt(f1)
            ReadShort(f1)
            ReadInt(f1)
            ReadInt(f1)
            For x=1To 11
               l=ReadInt(f1)
               t$=readchars(f1,l-1)
               Select x
                  Case 1:interpret$=t$
                  Case 2:title$=t$
                  Case 3:album$=t$
                  Case 4:track$=t$
                  Case 5:year$=t$
                  Case 6:genre$=t$
               End Select
               ReadByte(f1)
               ReadByte(f1)
               ReadByte(f1)
               ReadByte(f1)
               ReadByte(f1)
               ReadByte(f1)
               ReadByte(f1)
            Next
            Return
         EndIf
      EndIf
   Next
   SeekFile(f1,FileSize(f$)-128)
   If ReadByte(f1)=84
      If ReadByte(f1)=65 And ReadByte(f1)=71
         title$=readchars(f1,30)
         interpret$=readchars(f1,30)
         album$=readchars(f1,30)
         year$=readchars(f1,4)
         comment$=readchars(f1,30)
         genre$=getgenre(ReadByte(f1))
         ;   Exit
      EndIf
   EndIf
End Function


Alles Tutti. Das wäre nun auch geklärt.

Zum letzten Quelltext noch: das Auslesen der ID3-Tags sollte man natürlich in Types machen (siehe auch https://www.blitzforum.de/foru...hp?t=25321). Dann kann man sich nämlich auch die Infos schön gruppieren und leicht ausgeben. Ich habe es aber weggenommen, weil es ja nicht das eigendliche Anliegen des Tutorials ist.

Schritt 5: Was kann ich damit alles machen?
Macht den Media Player nieder, zerlegt iTunes, übertrumpft WinAMP. Es ist möglich. Erfahrung: selbstgemacht. Ich habe eine Jukebox (für die ich diese Funktionen auch geschrieben habe), die ich gerne auf Partys mitnehme. Mit einer 80GB (bei mir leider nur 30 davon belegt) externen Festplatte (alles MP3s in VBR à 160KBits) und einem kleinen Studium von BlitzBass, lässt sich schon so manche Party schmeissen. Also nur Mut.

Wer eigene Hacks geschrieben hat, kann sie gerne hier posten. Von mir kommt sicherlich auch noch etwas in Wochen und Monaten, so wie sich es eben gerade ergibt.

Viel Spaß, viel Erfolg und haut rein, Mädels und Jungs!

Neue Antwort erstellen


Übersicht BlitzBasic FAQ und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group