FC2ブログ

ホーム > MP3ファイルフォーマット > ID3タグの書き込み 第1部

ID3タグの書き込み 第1部



今回は、ID3タグ編集用ライブラリ「libid3tag-0.15.1b」を使用して、ID3タグMP3ファイルに書き込む方法を解説します。尚ID3タグ編集用ライブラリ「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タグ編集用ライブラリ「libid3tag-0.15.1b」には、latin1list文字列を書き込む関数がないので、自作した関数をライブラリーファイルに追加しました。

「field.c」の622行目に、下記のid3_field_setlatin1list関数を追加して下さい。

/*
* NAME: field->setlatin1list()
* DESCRIPTION: set the value of a latin1list field
*/

int id3_field_setlatin1list(union id3_field *field,
unsigned int length, id3_latin1_t **ptrs)
{
id3_latin1_t **strings;
unsigned int i;

assert(field);

if (field->type != ID3_FIELD_TYPE_LATIN1LIST)
return -1;

id3_field_finish(field);

if (length == 0)
return 0;

strings = malloc(length * sizeof(*strings));
if (strings == 0)
return -1;

for (i = 0; i < length; ++i) {
strings[i] = id3_latin1_duplicate(ptrs[i]);
if (strings[i] == 0) {
while (i--)
free(strings[i]);

free(strings);
return -1;
}
}

field->latin1list.strings = strings;
field->latin1list.nstrings = length;

return 0;
}


「id3tag.h」の301行目に、id3_field_setlatin1list関数のプロトタイプの追加を追加して下さい。

int id3_field_setlatin1list(union id3_field *, unsigned int, id3_latin1_t **);


タグフレーム内指定位置のフィールドに、文字列情報に対応する値を書き込む__stdcall関数です。

//画像名文字列の設定
BOOL __stdcall _SetPictureName(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;

int res=-1;
for(int i=0;i<PICTURE_NAME_COUNT;i++){
if (str==pictureName[i]){
res=::id3_field_setint(field,i);
break;
}
}
if (res!=0) return FALSE;
return TRUE;
}

//テキストエンコード文字列の設定
BOOL __stdcall _SetTextEncoding(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;

int res=-1;
for (int i=0;i<4;i++){
if (str==fieldTextEncoding[i]){
res=::id3_field_settextencoding(field,(enum id3_field_textencoding)i);
break;
}
}
if (res!=0) return FALSE;
return TRUE;
}

//内容タイプ文字列の設定
BOOL __stdcall _SetContentType(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;

int res=-1;
for(int i=0;i<9;i++){
if (str==contentType[i]){
res=::id3_field_setint(field,i);
break;
}
}
if (res!=0) return FALSE;
return TRUE;
}

//タイムスタンプフォーマット文字列の設定
BOOL __stdcall _SetTimeStampFormat(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;

int res=-1;
for(int i=0;i<2;i++){
if (str==timeStampFormat[i]){
res=::id3_field_setint(field,i+1);
break;
}
}
if (res!=0) return FALSE;
return TRUE;
}

//補間法文字列の設定
BOOL __stdcall _SetInterpolationMethod(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;

int res=-1;
for(int i=0;i<2;i++){
if (str==interpolationMethod[i]){
res=::id3_field_setint(field,i);
break;
}
}
if (res!=0) return FALSE;
return TRUE;
}


タグフレーム内指定位置のフィールドに数値や、文字列を書き込む__stdcall関数です。

//32ビット整数配列の取得
BOOL __stdcall _SetInt32Plus(struct id3_frame const *frame,unsigned int index,signed long number)
{
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 FALSE;

BYTE data[4]={0};
data[0]=(BYTE)(number>>24);
data[1]=(BYTE)(number>>16);
data[2]=(BYTE)(number>>8);
data[3]=(BYTE)number;
int res=::id3_field_setbinarydata(field,(const id3_byte_t*)&data,4);
if (res!=0) return FALSE;
return TRUE;
}

//Latin1文字列の設定
BOOL __stdcall _SetLatin1(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;

#ifdef _UNICODE
CStringA strA=(CStringA)str;
int res=::id3_field_setlatin1(field,(const id3_latin1_t*)strA.GetBuffer());
#else//_UNICODE
int res=::id3_field_setlatin1(field,(const id3_latin1_t*)str.GetBuffer());
#endif//_UNICODE

if (res!=0) return FALSE;
return TRUE;
}

//Latin1List文字列の設定
BOOL __stdcall _SetLatin1List(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)) return FALSE;

#ifdef _UNICODE
CStringA strA=(CStringA)str;
id3_latin1_t* latin1=(id3_latin1_t*)strA.GetBuffer();
#else//_UNICODE
id3_latin1_t* latin1=(id3_latin1_t*)str.GetBuffer();
#endif//_UNICODE
int res=::id3_field_setlatin1list(field,1,&latin1);

