close

如標題,會附上程式部分,很簡單易懂的程式。

ID3v1(後來有延伸版本ID31.1)為mp3格式通用標準,由ID3.org所制定的,後來廣會為使用" 。類似的tag還有ID3v2.x,APE,Lyrics3等。

 

Tag包含mp3檔案的一些訊息,包含Tag,Title(歌曲名稱,不是檔名,不同!!),Artist,Album,Year,Comment,Genre(音樂類型,如Rock),以上在Tag中是有順序的。

ID3v1的tag有 128 Bytes,分別為Tag(3 Bytes),Title(30 Bytes),Artist(30 Bytes),Album(30 Bytes),Year(4 Bytes), Comment(30 Bytes),Genre(1 Bytes)

剛好共計128 Bytes。

 

TAG為mp3的tag中前3個Bytes,當程式讀取到tag的前3個Bytes為"TAG"時,表示該mp3的Tag是照ID3V1而寫入的。相反,如果讀取tag前3個Byets,並不是"TAG",則

表示該mp3檔並非以ID3V1的規範寫入,很可能是ID3V2或ID3V2.3,ID3v2.4,2.4為最新版本,2.3為世界廣見的版本,2版則為最早期的版本,目前很少mp3檔採用此標準。

 

TAG後面接著30 Bytes為Title,一般多媒體播放器讀取這30個Bytes,便能秀出歌曲(Title)名稱,接著後面30 Bytes為Artist(演唱此歌曲的歌手名稱),再來為該首mp3發行年分

(4 Bytes),再來為Comment,顧名思義mp3其它訊息可放在這裡(30 Bytes),最後則是Genre(歌曲類型),佔1 Bytes,原先Genre有80種類型,後來Winamp支援到148種。

 

Tag的Comment部分:ID3v1為30 Bytes,ID3v1.1為28 Bytes,第29Byte為固定的Zero Byte(內容為0),第30 Byte為Track Number(此曲目在專輯中的第幾首)。

重點:mp3的tag是寫在mp3檔案的最後面,所以必須從檔案最後面倒退128 Bytes再開始讀取。

附上用UltraEdit開啟mp3檔,ID3v1的內容:

 

 

開始程式部分,部分程式會加上點簡單註解。 :)

--------------------------------------------------------------------------------------------------------

#ifndef  ID3V1_H__
#define ID3V1_H__

#define MP3_TAG_SIZE 128
#define TAG_SIZE 3
#define TITLE_SIZE 30
#define ARTIST_SIZE 30
#define ALBUM_SIZE 30
#define YEAR_SIZE 4
#define COMMENT_SIZE 28
#define ZERO_BYTE 1
#define TRACK_SIZE 1
#define GENRE_SIZE 1

typedef struct
{
   char *tag[TAG_SIZE];
   char *title[TITLE_SIZE]; 
   char *artist[ARTIST_SIZE];
   char *album[ALBUM_SIZE];
   char *year[YEAR_SIZE];
   char *comment[COMMENT_SIZE];  
   unsigned char zero;
   unsigned char trackno;
   unsigned char genre; 
} __attribute__ ((packed))ID3_v1_TAG;

 #endif
-----------------------------------------以上內容寫在id3v1.h-----------------------------------------

將資料結構定義在.h檔在include的好處是,其它隻程式要用到只要include該.h檔便可使用裡面所定義的變數資料結構和函式,如此一來,不用每隻程式都把上面重寫一遍。

接著開始寫.c檔的部分,開始讀取mp3的tag。

-----------------------------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "id3v1.h"

char *genre_list[] =
{
"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
"Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
"Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
"Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient",
"Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical",
"Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
"AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
"Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
"Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
"Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap",
"Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave",
"Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal",
"Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll",
"Hard Rock", "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion",
"Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
"Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock",
"Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour",
"Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony",
"Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club",
"Tango", "Samba", "Folklore", "Ballad","Power Ballad", "Rhythmic Soul",
"Freestyle", "Duet", "Punk Rock", "Drum Solo", "Acapella", "Euro-House",
"Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror",
"Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta",
"Heavy Metal", "Black Metal", "Crossover", "Contemporary C", "Christian Rock",
"Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop", "None"
};


 int main(int argc, char *argv[])
{

ID3_v1_TAG id3v1_tag; //宣告一變數 id3v1_tag,結構為ID3v1_TAG
FILE *fin;
 int i = 0;

char *file_path ="/home/林志玲/Documents/mp3/Always.mp3";//mp3檔路徑,這裡是Linux,如果是Windows,請自行修改
fin = fopen(file_path, "r");

if(fin == NULL)
{
  printf("file path error !!\nfile doesn't exist !!\n");
  return 0;
}

fseek(fin, -MP3_TAG_SIZE ,SEEK_END);//將fin指標移到檔案最後面倒退128 Bytes
fread(&id3v1_tag.tag, 1, TAG_SIZE, fin);//讀取3 Bytes(內容為TAG)
printf("mp3 header:\t%s\n", id3v1_tag.tag);

if(strncmp(id3v1_tag.tag, "TAG", 3) == 1)//判斷讀出來的3 Bytes是否為"TAG"
printf("the file is not mp3 file !\n");
else
{
  fread(&id3v1_tag.title, 1, TITLE_SIZE, fin);//讀Title (30 Bytes)
  fread(&id3v1_tag.artist, 1, ARTIST_SIZE, fin);//讀Artist (30 Bytes)
  fread(&id3v1_tag.album, 1, ALBUM_SIZE, fin);//讀Album (30 Bytes)
  fread(&id3v1_tag.year, 1, YEAR_SIZE, fin);//讀Year (4 Bytes)
  fread(&id3v1_tag.comment, 1, COMMENT_SIZE, fin);//讀 Comment (ID3v1為30 Bytes,ID3v1.1為28 Bytes,剩下兩個Bytes為Zero Byte和TrackNO)
  fread(&id3v1_tag.zero, 1, 1, fin);//讀 Zero Byte (1 Byte)
  fread(&id3v1_tag.trackno, 1, 1, fin);//讀 TrackNO (1 Byte)
  fread(&id3v1_tag.genre, 1, 1, fin);//讀Genre (1 Byte)

printf("mp3 title:\t%s\n", id3v1_tag.title);
printf("mp3 artist:\t%s\n", id3v1_tag.artist);
printf("mp3 album:\t%s\n", id3v1_tag.album);
printf("mp3 year:\t%s\n", id3v1_tag.year);
printf("mp3 comment:\t%s\n", id3v1_tag.comment);
printf("mp3 zero bit:\t%d\n", id3v1_tag.zero);
printf("mp3 track NO.:\t%d\n", id3v1_tag.trackno);

  while(i<sizeof(genre_list)) { //判斷Genre為哪一種類型
if(id3v1_tag.genre == i) {
printf("mp3 genre:\t%s", genre_list[i]);
break;
}
i++;
}
putchar('\n');
}
}

 fclose(fin);

system("PAUSE");    
return 0;
}
---------------------------------------------以上檔案寫在mp3.c---------------------------------------------------------------------------

以上為讀取mp3 Tag訊息的簡單程式,真的很簡單易瞭。其它程式版本作法相同,不需要call 啥API來處理,按照ID3V1.x規範直接讀取內容即可。

上述程式是初學者的程式,之後會更新為較有結構的版本。

接下來會再談到ID3v2.3和ID3v2.4 

 

版權沒有,翻印不究

但是以後工作程式寫不出來,自行負責。

 接受任何批評指教,謝謝! 

arrow
arrow
    全站熱搜

    deh3215 發表在 痞客邦 留言(0) 人氣()