2011年08月03日

ID3タグの読み込み 第1部



今回は、MP3ファイルID3タグを読み込むために、libid3tag-0.15.1bというフリーライブラリを使用してみました。尚libid3tag-0.15.1bの扱いについては、前回のlibid3tagのインストールをご参照ください。




libid3tag-0.15.1bをインクルードするための定義です。

extern "C"
{
#include "..\libid3tag-0.15.1b\id3tag.h"
#include "..\libid3tag-0.15.1b\frametype.h"
}


ID3タグに固有の文字列定義です。

//画像名文字列
static const TCHAR *const pictureName[]={
_T("Other"), _T("32x32 pixels 'file icon' (PNG only)"), _T("Other file icon"),
_T("Cover (front)"), _T("Cover (back)"), _T("Leaflet page"), _T("Media (e.g. lable side of CD)"),
_T("Lead artist/lead performer/soloist"), _T("Artist/performer"), _T("Conductor"),
_T("Band/Orchestra"), _T("Composer"), _T("Lyricist/text writer"), _T("Recording Location"),
_T("During recording"), _T("During performance"), _T("Movie/video screen capture"),
_T("A bright coloured fish"), _T("Illustration"), _T("Band/artist logotype"),
_T("Publisher/Studio logotype")
};

//画像名の数(21)
#define PICTURE_NAME_COUNT ((int)(sizeof(pictureName)/sizeof(const char *const)))

//テキストエンコード文字列
static const TCHAR *const fieldTextEncoding[]={
_T("ISO_8859_1"), //ID3_FIELD_TEXTENCODING_ISO_8859_1 = 0x00
_T("UTF_16"), //ID3_FIELD_TEXTENCODING_UTF_16 = 0x01
_T("UTF_16BE"), //ID3_FIELD_TEXTENCODING_UTF_16BE = 0x02
_T("UTF_8") //ID3_FIELD_TEXTENCODING_UTF_8 = 0x03
};

//タイムスタンプフォーマット文字列
static const TCHAR *const timeStampFormat[]={
_T("MPEG frames as unit"), //0x00
_T("milliseconds as unit") //0x01
};

//内容タイプ文字列
static const TCHAR *const contentType[]={
_T("other"), //0x00
_T("lyrics"), //0x01
_T("text transcription"), //0x02
_T("movement/part name"), //0x03
_T("events"), //0x04
_T("chord"), //0x05
_T("trivia information"), //0x06
_T("URLs to webpages"), //0x07
_T("URLs to images") //0x08
};

//補間法文字列
static const char *const interpolationMethod[]={
_T("Band"), //0x00
_T("Linear") //0x01
};


タグフレーム内指定位置のフィールド値と一致する、文字列情報を取得する__stdcall関数です。

//画像名文字列の取得
BOOL __stdcall _GetPictureName(struct id3_frame const *frame,unsigned int index, CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_INT8);
if ((!field)||(field->type!=ID3_FIELD_TYPE_INT8)) return FALSE;

long int8=::id3_field_getint(field);

ASSERT((int8>=0)&&(int8<PICTURE_NAME_COUNT));
if ((int8<0)||(int8>=PICTURE_NAME_COUNT)) return FALSE;
str=pictureName[int8];
return TRUE;
}

//テキストエンコード文字列の取得
BOOL __stdcall _GetTextEncoding(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_TEXTENCODING);
if ((!field)||(field->type!=ID3_FIELD_TYPE_TEXTENCODING)) return FALSE;

long value=field->number.value;
ASSERT((value>=0)&&(value<=3));
if ((value<0)||(value>3)) return FALSE;
str=fieldTextEncoding[field->number.value];
return TRUE;
}

//タイムスタンプフォーマット文字列の取得
BOOL __stdcall _GetTimeStampFormat(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_INT8);
if ((!field)||(field->type!=ID3_FIELD_TYPE_INT8)) return FALSE;

long int8=::id3_field_getint(field);

ASSERT((int8==1)||(int8==2));
if ((int8!=1)&&(int8!=2)) return FALSE;
str=timeStampFormat[int8-1];
return TRUE;
}

