[OK] Lecture de Tags MP3 V2.3

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Marc56
Messages : 2197
Inscription : sam. 08/févr./2014 15:19

[OK] Lecture de Tags MP3 V2.3

Message par Marc56 »

Bon, bon, bon
Ca fait un bout de tmps que je cherche à ajouter à mon desk, les titres pour les fichier MP3
Pour les ID V1, c'est facile, ce sont les 128 derniers octets (fileseek de la taille du fichier - 128 et hop)
C'est fait depuis longtemps.

Pour les ID V2, c'est l'horreur...
J'ai étudié tout ce que j'ai pu trouver sur le net
- La description officielle: http://id3.org/id3v2.3.0 (imbuvable pour mon cerveau à 2 neurones)
- Une page très intéressante: http://mgc99.free.fr/InfoMP3.html

Les exemples sur les forums PB (des tas!) mais surtout deux
- Celui de ts-soft (le seul qui marche bien en PB 5.60)
http://www.purebasic.fr/english/viewtop ... 12&t=55920
- Celui de Zorro/Spock , qui ne marche pas en PB 5.60 mais grâce à qui j'ai pu apprendre plein de trucs :wink:
http://www.purebasic.fr/french/viewtopi ... 0&start=31
(sauf que je n'ai rien pigé au little_indian :| donc je me suis débrouillé autrement)

Grace à vos explications sur mon topic "memoryseek" j'ai pu me lancer et après plusieurs jours, ça marche :!:
Vous allez me dire, il y a des libs bien mieux, mais cette roue (carrée) là c'est moi qui l'ai faite et elle roule (vite) :P

Code : Tout sélectionner

; Read MP3 Tags V2
; Minimum cherché: Lire le titre (Tag: TIT2)
; Marc56 - 22/03/2017
; Documentation:
; Format: http://id3.org/id3v2.3.0
; Explication Fr trouvée sur: http://mgc99.free.fr/InfoMP3.html
; Merci pour leurs exemples et explications à:
; Ts-soft: http://www.purebasic.fr/english/viewtopic.php?f=12&t=55920 
; Zorro: http://www.purebasic.fr/french/viewtopic.php?f=1&t=11240&start=31

MusicFile$ = OpenFileRequester("Lecture Tags MP3 V2.3", 
                               GetUserDirectory(#PB_Directory_Musics), 
                               "Fichier MP3|*.mp3", 1)

If MusicFile$ = ""
     End
EndIf

Declare.s Read_Value()

; Fichier cassé ou absent ? suivant.
If Not ReadFile(0, MusicFile$)   
     Debug "Erreur: " + MusicFile$
     End
EndIf

; Tag ID V2 (ID3 sur les 3 premiers octets)
If Not ReadString(0, #PB_UTF8, 3) = "ID3"
     Debug "Ce fichier n'est pas un mp3 V2"
     CloseFile(0)
     End
EndIf

Debug "Fichier: " + MusicFile$
; Lecture de l'entête (10 octets)
*Head = AllocateMemory(10)
ReadData(0, *Head, 10)
ID_Sub = PeekA(*Head) ; Identification version (position 4)
Debug "Tag ID v2." + ID_Sub
If ID_Sub <> 3 And ID_Sub <> 4
     End
EndIf

; On avance de 3 et on récupère la taille complète des tags
*Head + 3
x3 = PeekB(*Head) : *Head + 1
x2 = PeekB(*Head) : *Head + 1
x1 = PeekB(*Head) : *Head + 1
x0 = PeekB(*Head) : *Head + 1
Header_Size = x3 * Pow(128,3) + x2 * Pow(128,2) + x1 * Pow(128,1) + x0 * Pow(128,0)
Debug "Taille entête: " + Header_Size + " octets"      
; On libère le buffer d'entête
*Head - 7 : FreeMemory(*Head)

; Lecture de la zone de tags
Global *Buf = AllocateMemory(Header_Size)
FileSeek(0, 0) ; Revenir au début du fichier
ReadData(0, *Buf, Header_Size)
CloseFile(0) 

; Lecture de toute la zone (décalage de 1 lecture de 4)
For i = 0 To Header_Size
     IDT$ = PeekS(*Buf, 4, #PB_UTF8) 
     Select IDT$
          Case "TPE1"
               Debug "TPE1 - Artiste    : " + Read_Value()
          Case "TALB"
               Debug "TALB - CD         : " + Read_Value()                          
          Case "TIT2"
               Debug "TIT2 - Titre      : " + Read_Value()                                
          Case "TYER"
               Debug "TYER - Année      : " + Read_Value()
          Case "TDRC"
               Debug "TDRC - Année      : " + Read_Value()                    
          Case "TRCK"
               Debug "TRCK - Piste      : " + Read_Value()
          Case "TLEN" 
               Debug "TLEN - Durée      : " + Read_Value() + " (?)"                   
          Case "TPUB" 
               Debug "TPUB - ???        : " + Read_Value()                   
     EndSelect         
     ; Avance de 1
     *Buf + 1
Next

Procedure.s Read_Value()
     ; Récupérer la taille du champs
     *Buf + 4
     x3 = PeekB(*Buf) : *Buf + 1
     x2 = PeekB(*Buf) : *Buf + 1
     x1 = PeekB(*Buf) : *Buf + 1
     x0 = PeekB(*Buf) : *Buf + 1
     Frame_Size = x3 * Pow(128,3) + x2 * Pow(128,2) + x1 * Pow(128,1) + x0 * Pow(128,0)
     ; Déplacer le flag de 2 octets (?)
     *Buf + 3
     ProcedureReturn PeekS(*Buf, Frame_Size-1, #PB_UTF8)
EndProcedure
Voilà. Ce code est affreux, car c'est le fruit de tout un tas d'essais, mais ça fonctionne.
Il ne me reste plus qu'à le mettre au propre et à l'intégrer au desk.
Si vous avez des suggestions ou critiques, je suis preneur

8)
Dernière modification par Marc56 le mer. 22/mars/2017 16:35, modifié 1 fois.
Avatar de l’utilisateur
falsam
Messages : 7323
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Lecteur de Tags MP3 V2.3

Message par falsam »

Un petit tour pas là en complément : https://github.com/pbcodex/MP3-Collection
Pour Pb 4.43 -> 5.60
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7323
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Lecteur de Tags MP3 V2.3

Message par falsam »

J'ai testé ton code. Il y a des souci unicodes sur presque tous les mp3 que j'ai testé.

Exemple
Tag ID v2.3
Taille entête: 1197 octets
TPE1 - Artiste : ��w
TALB - CD : ��U
TIT2 - Titre : ��R
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Marc56
Messages : 2197
Inscription : sam. 08/févr./2014 15:19

Re: Lecteur de Tags MP3 V2.3

Message par Marc56 »

Bizarre, tous ceux que j'ai testé sont passés :(
J'ai compilé en PB 5.60 x64
Tu as un liens vers un fichier à problème pour que je le mette dans mon lot de tests ?

PS. Merci pour les compléments. :wink:

Edit: Pas la peine, j'en ai trouvé (effectivement, les très anciens ne passent pas)
Je replonge dans mon code, j'ai oublié de traiter selon UTF-8 ou Unicode 8)
Avatar de l’utilisateur
falsam
Messages : 7323
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Lecteur de Tags MP3 V2.3

Message par falsam »

Ce titre contient les frames id3v1 et id3v2. Il ne fonctionne pas du tout avec ton code.
http://falsam.com/Download/sound/Earth% ... Groove.mp3

PS : Je viens de voir aussi une erreur sur un des codes github dont je t'ai passé le lien. Les commentaires ne sont pas lisibles.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Marc56
Messages : 2197
Inscription : sam. 08/févr./2014 15:19

Re: Lecteur de Tags MP3 V2.3

Message par Marc56 »

falsam a écrit :PS : Je viens de voir aussi une erreur sur un des codes github dont je t'ai passé le lien. Les commentaires ne sont pas lisibles.
et le dernier caractère de chaque champs retourné par le programme est supprimé. :?
(dans mes exemples qui fonctionnent dans l'autre)

Dans les deux programmes, les tailles retournées par l'entête et par chaque champs sont identiques,
ce n'est donc qu'une question de transtypage du résultat. :wink:

(A+ Je vais faire autre-chose le temps que mes neurones refroidissent un peu)

8)
Marc56
Messages : 2197
Inscription : sam. 08/févr./2014 15:19

Re: Lecteur de Tags MP3 V2.3

Message par Marc56 »

Version modifiée pour voir les fichiers à tag unicode
(seule la procédure est modifiée, pour repérer le flag unicode, mais je remet tout car j'ai mis un système de boucle pour tester plusieurs fichiers)
Mettez quelques fichiers à tester dans votre répertoire "Musique" et modifiez la liste au début du code.

Code : Tout sélectionner

; Read MP3 Tags V2
; Minimum cherché: Lire le titre (Tag: TIT2)
; Marc56 - 22/03/2017
; Documentation:
; Format: http://id3.org/id3v2.3.0
; Explication Fr trouvée sur: http://mgc99.free.fr/InfoMP3.html
; Merci pour leurs exemples et explications à:
; Ts-soft: http://www.purebasic.fr/english/viewtopic.php?f=12&t=55920 
; Zorro: http://www.purebasic.fr/french/viewtopic.php?f=1&t=11240&start=31

; Music() = OpenFileRequester("Lecture Tags MP3 V2.3", 
;                                GetUserDirectory(#PB_Directory_Musics), 
;                                "Fichier MP3|*.mp3", 1)

Global NewList Music.s()

; Ajoutez vos fichiers tests dans le répertoire standard "Musique"
AddElement(Music()) : Music() = "Test_Standard.mp3"
AddElement(Music()) : Music() = "Test_Unicode.mp3"
AddElement(Music()) : Music() = "Earth, Wind Fire - Let's Groove.mp3"

SetCurrentDirectory(GetUserDirectory(#PB_Directory_Musics))

ForEach Music()
     If Music() = ""
          End
     EndIf
     
     Declare.s Read_Value()
     
     ; Fichier cassé ou absent ? suivant.
     If Not ReadFile(0, Music())   
          Debug "Erreur: " + Music()
          End
     EndIf
     
     ; Tag ID V2 (ID3 sur les 3 premiers octets)
     If Not ReadString(0, #PB_UTF8, 3) = "ID3"
          Debug "Ce fichier n'est pas un mp3 V2"
          CloseFile(0)
          End
     EndIf
     
     Debug #CRLF$ + "--- Fichier: " + Music()
     ; Lecture de l'entête (10 octets)
     *Head = AllocateMemory(10)
     ReadData(0, *Head, 10)
     ID_Sub = PeekA(*Head) ; Identification version (position 4)
     Debug "Tag ID v2." + ID_Sub
     If ID_Sub <> 3 And ID_Sub <> 4
          End
     EndIf
     
     ; On avance de 3 et on récupère la taille complète des tags
     *Head + 3
     x3 = PeekB(*Head) : *Head + 1
     x2 = PeekB(*Head) : *Head + 1
     x1 = PeekB(*Head) : *Head + 1
     x0 = PeekB(*Head) : *Head + 1
     Header_Size = x3 * Pow(128,3) + x2 * Pow(128,2) + x1 * Pow(128,1) + x0 * Pow(128,0)
     Debug "Taille entête: " + Header_Size + " octets"      
     ; On libère le buffer d'entête
     *Head - 7 : FreeMemory(*Head)
     
     ; Lecture de la zone de tags
     Global *Buf = AllocateMemory(Header_Size)
     FileSeek(0, 0) ; Revenir au début du fichier
     ReadData(0, *Buf, Header_Size)
     CloseFile(0) 
     
     ; Lecture de toute la zone (décalage de 1 lecture de 4)
     For i = 0 To Header_Size - 10
          IDT$ = PeekS(*Buf, 4, #PB_UTF8) 
          Select IDT$
               Case "TPE1"
                    Debug "TPE1 - Artiste    : >" + Read_Value()
               Case "TALB"
                    Debug "TALB - CD         : >" + Read_Value()                          
               Case "TIT2"
                    Debug "TIT2 - Titre      : >" + Read_Value()                                
               Case "TYER"
                    Debug "TYER - Année      : >" + Read_Value()
               Case "TDRC"
                    Debug "TDRC - Année      : >" + Read_Value()                    
               Case "TRCK"
                    Debug "TRCK - Piste      : >" + Read_Value()
               Case "TLEN" 
                    Debug "TLEN - Durée (?)  : >" + Read_Value()                  
               Case "TPUB" 
                    Debug "TPUB - ???        : >" + Read_Value()                   
          EndSelect         
          ; Avance de 1
          *Buf + 1
     Next
     
Next

Procedure.s Read_Value()
     ; Récupérer la taille du champs
     *Buf + 4
     x3 = PeekB(*Buf) : *Buf + 1
     x2 = PeekB(*Buf) : *Buf + 1
     x1 = PeekB(*Buf) : *Buf + 1
     x0 = PeekB(*Buf) : *Buf + 1
     Frame_Size = x3 * Pow(128,3) + x2 * Pow(128,2) + x1 * Pow(128,1) + x0 * Pow(128,0)
     ; Flags Unicode
     *Buf + 2
     If PeekA(*Buf) = 1
          Unicode = 1
     Else
          Unicode = 0
     EndIf
     *Buf + 1 
     If Unicode = 0 
          ProcedureReturn PeekS(*Buf, Frame_Size-1, #PB_UTF8) + "< (" + Frame_Size + ")" 
     ElseIf Unicode = 1
          ProcedureReturn PeekS(*Buf, Frame_Size/2, #PB_Unicode) + "< (" + Frame_Size + ")" 
     EndIf  
EndProcedure
Chez moi certains fichiers ne passent pas bien, j'ai un doute sur mon 'Frame_Size' dans le cas d'Unicode) :?

:idea: Oups, non, corrigé Frame_Size / 2 puisque c'est unicode. Ça marche :P

Merci pour vos conseils sur l'utilisation de la mémoire et pour les exemples.
(Je vais mettre ça au propre et en faire une mini version pour l'intégrer à mon Desk qui pour l'instant ne lisait que les tags V1)

:wink:
Répondre