View Javadoc

1   package com.melloware.jukes.file.tag;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.util.ArrayList;
6   import java.util.Map;
7   
8   import org.apache.commons.lang.StringUtils;
9   import org.apache.commons.logging.Log;
10  import org.apache.commons.logging.LogFactory;
11  import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
12  import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
13  import org.jaudiotagger.audio.mp3.MP3File;
14  import org.jaudiotagger.tag.TagException;
15  import org.jaudiotagger.tag.id3.AbstractID3v2Frame;
16  import org.jaudiotagger.tag.id3.AbstractID3v2Tag;
17  import org.jaudiotagger.tag.id3.AbstractTagFrameBody;
18  import org.jaudiotagger.tag.id3.ID3v11Tag;
19  import org.jaudiotagger.tag.id3.ID3v24Frame;
20  import org.jaudiotagger.tag.id3.ID3v24Tag;
21  import org.jaudiotagger.tag.id3.framebody.AbstractID3v2FrameBody;
22  import org.jaudiotagger.tag.id3.framebody.FrameBodyCOMM;
23  import org.jaudiotagger.tag.id3.framebody.FrameBodyTALB;
24  import org.jaudiotagger.tag.id3.framebody.FrameBodyTCON;
25  import org.jaudiotagger.tag.id3.framebody.FrameBodyTDRC;
26  import org.jaudiotagger.tag.id3.framebody.FrameBodyTENC;
27  import org.jaudiotagger.tag.id3.framebody.FrameBodyTIT2;
28  import org.jaudiotagger.tag.id3.framebody.FrameBodyTLEN;
29  import org.jaudiotagger.tag.id3.framebody.FrameBodyTPE1;
30  import org.jaudiotagger.tag.id3.framebody.FrameBodyTRCK;
31  
32  import com.melloware.jukes.exception.MusicTagException;
33  
34  /**
35   * MusicTag class used for editing MP3 file tags.  Both version ID3v1.1 and
36   * IDv2.4 are supported.
37   * <p>
38   * The JAudioTagger (https://jaudiotagger.dev.java.net/) library is used to read
39   * these types of Tags.
40   * <p>
41   * Copyright (c) 2006
42   * Melloware, Inc. <http://www.melloware.com>
43   * @author Emil A. Lefkof III <info@melloware.com>
44   * @version 4.0
45   */
46  public final class Mp3Tag
47      extends MusicTag {
48  
49      private static final Log LOG = LogFactory.getLog(Mp3Tag.class);
50      public static final String V2_CODE_ALBUM = "TALB";
51      public static final String V2_CODE_TITLE = "TIT2";
52      public static final String V2_CODE_ARTIST = "TPE1";
53      public static final String V2_CODE_YEAR = "TDRC";
54      public static final String V2_CODE_COMMENT = "COMM";
55      public static final String V2_CODE_GENRE = "TCON";
56      public static final String V2_CODE_TRACK = "TRCK";
57      public static final String V2_CODE_ENCODE = "TENC";
58      public static final String V2_CODE_LENGTH = "TLEN";
59      private static final String LINE_BREAK = "\n\n";
60      private MP3File audioFile;
61  
62      /**
63       * Constructor that takes a file.
64       * <p>
65       * @param aFile the music file
66       * @throws MusicTagException if any error occurs reading file
67       */
68      public Mp3Tag(File aFile)
69             throws MusicTagException {
70          super(aFile);
71  
72          try {
73              // create the audio file object
74              this.audioFile = new MP3File(aFile);
75  
76              // initialize all tags
77              initializeTags();
78          } catch (IOException ex) {
79              LOG.error(ex.getMessage(), ex);
80              throw new MusicTagException("IOException opening Music File Tag. " + aFile.getAbsolutePath() + LINE_BREAK
81                                          + ex.getMessage());
82          } catch (TagException ex) {
83              LOG.error(ex.getMessage(), ex);
84              throw new MusicTagException("MusicTagException opening Music File Tag. " + aFile.getAbsolutePath() + LINE_BREAK
85                                          + ex.getMessage());
86          } catch (Exception ex) {
87              LOG.error(ex.getMessage(), ex);
88              throw new MusicTagException("Unexpected exception opening Music File Tag. " + aFile.getAbsolutePath()
89                                          + LINE_BREAK + ex.getMessage());
90          }
91      }
92  
93      /**
94       * Gets the artist.
95       * <p>
96       * @return Returns the artist.
97       */
98      public String getArtist() {
99  
100         if (StringUtils.isBlank(this.artist)) {
101             String v1 = null;
102             String v2 = null;
103             if (audioFile.hasID3v1Tag()) {
104                 v1 = StringUtils.defaultIfEmpty(audioFile.getID3v1Tag().getFirstArtist(), NO_TAG);
105             }
106             final AbstractID3v2Frame frame = loadFrame(V2_CODE_ARTIST);
107             if (frame != null) {
108             	final AbstractID3v2FrameBody frameBody = ((FrameBodyTPE1)frame.getBody());
109                 v2 = ((FrameBodyTPE1)frameBody).getText();
110             }
111 
112             // return v2 tag else if empty return the v1 tag
113             this.artist = StringUtils.defaultIfEmpty(v2, v1).trim();
114         }
115         return this.artist;
116     }
117 
118     /**
119      * Gets the maximum bitrate for this file.
120      * <p>
121      * @return Returns the maximum bitrate for this file
122      */
123     public Long getBitRate() {
124         if (this.bitRate == null) {
125             final Integer bitrate = (header == null) ? Integer.valueOf(1000)
126                                                      : ((Integer)header.get("mp3.bitrate.nominal.bps"));
127             this.bitRate = Long.valueOf((bitrate.longValue() / 1000));
128         }
129 
130         return this.bitRate;
131     }
132 
133     /**
134      * Gets the comment.
135      * <p>
136      * @return Returns the comment.
137      */
138     public String getComment() {
139         if (StringUtils.isBlank(this.comment)) {
140             String v1 = null;
141             String v2 = null;
142             if (audioFile.hasID3v1Tag()) {
143                 v1 = StringUtils.defaultIfEmpty(audioFile.getID3v1Tag().getFirstComment(), " ");
144             }
145             final AbstractID3v2Frame frame = loadFrame(V2_CODE_COMMENT);
146             if (frame != null) {
147             	final AbstractID3v2FrameBody frameBody = ((FrameBodyCOMM)frame.getBody());
148                 v2 = ((FrameBodyCOMM)frameBody).getText();
149             }
150 
151             // return v2 tag else if empty return the v1 tag
152             this.comment = StringUtils.defaultIfEmpty(v2, v1);
153         }
154         return this.comment;
155     }
156 
157     /* (non-Javadoc)
158      * @see com.melloware.jukes.file.tag.MusicTag#getCopyrighted()
159      */
160     public String getCopyrighted() {
161         return Boolean.toString(audioFile.getMP3AudioHeader().isCopyrighted());
162     }
163 
164     /**
165      * Gets the disc.
166      * <p>
167      * @return Returns the disc.
168      */
169     public String getDisc() {
170         if (StringUtils.isBlank(this.disc)) {
171             String v1 = null;
172             String v2 = null;
173             if (audioFile.hasID3v1Tag()) {
174                 v1 = StringUtils.defaultIfEmpty(audioFile.getID3v1Tag().getFirstAlbum(), NO_TAG);
175             }
176             final AbstractID3v2Frame frame = loadFrame(V2_CODE_ALBUM);
177             if (frame != null) {
178             	final AbstractID3v2FrameBody frameBody = ((FrameBodyTALB)frame.getBody());
179                 v2 = ((FrameBodyTALB)frameBody).getText();
180             }
181 
182             // return v2 tag else if empty return the v1 tag
183             this.disc = StringUtils.defaultIfEmpty(v2, v1).trim();
184         }
185         return this.disc;
186     }
187 
188     /* (non-Javadoc)
189      * @see com.melloware.jukes.file.tag.MusicTag#getEmphasis()
190      */
191     public String getEmphasis() {
192         return audioFile.getMP3AudioHeader().getEmphasis();
193     }
194 
195     /**
196      * Gets the encodedBy.
197      * <p>
198      * @return Returns the encodedBy.
199      */
200     public String getEncodedBy() {
201         if (StringUtils.isBlank(this.encodedBy)) {
202 
203         	final AbstractID3v2Frame frame = loadFrame(V2_CODE_ENCODE);
204             if (frame != null) {
205             	final AbstractID3v2FrameBody frameBody = ((FrameBodyTENC)frame.getBody());
206                 this.encodedBy = ((FrameBodyTENC)frameBody).getText().trim();
207             }
208         }
209         return this.encodedBy;
210     }
211 
212     /* (non-Javadoc)
213      * @see com.melloware.jukes.file.tag.MusicTag#getFrequency()
214      */
215     public String getFrequency() {
216         return audioFile.getMP3AudioHeader().getSampleRate();
217     }
218 
219     /**
220      * Gets the genre.
221      * <p>
222      * @return Returns the genre.
223      */
224     public String getGenre() {
225         if (StringUtils.isBlank(this.genre)) {
226             String v1 = null;
227             String v2 = null;
228             if (audioFile.hasID3v1Tag()) {
229                 v1 = audioFile.getID3v1Tag().getFirstGenre();
230             }
231             final AbstractID3v2Frame frame = loadFrame(V2_CODE_GENRE);
232             if (frame != null) {
233             	final AbstractID3v2FrameBody frameBody = ((FrameBodyTCON)frame.getBody());
234                 v2 = StringUtils.defaultIfEmpty(((FrameBodyTCON)frameBody).getText(), NO_TAG);
235             }
236 
237             // return v2 tag else if empty return the v1 tag
238             this.genre = StringUtils.defaultIfEmpty(v1, v2);
239         }
240         return this.genre;
241     }
242 
243     /* (non-Javadoc)
244      * @see com.melloware.jukes.file.tag.MusicTag#getHeader()
245      */
246     public Map getHeader() {
247         return header;
248     }
249 
250     /* (non-Javadoc)
251      * @see com.melloware.jukes.file.tag.MusicTag#getLayer()
252      */
253     public String getLayer() {
254         return audioFile.getMP3AudioHeader().getMpegLayer();
255     }
256 
257     /* (non-Javadoc)
258      * @see com.melloware.jukes.file.tag.MusicTag#getMode()
259      */
260     public String getMode() {
261         return audioFile.getMP3AudioHeader().getChannels();
262     }
263 
264     /**
265      * Gets the title.
266      * <p>
267      * @return Returns the title.
268      */
269     public String getTitle() {
270 
271     	// if not blank then just return the title
272         if (StringUtils.isNotBlank(this.title)) {
273             return this.title;
274         }
275 
276         String v1 = null;
277         String v2 = null;
278         if (audioFile.hasID3v1Tag()) {
279             v1 = StringUtils.defaultIfEmpty(audioFile.getID3v1Tag().getFirstTitle(), NO_TAG);
280 
281             // if this is the max length for a v1 tag, or it begins with "Track"
282             // try and grab by filename it may be longer
283             if ((v1.length() == 30) || (v1.equals(NO_TAG)) || (v1.startsWith("Track"))) {
284                 v1 = extractTitleFromFilename();
285                 LOG.debug("Filename extracted");
286             }
287         }
288         final AbstractID3v2Frame frame = loadFrame(V2_CODE_TITLE);
289         if (frame != null) {
290         	final AbstractID3v2FrameBody frameBody = ((FrameBodyTIT2)frame.getBody());
291             v2 = ((FrameBodyTIT2)frameBody).getText();
292         }
293 
294         // return v2 tag else if empty return the v1 tag
295         this.title = StringUtils.defaultIfEmpty(v2, v1).trim();
296 
297         return this.title;
298     }
299 
300     /**
301      * Gets the track.
302      * <p>
303      * @return Returns the track.
304      */
305     public String getTrack() {
306         if (StringUtils.isBlank(this.track)) {
307             String v1 = null;
308             String v2 = null;
309             if ((audioFile.hasID3v1Tag()) && (audioFile.getID3v1Tag() instanceof ID3v11Tag)) {
310                 v1 = ((ID3v11Tag)audioFile.getID3v1Tag()).getFirstTrack();
311 
312                 // default it to  non number if empty so isNumeric() test fails
313                 v1 = StringUtils.defaultIfEmpty(v1, "X");
314             }
315             final AbstractID3v2Frame frame = loadFrame(V2_CODE_TRACK);
316             if (frame != null) {
317             	final AbstractID3v2FrameBody frameBody = ((FrameBodyTRCK)frame.getBody());
318                 v2 = ((FrameBodyTRCK)frameBody).getText();
319                 // default it to  non number if empty so isNumeric() test fails
320                 v2 = StringUtils.defaultIfEmpty(v2, "X");
321             }
322 
323             // if V1 is a number grab it as a number
324             int track1 = 0;
325             int track2 = 0;
326             if (StringUtils.isNumeric(v1)) {
327                 track1 = Integer.parseInt(v1);
328             }
329 
330             // v2 can contain format like 7 of 13, 12/15, etc.
331             if (StringUtils.isNumeric(v2)) {
332                 track2 = Integer.valueOf(v2).intValue();
333             }
334             // find the best match whihc is the larger of these two values
335             final int bestMatch = Math.max(track1, track2);
336 
337             // return v2 tag else if empty return the v1 tag
338             this.track = StringUtils.leftPad(String.valueOf(bestMatch), 2, "0").trim();
339         }
340         return this.track;
341     }
342 
343     /**
344      * Gets the track length in seconds.
345      * <p>
346      * @return Returns the track length in seconds.
347      */
348     public long getTrackLength() {
349         if (this.trackLength > 1) {
350             return this.trackLength;
351         }
352         final Long duration = (header == null) ? Long.valueOf(100000) : ((Long)header.get("duration"));
353         this.trackLength = ((duration.longValue() / 1000) / 1000);
354         return this.trackLength;
355     }
356 
357     /* (non-Javadoc)
358      * @see com.melloware.jukes.file.tag.MusicTag#getVersion()
359      */
360     public String getVersion() {
361         return audioFile.getMP3AudioHeader().getMpegVersion();
362     }
363 
364     /**
365      * Gets the year.
366      * <p>
367      * @return Returns the year.
368      */
369     public String getYear() {
370         if (StringUtils.isBlank(this.year)) {
371             String v1 = null;
372             String v2 = null;
373             if (audioFile.hasID3v1Tag()) {
374                 v1 = audioFile.getID3v1Tag().getFirstYear();
375                 v1 = StringUtils.defaultIfEmpty(v1, CURRENT_YEAR);
376             }
377             final AbstractID3v2Frame frame = loadFrame(V2_CODE_YEAR);
378             if (frame != null) {
379             	final AbstractID3v2FrameBody frameBody = ((FrameBodyTDRC)frame.getBody());
380                 v2 = ((FrameBodyTDRC)frameBody).getText();
381             }
382 
383             // return v2 tag else if empty return the v1 tag
384             this.year = StringUtils.defaultIfEmpty(v2, v1).trim();
385         }
386         return this.year;
387     }
388 
389     /**
390      * Sets the artist.
391      * <p>
392      * @param aArtist The artist to set.
393      */
394     public void setArtist(final String aArtist) {
395         this.artist = StringUtils.defaultIfEmpty(aArtist, NO_TAG).trim();
396 
397         if (audioFile.hasID3v1Tag()) {
398             audioFile.getID3v1Tag().setArtist(this.artist);
399         }
400         final AbstractID3v2Frame frame = loadFrame(V2_CODE_ARTIST);
401         if (frame != null) {
402         	final AbstractID3v2FrameBody frameBody = ((FrameBodyTPE1)frame.getBody());
403             ((FrameBodyTPE1)frameBody).setText(this.artist);
404         }
405     }
406 
407     /**
408      * Sets the comment.
409      * <p>
410      * @param aComment The comment to set.
411      */
412     public void setComment(final String aComment) {
413         this.comment = StringUtils.defaultIfEmpty(aComment, "").trim();
414 
415         if (audioFile.hasID3v1Tag()) {
416             audioFile.getID3v1Tag().setComment(this.comment);
417         }
418         final AbstractID3v2Frame frame = loadFrame(V2_CODE_COMMENT);
419         if (frame != null) {
420         	final AbstractID3v2FrameBody frameBody = ((FrameBodyCOMM)frame.getBody());
421             ((FrameBodyCOMM)frameBody).setText(this.comment);
422         }
423     }
424 
425     /**
426      * Sets the disc.
427      * <p>
428      * @param aDisc The disc to set.
429      */
430     public void setDisc(final String aDisc) {
431         this.disc = StringUtils.defaultIfEmpty(aDisc, NO_TAG).trim();
432 
433         if (audioFile.hasID3v1Tag()) {
434             audioFile.getID3v1Tag().setAlbum(this.disc);
435         }
436         final AbstractID3v2Frame frame = loadFrame(V2_CODE_ALBUM);
437         if (frame != null) {
438         	final AbstractID3v2FrameBody frameBody = ((FrameBodyTALB)frame.getBody());
439             ((FrameBodyTALB)frameBody).setText(this.disc);
440         }
441     }
442 
443     /**
444      * Sets the Encoded By.
445      * <p>
446      * @param aEncodedBy The encoded by to set.
447      */
448     public void setEncodedBy(final String aEncodedBy) {
449         this.encodedBy = StringUtils.defaultIfEmpty(aEncodedBy, System.getProperty("application.name")).trim();
450 
451         final AbstractID3v2Frame frame = loadFrame(V2_CODE_ENCODE);
452         if (frame != null) {
453         	final AbstractID3v2FrameBody frameBody = ((FrameBodyTENC)frame.getBody());
454             ((FrameBodyTENC)frameBody).setText(encodedBy);
455         }
456     }
457 
458     /**
459      * Sets the genre.
460      * <p>
461      * @param aGenre The genre to set.
462      */
463     public void setGenre(final String aGenre) {
464         this.genre = StringUtils.defaultIfEmpty(aGenre, NO_TAG).trim();
465 
466         if (audioFile.hasID3v1Tag()) {
467             audioFile.getID3v1Tag().setGenre(this.genre);
468         }
469         final AbstractID3v2Frame frame = loadFrame(V2_CODE_GENRE);
470         if (frame != null) {
471         	final AbstractID3v2FrameBody frameBody = ((FrameBodyTCON)frame.getBody());
472             ((FrameBodyTCON)frameBody).setText(this.genre);
473         }
474     }
475 
476     /**
477      * Sets the title.
478      * <p>
479      * @param aTitle The title to set.
480      */
481     public void setTitle(final String aTitle) {
482         this.title = StringUtils.defaultIfEmpty(aTitle, NO_TAG).trim();
483 
484         if (audioFile.hasID3v1Tag()) {
485             audioFile.getID3v1Tag().setTitle(this.title);
486         }
487         final AbstractID3v2Frame frame = loadFrame(V2_CODE_TITLE);
488         if (frame != null) {
489         	final AbstractID3v2FrameBody frameBody = ((FrameBodyTIT2)frame.getBody());
490             ((FrameBodyTIT2)frameBody).setText(this.title);
491         }
492     }
493 
494     /**
495      * Sets the track.
496      * <p>
497      * @param aTrack The track to set.
498      */
499     public void setTrack(final String aTrack) {
500         setTrack(aTrack, 2);
501     }
502     
503     
504     /**
505      * Sets the track.
506      * <p>
507      * @param aTrack The track to set.
508      * @param aPadding the number of 0's to pad this track with
509      */
510     public void setTrack(final String aTrack, final int aPadding) {
511        final String current = StringUtils.defaultIfEmpty(aTrack, "0").trim();
512        this.track = StringUtils.leftPad(current, aPadding, "0").trim();
513 
514        if ((audioFile.hasID3v1Tag()) && (audioFile.getID3v1Tag() instanceof ID3v11Tag)) {
515            ((ID3v11Tag)audioFile.getID3v1Tag()).setTrack(this.track);
516        }
517        final AbstractID3v2Frame frame = loadFrame(V2_CODE_TRACK);
518        if (frame != null) {
519         final AbstractID3v2FrameBody frameBody = ((FrameBodyTRCK)frame.getBody());
520            ((FrameBodyTRCK)frameBody).setText(this.track);
521        }
522     }
523 
524     /**
525      * Sets the trackLength.
526      * <p>
527      * @param aTrackLength The trackLength to set.
528      */
529     public void setTrackLength(final long aTrackLength) {
530         this.trackLength = aTrackLength;
531 
532         if (audioFile.hasID3v2Tag()) {
533         	final AbstractID3v2Frame frame = loadFrame(V2_CODE_LENGTH);
534             if (frame != null) {
535             	final AbstractID3v2FrameBody frameBody = ((FrameBodyTLEN)frame.getBody());
536                 ((FrameBodyTLEN)frameBody).setText(String.valueOf(this.trackLength * 1000));
537             }
538         }
539     }
540 
541     /**
542      * Sets the year.
543      * <p>
544      * @param aYear The year to set.
545      */
546     public void setYear(final String aYear) {
547         this.year = StringUtils.defaultIfEmpty(aYear, CURRENT_YEAR).trim();
548 
549         if (audioFile.hasID3v1Tag()) {
550             audioFile.getID3v1Tag().setYear(this.year);
551         }
552         final AbstractID3v2Frame frame = loadFrame(V2_CODE_YEAR);
553         if (frame != null) {
554         	final AbstractID3v2FrameBody frameBody = ((FrameBodyTDRC)frame.getBody());
555             ((FrameBodyTDRC)frameBody).setText(this.year);
556         }
557     }
558 
559     /**
560      * Is this file a variable bit rate.
561      * <p>
562      * @return true if variable false if constant bit rate
563      */
564     public boolean isVBR() {
565         return ((header == null) ? Boolean.FALSE : ((Boolean)header.get("mp3.vbr"))).booleanValue();
566     }
567 
568     /**
569      * Removes tags from the audio file.
570      * <p>
571      * @throws MusicTagException if any error occurs removing the tag
572      */
573     public void removeTags()
574                     throws MusicTagException {
575         try {
576             if (audioFile != null) {
577                 if (audioFile.hasID3v1Tag()) {
578                     audioFile.setID3v1Tag(null);
579                 }
580                 if (audioFile.hasID3v2Tag()) {
581                     audioFile.setID3v2Tag(null);
582                 }
583                 audioFile.save();
584                 initializeTags();
585             }
586         } catch (IOException ex) {
587             LOG.error(ex.getMessage(), ex);
588             throw new MusicTagException("IOException removing Music File Tag.", ex);
589         } catch (TagException ex) {
590             LOG.error(ex.getMessage(), ex);
591             throw new MusicTagException("TagException removing Music File Tag.", ex);
592         } catch (Exception ex) {
593             LOG.error(ex.getMessage(), ex);
594             throw new MusicTagException("Exception removing Music File Tag.", ex);
595         }
596     }
597 
598     /**
599      * Renames this Music file based on a format from prefs.  The format is in
600      * aFormat and can have values %n for track number, %t for title,
601      * %a for artist, and %d for disc.    Replaces any invalid characters
602      * (\\, /, :, , *, ?, ", <, >, or |) with underscores _ to prevent any
603      * errors on file systems.
604      *
605      * Examples:
606      * %n -%t = 01 - Track.mp3
607      * %a - %d - %n - %t = Artist - Album - 01 - Track.mp3
608      * <p>
609      * @param aFormat the string format like %n -%t to rename 01 - Track.mp3
610      * @return true if renamed, false if failure
611      */
612     public boolean renameFile(final String aFormat) {
613         boolean result = false;
614         try {
615             final String newFileName = createFilenameFromFormat(aFormat);
616             final File newFile = new File(newFileName);
617 
618             // close the audioFile
619             audioFile = null;
620 
621             result = this.file.renameTo(newFile);
622             if (result) {
623                 this.file = newFile;
624                 audioFile = new MP3File(newFile);
625                 initializeTags();
626             }
627         } catch (IOException ex) {
628             LOG.error("Error renaming file", ex);
629         } catch (TagException ex) {
630             LOG.error("TagException", ex);
631         } catch (ReadOnlyFileException ex) {
632          LOG.error("ReadOnlyFileException", ex);
633       } catch (InvalidAudioFrameException ex) {
634          LOG.error("InvalidAudioFrameException", ex);
635       } 
636         return result;
637     }
638 
639     /**
640      * Saves the tag back to the file.
641      * <p>
642      * @throws MusicTagException if any error occurs saving the file
643      */
644     public void save()
645               throws MusicTagException {
646         try {
647             if (audioFile != null) {
648                 this.synchronize();
649                 audioFile.save();
650             }
651         } catch (IOException ex) {
652             LOG.error(ex.getMessage(), ex);
653             throw new MusicTagException("IOException saving Music File Tag " + this.file.getName(), ex);
654         } catch (TagException ex) {
655             LOG.error(ex.getMessage(), ex);
656             throw new MusicTagException("MusicTagException saving Music File Tag " + this.file.getName(), ex);
657         } catch (Exception ex) {
658             LOG.error(ex.getMessage(), ex);
659             throw new MusicTagException("Error saving Music File Tag " + this.file.getName(), ex);
660         }
661     }
662 
663     /**
664      * Initialize the V1 and V2 tags for this audio file.
665      */
666     private void initializeTags() {
667         // check for V1 tag, if not there then create one, if V0 then convert it to V11
668         if (audioFile.hasID3v1Tag()) {
669             if (audioFile.getID3v1Tag().getMajorVersion() == 0) {
670                 LOG.debug("Updating to v11 tag from old V10 tag.");
671                 final ID3v11Tag newTagVersion = new ID3v11Tag(audioFile.getID3v1Tag());
672                 // Set to the correct tag need to cast
673                 audioFile.setID3v1Tag((ID3v11Tag)newTagVersion);
674             }
675         } else {
676             LOG.debug("Create v11 tag.");
677             audioFile.setID3v1Tag(new ID3v11Tag());
678         }
679 
680         // check for V2 tag and set it as the default V2 tag in this file
681         if (audioFile.hasID3v2Tag()) {
682             if (LOG.isDebugEnabled()) {
683                 LOG.debug("V2 Version = " + audioFile.getID3v2Tag().getMajorVersion());
684             }
685             final AbstractID3v2Tag newTagVersion = audioFile.getID3v2TagAsv24();
686             audioFile.setID3v2TagOnly(newTagVersion);
687         }
688 
689         // initialize private variables from tags
690         this.getDisc();
691         this.getArtist();
692         this.getComment();
693         this.getGenre();
694         this.getTitle();
695         this.getTrack();
696         this.getYear();
697         this.getTrackLength();
698         this.getEncodedBy();
699 
700         // now create the new V2 tag to fill and delete the old V2 tag
701         LOG.debug("Create v24 tag.");
702         audioFile.setID3v2Tag(new ID3v24Tag());
703         audioFile.setID3v2TagOnly(audioFile.getID3v2TagAsv24());
704     }
705 
706     /**
707     * Gets the V2 tag frame requested by the aFrameCode value.
708     * <p>
709     * @param aFrameCode the code such as TALB, COMM, TIT2
710     * @return the AbstractID3v2Frame or null if not found
711     */
712     private AbstractID3v2Frame loadFrame(final String aFrameCode) {
713         AbstractID3v2Frame frame = null;
714         AbstractTagFrameBody frameBody = null;
715 
716         if (StringUtils.isBlank(aFrameCode)) {
717             throw new IllegalArgumentException("aFrameCode must have a value.");
718         }
719 
720         // look for the correct frame in the tag
721         if (audioFile.hasID3v2Tag()) {
722             final Object frames = audioFile.getID3v2Tag().getFrame(aFrameCode);
723             if (frames instanceof AbstractID3v2Frame) {
724                 frame = (AbstractID3v2Frame)frames;
725             } else if (frames instanceof ArrayList) {
726                 // more than one frame of this type so just return the first one
727                 final ArrayList frameList = (ArrayList)frames;
728                 frame = (AbstractID3v2Frame)frameList.get(0);
729             } else {
730                 frame = null;
731             }
732         } else {
733             return null;
734         }
735 
736         // if no frame was found create a new one then
737         if (frame == null) {
738             if (V2_CODE_ALBUM.equals(aFrameCode)) {
739                 frame = new ID3v24Frame(V2_CODE_ALBUM);
740                 frameBody = frame.getBody();
741                 final FrameBodyTALB body = (FrameBodyTALB)frameBody;
742                 body.setText("");
743             } else if (V2_CODE_ARTIST.equals(aFrameCode)) {
744                 frame = new ID3v24Frame(V2_CODE_ARTIST);
745                 frameBody = frame.getBody();
746                 final FrameBodyTPE1 body = (FrameBodyTPE1)frameBody;
747                 body.setText("");
748             } else if (V2_CODE_TITLE.equals(aFrameCode)) {
749                 frame = new ID3v24Frame(V2_CODE_TITLE);
750                 frameBody = frame.getBody();
751                 final FrameBodyTIT2 body = (FrameBodyTIT2)frameBody;
752                 body.setText("");
753             } else if (V2_CODE_YEAR.equals(aFrameCode)) {
754                 frame = new ID3v24Frame(V2_CODE_YEAR);
755                 frameBody = frame.getBody();
756                 final FrameBodyTDRC body = (FrameBodyTDRC)frameBody;
757                 body.setText("");
758             } else if (V2_CODE_COMMENT.equals(aFrameCode)) {
759                 frame = new ID3v24Frame(V2_CODE_COMMENT);
760                 frameBody = frame.getBody();
761                 final FrameBodyCOMM body = (FrameBodyCOMM)frameBody;
762                 body.setText("");
763             } else if (V2_CODE_GENRE.equals(aFrameCode)) {
764                 frame = new ID3v24Frame(V2_CODE_GENRE);
765                 frameBody = frame.getBody();
766                 final FrameBodyTCON body = (FrameBodyTCON)frameBody;
767                 body.setText("");
768             } else if (V2_CODE_TRACK.equals(aFrameCode)) {
769                 frame = new ID3v24Frame(V2_CODE_TRACK);
770                 frameBody = frame.getBody();
771                 final FrameBodyTRCK body = (FrameBodyTRCK)frameBody;
772                 body.setText("");
773             } else if (V2_CODE_ENCODE.equals(aFrameCode)) {
774                 frame = new ID3v24Frame(V2_CODE_ENCODE);
775                 frameBody = frame.getBody();
776                 final FrameBodyTENC body = (FrameBodyTENC)frameBody;
777                 body.setText("");
778             } else if (V2_CODE_LENGTH.equals(aFrameCode)) {
779                 frame = new ID3v24Frame(V2_CODE_LENGTH);
780                 frameBody = frame.getBody();
781                 final FrameBodyTLEN body = (FrameBodyTLEN)frameBody;
782                 body.setText("1");
783             } else {
784                 throw new IllegalArgumentException(aFrameCode + " is not a valid Frame Type.");
785             }
786 
787             if (frame != null) {
788                 audioFile.getID3v2Tag().setFrame(frame);
789             }
790         }
791 
792         return frame;
793     }
794 
795 }