//内容タイプ文字列の取得
BOOL __stdcall _GetContentType(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_INT8);
if ((!field)||(field->type!=ID3_FIELD_TYPE_INT8)) return FALSE;
long int8=::id3_field_getint(field);

ASSERT((int8>=0)&&(int8<=8));
if ((int8<0)&&(int8>8)) return FALSE;
str=contentType[int8];
return TRUE;
}

//補間法文字列の取得
BOOL __stdcall _GetInterpolationMethod(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_INT8);
if ((!field)||(field->type!=ID3_FIELD_TYPE_INT8)) return FALSE;
long int8=::id3_field_getint(field);

ASSERT((int8==0)||(int8==1));
if ((int8<0)||(int8>1)) return FALSE;
str=interpolationMethod[int8];
return TRUE;
}


タグフィールド内の数値や、文字列を取得する__stdcall関数です。

//32ビット整数配列の取得
//エラー時の戻り値:-1

int __stdcall _GetInt32Plus(struct id3_frame const *frame,unsigned int index)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_INT32PLUS);
if ((!field)||(field->type!=ID3_FIELD_TYPE_INT32PLUS)) return -1;

id3_length_t length=field->binary.length;
const id3_byte_t* bin=field->binary.data;
if (length<4) return -1;

DWORD int32=(((DWORD)bin[0])<<24)|(((DWORD)bin[1])<<16)|
(((DWORD)bin[2])<<8)|((DWORD)bin[3]);
return int32;
}

//Latin1文字列の取得
BOOL __stdcall _GetLatin1(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_LATIN1);
if ((!field)||(field->type!=ID3_FIELD_TYPE_LATIN1)) return FALSE;

const id3_latin1_t* latin1=::id3_field_getlatin1(field);
if (!latin1) return FALSE;

#ifdef _UNICODE
CStringA strA=(char*)latin1;
str=strA;
#else//_UNICODE
str=(char*)latin1;
#endif//_UNICODE

return TRUE;
}

//Latin1List文字列の取得
BOOL __stdcall _GetLatin1List(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_LATIN1LIST);
if ((!field)||(field->type!=ID3_FIELD_TYPE_LATIN1LIST)||
(!field->latin1list.nstrings)) return FALSE;
if (!latin1) return FALSE;

#ifdef _UNICODE
CStringA strA=(char*)latin1;
str=strA;
#else//_UNICODE
str=(char*)latin1;
#endif//_UNICODE

return TRUE;
}

//String文字列の取得
BOOL __stdcall _GetString(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_STRING);

if ((!field)||(field->type!=ID3_FIELD_TYPE_STRING)) return FALSE;

const id3_ucs4_t* ucs4=::id3_field_getstring(field);
if (!ucs4) return FALSE;

id3_utf16_t* utf16=::id3_ucs4_utf16duplicate(ucs4);
str=utf16;
::free(utf16);

return TRUE;
}

//StringFull文字列の取得
BOOL __stdcall _GetStringFull(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_STRINGFULL);
if ((!field)||(field->type!=ID3_FIELD_TYPE_STRINGFULL)) return FALSE;

const id3_ucs4_t* ucs4=::id3_field_getfullstring(field);
if (!ucs4) return FALSE;

id3_utf16_t* utf16=::id3_ucs4_utf16duplicate(ucs4);
str=utf16;
::free(utf16);

return TRUE;
}

//StringList文字列の取得
BOOL __stdcall _GetStringList(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_STRINGLIST);
if ((!field)||(field->type!=ID3_FIELD_TYPE_STRINGLIST)) return FALSE;

const id3_ucs4_t* ucs4=::id3_field_getstrings(field,0);
if (!ucs4) return FALSE;

id3_utf16_t* utf16=::id3_ucs4_utf16duplicate(ucs4);
str=utf16;
::free(utf16);

return TRUE;
}

//Binaryデータダンプ文字列の取得
BOOL __stdcall _GetBinaryDump(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_BINARYDATA);
if ((!field)||(field->type!=ID3_FIELD_TYPE_BINARYDATA)) return FALSE;

id3_length_t length;
const id3_byte_t* bin=::id3_field_getbinarydata(field,&length);

for(UINT i=0;i<length;i++)
str.AppendFormat("%02X ",bin[i]);