if (res!=0) return FALSE;
return TRUE;
}

//String文字列の設定
BOOL __stdcall _SetString(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;

#ifdef _UNICODE
id3_ucs4_t* ucs4=::id3_utf16_ucs4duplicate((const id3_utf16_t*)str.GetBuffer());
#else//_UNICODE
CStringW strW=(CStringW)str;
id3_ucs4_t* ucs4=::id3_utf16_ucs4duplicate((const id3_utf16_t*)strW.GetBuffer());
#endif//_UNICODE
int res=::id3_field_setstring(field,ucs4);
::free(ucs4);

if (res!=0) return FALSE;
return TRUE;
}

//StringFull文字列の設定
BOOL __stdcall _SetStringFull(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;

#ifdef _UNICODE
id3_ucs4_t* ucs4=::id3_utf16_ucs4duplicate((const id3_utf16_t*)str.GetBuffer());
#else//_UNICODE
CStringW strW=(CStringW)str;
id3_ucs4_t* ucs4=::id3_utf16_ucs4duplicate((const id3_utf16_t*)strW.GetBuffer());
#endif//_UNICODE
int res=::id3_field_setfullstring(field,ucs4);
::free(ucs4);

if (res!=0) return FALSE;
return TRUE;
}

//StringList文字列の設定
BOOL __stdcall _SetStringList(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;

#ifdef _UNICODE
id3_ucs4_t* ucs4=::id3_utf16_ucs4duplicate((const id3_utf16_t*)str.GetBuffer());
#else//_UNICODE
CStringW strW=(CStringW)str;
id3_ucs4_t* ucs4=::id3_utf16_ucs4duplicate((const id3_utf16_t*)strW.GetBuffer());
#endif//_UNICODE
int res=::id3_field_setstrings(field,1,&ucs4);
::free(ucs4);
if (res!=0) return FALSE;
return TRUE;
}

//Binaryデータダンプ文字列の設定
BOOL __stdcall _SetBinaryDump(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=(id3_length_t)(str.GetLength()/3);
CByteArray arrayBin;
arrayBin.SetSize(length);
PBYTE binary=arrayBin.GetData();
PBYTE dst=binary;

TCHAR tszHex[]=_T("0x00");
LPTSTR pch=str.GetBuffer();
for (UINT i=0;i<length;i++){
tszHex[2]=*pch++;
tszHex[3]=*pch++;
pch++;
DWORD bin=0;
_stscanf(tszHex,_T("%X"),&bin);
*dst++=(BYTE)bin;
}
int res=::id3_field_setbinarydata(field,binary,length);
if (res!=0) return FALSE;
return TRUE;
}

//Binaryデータ文字列の設定
BOOL __stdcall _SetBinaryText(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=(id3_length_t)str.GetLength();
CByteArray arrayBin;
arrayBin.SetSize(length);
PBYTE binary=arrayBin.GetData();
PBYTE dst=binary;

#ifdef _UNICODE
CStringA strA=(CStringA)str;
char* pch=strA.GetBuffer();
#else//_UNICODE
char* pch=str.GetBuffer();
#endif//_UNICODE
for (UINT i=0;i<length;i++)
*dst++=(BYTE)*pch++;

int res=::id3_field_setbinarydata(field,binary,length);
if (res!=0) return FALSE;
return TRUE;
}

//言語テキストの設定
BOOL __stdcall _SetLanguage(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=(CStringA)str;
int res=::id3_field_setlanguage(field,strA.GetBuffer());
#else//_UNICODE
int res=::id3_field_setlanguage(field,str.GetBuffer());
#endif//_UNICODE

if (res!=0) return FALSE;
return TRUE;
}

//フレームIDの設定
BOOL __stdcall _SetFrameID(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=(CStringA)str;
int res=::id3_field_setframeid(field,strA.GetBuffer());
#else//_UNICODE
int res=::id3_field_setframeid(field,str.GetBuffer());
#endif//_UNICODE

if (res!=0) return FALSE;
return TRUE;
}

//DATEの設定
BOOL __stdcall _SetDate(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)) returnFALSE;
::ZeroMemory(field->immediate.value, sizeof(field->immediate.value));

#ifdef _UNICODE
CStringA strA=(CStringA)str;
::lstrcpynA(field->immediate.value,strA.GetBuffer(),9);
#else//_UNICODE
::lstrcpynA(field->immediate.value,str.GetBuffer(),9);
#endif//_UNICODE

return TRUE;
}

