[ID3-Tag] "Set COMMENT = X" per foobar2000 macht Tag unlesbar



  • !!!Achtung!!!
    Der folgende Beitrag ist lang, ausführlich und beinhaltet Englisch

    Moin beisammen!

    Ich habe nun schon unzählige Stunden über Monate hinweg an einem für mich sehr wichtigen Projekt gearbeitet. Das gesamte Projekt ist endgültig fertig und es gibt nur einen einzigen Bug, der die gesamte Arbeit in Frage stellt.

    Ich möchte nicht das ganze Projekt beschreiben, sondern nur den Ausschnitt der für die Analyse wesentlich ist. Es gibt ein ein Struct (xTag) aus CStrings, das Artist, Album, Genre, Year und Title beinhaltet. Dieses wird mit Hilfe einer Maske und eines Parsers aus den Unterordnern einer MP3-Datei zusammengesetzt.

    Außerdem wird der eigentlich Tag der MP3-Datei (vorzugsweiße ID3v2.3.0) eingelesen. Dazu benutze ich die ID3Lib von sourceforge.net.

    - Homepage: http://id3lib.sourceforge.net/
    - Documentation kurz: http://id3lib.sourceforge.net/api/index.html
    - Documentation lang: http://id3lib.sourceforge.net/id3lib-manual.php

    In der globals.h der ID3Lib kann eingestellt werden, welche Version zum Lesen und Schreiben benutzt werden soll:

    ID3_ENUM(ID3_V2Spec)
    {
      ID3V2_UNKNOWN = -1,
      ID3V2_2_0 = 0,
      ID3V2_2_1,
      ID3V2_3_0,
      ID3V2_4_0,
      ID3V2_EARLIEST = ID3V2_2_0,
      ID3V2_LATEST = ID3V2_3_0 // Dieser Version wird benutzt
    };
    

    Wenn ich nun das Programm benutzt um die ID3-Tags zu schreiben, funktioniert alles wunderbar. Es ließt die ID3-Tags problemlos aus, der Vergleich funktioniert und wenn der Tag nicht mit dem Tag aus der Ordnerstruktur übereinstimmt, wird er neugeschrieben, ansonsten gelassen. Nach dem Schreiben erkennen alle Programme, wie z.B. der Ultra Tragger die Tags. Auch mein Musicplayer foobar2000 macht keine Anstände alle Felder ordnungsgemäß auszulesen.

    Nun zu der wichtigen Zusatzinformation:
    Ich benutze das Feld "COMMENT" des ID3v2-Tags um dort die Werte 0 bis 5 einzutragen. Diese repräsentieren (in Sternen in foobar2000) meine Bewertung für einen Song. Wird von dem Programm ein Tag neu geschrieben, wird das COMMENT Feld mit dem Wert "0" initialisiert. Auch diesen Wert erkennt foobar2000 ohne Probleme.

    In foobar2000 benutzte ich zum Bewerten der Songs, also zum Setzen des Werts des Felds COMMENT, den eingebauten Scipt vom Masstagger. Dieser Script tut laut einem Moderator aus dem offiziellen bei hydrogenaudio.org gehostetem foobar2000-Forum nichts weiter, als einfach das Feld auf einen gewissen Wert zu setzen:

    It merely sets the COMMENT field to the specified value. The tags are then written by masstagger using the same tag writing routines that are also used by other parts of foobar2000, for example the properties window.

    Jetzt kommt der Fehler!!!!
    Nachdem ich mit foobar2000 nun einen Song bewertet habe, kann foobar2000 den gesamtem Tag problemlos lesen. Programme wie der Ultra Tagger oder meine C++-Routine zum Lesen der ID3-Tags mit Hilfe der ID3Lib können den gesamtem Tag nicht mehr lesen. Kein einziges Feld wird dabei gefunden.

    Hier erstmal der wichtige Quellcode:

    Ausgangsroutine

    ID3_Tag oTag;
    oTag.Link(oRealPath, ID3TT_ID3V2);
    
    if(!oTagger.checkField(oTag, ID3FID_CONTENTTYPE, xTag.oGenre)
    || !oTagger.checkField(oTag, ID3FID_LEADARTIST, xTag.oArtist)
    || !oTagger.checkField(oTag, ID3FID_ALBUM, xTag.oAlbum)      
    || !oTagger.checkField(oTag, ID3FID_YEAR, xTag.oYear)      
    || !oTagger.checkField(oTag, ID3FID_TITLE, xTag.oTitle))
    {
      oTagger.writeTag(oTag, xTag);
    };
    

    Angewendete Funktionen

    //---------------------------------------------------------------------
    
    void CTagger::writeTag(ID3_Tag &roTag, CTagger::Tag &rxTag) throw()
    {
      CString oComment;
      ID3_Frame *poFrame;    
    
      if(poFrame = roTag.Find(ID3FID_COMMENT))
      { 
        char acContent[1024];
        poFrame->Field(ID3FN_TEXT).Get(acContent, 1024); 
        oComment = acContent;
      }
    
      else
      {
        oComment = "0";
      };
    
      poFrame = NULL;
    
      roTag.Strip(true); 
    
      writeField(roTag, ID3FID_CONTENTTYPE, rxTag.oGenre);
      writeField(roTag, ID3FID_LEADARTIST, rxTag.oArtist);
      writeField(roTag, ID3FID_ALBUM, rxTag.oAlbum);
      writeField(roTag, ID3FID_YEAR, rxTag.oYear);
      writeField(roTag, ID3FID_TITLE, rxTag.oTitle);
      writeField(roTag, ID3FID_COMMENT, oComment);
    
      roTag.SetUnsync(false);
      roTag.SetExtendedHeader(false);
      roTag.SetCompression(false);
      roTag.SetPadding(false);
    
      roTag.Update();
    };
    
    //---------------------------------------------------------------------
    
    void CTagger::writeField(ID3_Tag &roTag, ID3_FrameID xFrameID,
                             CString &roContent) throw()
    {
      char acContent[1024];
      strcpy_s(acContent, roContent);
    
      ID3_Frame *poFrame;
      poFrame = roTag.Find(xFrameID);  
    
      if(!poFrame)
      {
        poFrame = new ID3_Frame;
        poFrame->SetID(xFrameID);
        poFrame->Field(ID3FN_TEXT).Set(acContent);    
        roTag.AddFrame(poFrame);
      }
    
      else
      {
        poFrame->Field(ID3FN_TEXT).Set(acContent);
      };
    
      poFrame = NULL;
    };
    
    //---------------------------------------------------------------------
    
    bool CTagger::checkField(ID3_Tag &roTag, ID3_FrameID xFrameID,
                             CString &roCompare) throw()
    {
      bool bResult;
      bResult = false;
    
      ID3_Frame *poFrame;
      poFrame = roTag.Find(xFrameID);  
    
      if(poFrame)
      {
        char acTemp[1024];
        poFrame->Field(ID3FN_TEXT).Get(acTemp, 1024);
    
        CString oCompare;
        oCompare = acTemp;
    
        if(roCompare == oCompare)
        {
          bResult = true;
        };
      };
    
      return bResult;
    };
    
    //---------------------------------------------------------------------
    

    Lesen eines Feldes

    ID3_Tag oTag;
    oTag.Link("goreality.mp3", ID3TT_ID3V2);
    
    ID3_Frame *poFrame; 
    char acContent[1024];
    
    if(poFrame = oTag.Find(ID3FID_CONTENTTYPE))
    {    
      poFrame->Field(ID3FN_TEXT).Get(acContent, 1024); 
    };
    

    Ich habe bereits mit einigen sehr guten Programmieren über dieses Problem gesprochen und unabhängig voneinander fanden auch sie nur drei Mögliche Fehlerquellen, genau wie ich:

    1. Am wahrscheinlichten scheint ein Fehler beim Schreiben zu sein, wegen dem der Tag nicht richtig darauf vorbereitet ist, dass foobar2000 das Feld COMMENT veraendert. Muss ich irgendetwas in einer anderen Reihenfolge machen? Setze ich die Flags wie extended Header, unsyncronisation etc. falsch oder muss ich die Felder anders initialisieren?

    2. Es könnte auch sein, dass ich irgendwas beim Lesen falsch mache, nachdem das COMMENT-Feld per foobar2000 geändert wurde.

    3. Am unwahrscheinlichten, aber auch möglich wäre es, dass foobar2000 beim Setzen des COMMENT-Felds den Tag beschädigt. Eigentlich kann das aber nicht sein, da wenn ich das ganze über ein PHP-ID3-Lib laufen lasse, alles problemlos funktioniert (allerdings soll das Programm ohne PHP funktionieren ;))

    Ich würde mich unglaublich darüber freuen, wenn irgendein geniales Hirn hier mir bei diesem verzwickten Problem helfen kann. Ich arbeite an dem Projekt inzwischen über ein Jahr und bin nach unendlich vielen Hürden endlich fertig und nur noch dieses eine Problem hindert mich am Abschließen dieses Projekts.

    Gruß, Kane



  • Hex-Editor



  • Ist foobar200 jetzt dein Programm oder nicht? Dein Text ist irgendwie verwirrend



  • äh was schrieb:

    Ist foobar200 jetzt dein Programm oder nicht? Dein Text ist irgendwie verwirrend

    Natürlich nicht. foobar2000 ist ein bekannter Player.

    MfG SideWinder



  • He he, ich hab gedacht er will den Namen seines Produkts nicht verraten.



  • äh was schrieb:

    He he, ich hab gedacht er will den Namen seines Produkts nicht verraten.

    Nene, das Programm um das es geht nennt sich "KaneZ MP3-Studio" und kann halt u.a. mithilfe von Masken die der User eingibt Massenweiße Ordner durchtaggen systematisch. Gibts zwar schon hier und da, aber nicht so wie ich und paar Kollegen sich das vorstellen xD. Ist also eher für Eigennutzung aber könnte sich ggf. auch mancher Beliebtheit erfreuen...

    ...egal zurück zum Fehler: Irgendeine Idee?


Anmelden zum Antworten