return TRUE;
}


//Binaryデータ文字列の取得
BOOL __stdcall _GetBinaryText(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_BINARYDATA);
if ((!field)||(field->type!=ID3_FIELD_TYPE_BINARYDATA)) return FALSE;

id3_length_t length;
const id3_byte_t* bin=::id3_field_getbinarydata(field,&length);

for(UINT i=0;i<length;i++)
str.AppendChar(bin[i]);

return TRUE;
}

//言語テキストの取得
BOOL __stdcall _GetLanguage(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_LANGUAGE);
if ((!field)||(field->type!=ID3_FIELD_TYPE_LANGUAGE)) return FALSE;

#ifdef _UNICODE
CStringA strA=field->immediate.value;
str=strA;
#else//_UNICODE
str=field->immediate.value;
#endif//_UNICODE

return TRUE;
}

//フレームIDの取得
BOOL __stdcall _GetFrameID(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_FRAMEID);
if ((!field)||(field->type!=ID3_FIELD_TYPE_FRAMEID)) return FALSE;

#ifdef _UNICODE
CStringA strA=field->immediate.value;
str=strA;
#else//_UNICODE
str=field->immediate.value;
#endif//_UNICODE

return TRUE;
}

//DATEの取得
BOOL __stdcall _GetDate(struct id3_frame const *frame,unsigned int index,CString& str)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->type==ID3_FIELD_TYPE_DATE);
if ((!field)||(field->type!=ID3_FIELD_TYPE_DATE)) return FALSE;

#ifdef _UNICODE
CStringA strA=field->immediate.value;
str=strA;
#else//_UNICODE
str=field->immediate.value;
#endif//_UNICODE
str=field->immediate.value;

return TRUE;
}

//イメージデータの取得
BOOL __stdcall _GetImageData(struct id3_frame const *frame,unsigned int index,CMemFile& infile)
{
union id3_field* field=::id3_frame_field(frame,index);

ASSERT(field);
ASSERT(field->binary.type==ID3_FIELD_TYPE_BINARYDATA);
if ((!field)||(field->binary.type!=ID3_FIELD_TYPE_BINARYDATA)) return FALSE;

UINT length=field->binary.length;
BYTE* data=field->binary.data;
if ((!length)||(!data)) return FALSE;
infile.Attach(data,length);
return TRUE;
}


//バージョン文字列の取得
BOOL __stdcall _GetTagVersion(id3_tag *tag,CString& str)
{
ASSERT(tag);
if (!tag) return FALSE;
UINT version=::id3_tag_version(tag);
BYTE versionHi=ID3_TAG_VERSION_MAJOR(version);
BYTE versionLo=ID3_TAG_VERSION_MINOR(version);
if (versionHi==1) str.Format(_T("id3v1.%d"),versionLo);
else str.Format(_T("id3v2.%d.%d"),versionHi,versionLo);
return TRUE;
}


libid3tagライブラリーを使いやすくするため、CID3Fileクラスを独自に定義しました。


typedef struct id3_file id3_file;
typedef struct id3_tag id3_tag;
typedef struct id3_frame;