//イメージデータの設定
BOOL __stdcall _SetImageData(struct id3_frame const *frame,unsigned int index,CMemFile& outfile)
{
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=(ULONG)outfile.GetLength();
if (!length) return FALSE;
BYTE* data=outfile.Detach();
if (!data) return FALSE;
outfile.Attach(data,length);
if (data==field->binary.data) return TRUE;

int res=::id3_field_setbinarydata(field,data,length);
if (res!=0) return FALSE;
return TRUE;
}

//バージョン文字列の設定
BOOL __stdcall _SetTagVersion(id3_tag *tag,CString& str)
{
ASSERT(tag);
if (!tag) return FALSE;

DWORD versionHi=0;
DWORD versionLo=0;
sscanf(str.GetBuffer(),"ID3v%d.%d",&versionHi,&versionLo);
//ID3v1に変更する場合。
if (versionHi==1){
tag->version=((versionHi&0xff)<<8)|(versionLo&0xff);
tag->options|=ID3_TAG_OPTION_ID3V1;
tag->options&=~ID3_TAG_OPTION_COMPRESSION;
tag->restrictions=ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 |
ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS;
}
//ID3v2に変更する場合。
else{
sscanf(str.GetBuffer(),"ID3v2.%d.%d",&versionHi,&versionLo);
tag->version=((versionHi&0xff)<<8)|(versionLo&0xff);
tag->options&=~ID3_TAG_OPTION_ID3V1;
tag->options|=ID3_TAG_OPTION_COMPRESSION;
tag->restrictions=0;
}
return TRUE;
}


ID3タグを編集及び書き込むのためのCID3Fileクラスのメンバー関数です。

//新規ID3タグの作成
BOOL CID3File::TagNew()
{
//ファイルから読み込んだ場合。
if (m_file) ::id3_file_close(m_file);
//id3タグの生データから読み込んだ場合。
else if (m_id3tag) ::id3_tag_delete(m_id3tag);
m_id3tag=0;
m_file=0;

//新規にID3タグを作成します。
struct id3_tag *tag=::id3_tag_new();
if (!tag) return FALSE;

m_id3tag=tag;
return TRUE;
}

//新規フレームの挿入
// indexFrame<0:末尾に追加します。

BOOL CID3File::InsertFrameNew(int indexFrame,const char* FrameID)
{
//引数のFrameIDを元に新規フレームを作成します。
id3_frame* frame=::id3_frame_new(FrameID);
if (!frame) return FALSE;
if (!InsertFrame(indexFrame,frame)){
::id3_frame_delete(frame);
return FALSE;
}
return TRUE;
}

//指定フレームの挿入
// indexFrame<0:末尾に追加します。

BOOL CID3File::InsertFrame(int indexFrame,id3_frame* frame)
{
//指定フレームをタグ末尾に追加します。
int res=::id3_tag_attachframe(m_id3tag,frame);
if (res!=0) return FALSE;
//フレーム番号がフレーム数の範囲内なら、
//新規フレームが正しい位置に来るように並び替えます。

if ((indexFrame>=0)&&(indexFrame<(int)m_id3tag->nframes)){
for (int i=m_id3tag->nframes-1;i>indexFrame;i--)
m_id3tag->frames[i]=m_id3tag->frames[i-1];
m_id3tag->frames[indexFrame]=frame;
}
return TRUE;
}

//現在のID3タグから指定番号のフレームを抜き出します。
id3_frame* CID3File::DetachFrame(UINT indexFrame)
{
//指定番号のフレームを探します。
struct id3_frame* frame=::id3_tag_findframe(m_id3tag,NULL,indexFrame);
if (!frame) return FALSE;

//フレームをタグから切り離します。
int res=::id3_tag_detachframe(m_id3tag,frame);
if (res!=0) return FALSE;
//タグにフレームが一つもない場合は、メンバー変数をすべて削除します。
if (!GetFrameCount()) Delete();
return frame;
}

//フレームの削除
BOOL CID3File::DeleteFrame(UINT indexFrame)
{
id3_frame* frame=DetachFrame(indexFrame);
if (!frame) return FALSE;

//フレームを削除します。
::id3_frame_delete(frame);
return TRUE;
}

//現在のID3タグのバージョンを変更します。
BOOL CID3File::SetTagVersion(CString& strVersion)
{
return _SetTagVersion(m_id3tag,strVersion);
}


<<ID3タグの読み込み 第3部ページの先頭ID3タグの書き込み 第2部>>



スポンサーサイト



コメント: 0

この記事へのコメント
ブログ著者にのみ知らせます。

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/59-d9f44adb
Listed below are links to weblogs that reference
ID3タグの書き込み 第1部 from マルチメディアファイルフォーマット

Home > MP3ファイルフォーマット > ID3タグの書き込み 第1部

タグクラウド
ブロとも申請フォーム

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る