class CID3File : public CObject
{
public:
//コンストラクタ
CID3File(const char* lpszFileName=NULL);
//デストラクタ
virtual ~CID3File();
//メンバー変数の初期化
void Init();
//メンバー変数の削除
void Delete();
//id3タグの生データから、その内容を解析します。
unsigned int Parse(BYTE* data,DWORD memSize);
//読み込んだタグのフレーム数を取得します。
unsigned int GetFrameCount();
//指定FrameIDと同じフレームを探して、フレーム番号を返します。(エラー時:-1)
int FindFrame(const char* FrameID);
//指定位置のフレームの内容を、メンバー変数文字列に書き出します。
BOOL GetFrame(UINT indexFrame);
//メンバー変数文字列を、指定位置のフレームに書き込みます。
BOOL SetFrame(UINT indexFrame);
//新規ID3タグの作成
BOOL TagNew();
//新規フレームの挿入
// indexFrame<0:末尾に追加します。

BOOL InsertFrameNew(int indexFrame,const char* FrameID);
//指定フレームの挿入
// indexFrame<0:末尾に追加します。

BOOL InsertFrame(int indexFrame,id3_frame* frame);
//現在のID3タグから指定番号のフレームを抜き出します。
id3_frame* DetachFrame(UINT indexFrame);
//フレームの削除
BOOL DeleteFrame(UINT indexFrame);
//画像をファイルから読み込みます。
BOOL LoadImage(LPCTSTR lpszPathName);
//id3タグの内容をファイルまたは指定CByteArrayクラスに更新します。
BOOL Update(CByteArray* pByteArray);
//現在のID3タグのバージョンの取得
BOOL TagVersion(CString& strVersion);
//現在のID3タグのバージョンを変更します。
BOOL SetTagVersion(CString& strVersion);

private:
id3_file* m_file; //読み込んだファイル構造体へのポインタ。
id3_tag* m_id3tag; //読み込んだid3タグへのポインタ。
public:
//フレーム毎のデータ
CString m_strTitle; //フレーム名
CString m_strID; //フレームID
CString m_strBinary; //バイナリーデータ
CString m_strDesc; //フレーム見出し
CString m_strText; //フレームテキスト
CString m_strImmediate; //テキストの言語/属性
CString m_strTextEnc; //テキストのエンコード
CString m_strVersion; //フレームのバージョン
CString m_strTimeStamp; //タイムスタンプフォーマット
CString m_strPictureName; //画像名

CMemFile m_memfileImage; //画像データのメモリーファイル
private:
CByteArray m_arrayImage; //画像データ書き込み用バッファ
};


CID3Fileクラスのコンストラクタ/デストラクタです。

//コンストラクタ
CID3File::CID3File(const char* lpszFileName)
{
Init();
//ファイル名があれば、ファイルからタグを読みます。
if (lpszFileName){
m_file=::id3_file_open(lpszFileName,ID3_FILE_MODE_READWRITE);
m_id3tag=id3_file_tag(m_file);
}
}

//デストラクタ
CID3File::~CID3File()
{
Delete();
}


CID3Fileクラスのメンバ関数です。

//メンバー変数の初期化
void CID3File::Init()
{
m_id3tag=0;
m_file=0;
}

//メンバー変数の削除
void CID3File::Delete()
{
//ファイルから読み込んだ場合。
if (m_file)
::id3_file_close(m_file);
//id3タグの生データから読み込んだ場合。
else if (m_id3tag)
::id3_tag_delete(m_id3tag);

m_memfileImage.Detach();
m_memfileImage.Close();
Init();
}

//MP3ファイル等から直接読み込んだID3タグの生データから、
その内容を解析してid3_tag構造体を作成し、タグ内にあるフレーム数を返します。

unsigned int CID3File::Parse(BYTE* data,DWORD memSize)
{
ASSERT(AfxIsValidAddress(data,memSize,FALSE));
if (!AfxIsValidAddress(data,memSize,FALSE)) return FALSE;

//メンバー変数を削除します。
Delete();

//生データの内容を解析して、タグを作成します。
m_id3tag=::id3_tag_parse(data,memSize);
if (!m_id3tag) return FALSE;

//フレーム数を返して、終了します。
return GetFrameCount();
}

//読み込んだタグのフレーム数を取得します。
unsigned int CID3File::GetFrameCount()
{
return (m_id3tag)?m_id3tag->nframes:0;
}

//指定FrameIDと同じフレームを探して、フレーム番号を返します。(エラー時:-1)
int CID3File::FindFrame(const char* FrameID)
{
int nCount=GetFrameCount();
for (int i=0;i<nCount;i++){
//指定番号に該当する、フレームへのポインタを取得します。
struct id3_frame* frame=::id3_tag_findframe(m_id3tag,NULL,i);
if ((frame)&&(::memcmp(frame->id,FrameID,4)==0))
return i;
}
return -1;
}

//現在のID3タグのバージョンの取得
BOOL CID3File::TagVersion(CString& strVersion)
{
return _GetTagVersion(m_id3tag,strVersion);
}




<<libid3tagのインストールページの先頭ID3タグの読み込み 第2部>>




posted by ひろし at 13:05| Comment(0) | MP3ファイルフォーマット | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。