#include #include #define GET_TL_TAG(self,tag) \ taglib_t *tl; \ Data_Get_Struct(self, taglib_t, tl); \ if(NULL==tl->file || tl->open==0) {tl_closed();} \ TagLib_Tag *tag=tl->tag; #define GET_TL_CHECK(self,file) \ taglib_t *tl; \ Data_Get_Struct(self, taglib_t, tl); \ if(NULL==tl->file || tl->open==0) {tl_closed();} \ TagLib_File *file=tl->file; typedef struct { TagLib_File *file; TagLib_Tag *tag; const TagLib_AudioProperties *audio; int open; } taglib_t; void tl_closed() { rb_raise(rb_eException, "FileTag already closed"); } static void _tag_lib_file_free(taglib_t * t) { taglib_file_free(t->file); free(t); } VALUE mTagFile; VALUE cTagFileFile; VALUE eBadPath; VALUE eBadFile; VALUE eBadTag; VALUE eBadAudioProperties; VALUE cTagFileFile_new(int argc, VALUE * argv, VALUE class); VALUE cTagFileFile_close(VALUE self); VALUE cTagFileFile_save(VALUE self); VALUE cTagFileFile_init(VALUE self, VALUE path, VALUE file_type); VALUE cTagFileFile_title(VALUE self); VALUE cTagFileFile_artist(VALUE self); VALUE cTagFileFile_album(VALUE self); VALUE cTagFileFile_comment(VALUE self); VALUE cTagFileFile_genre(VALUE self); VALUE cTagFileFile_year(VALUE self); VALUE cTagFileFile_track(VALUE self); VALUE cTagFileFile_title_set(VALUE self, VALUE valor); VALUE cTagFileFile_artist_set(VALUE self, VALUE valor); VALUE cTagFileFile_album_set(VALUE self, VALUE valor); VALUE cTagFileFile_comment_set(VALUE self, VALUE valor); VALUE cTagFileFile_genre_set(VALUE self, VALUE valor); VALUE cTagFileFile_year_set(VALUE self, VALUE valor); VALUE cTagFileFile_track_set(VALUE self, VALUE valor); VALUE cTagFileFile_length(VALUE self); VALUE cTagFileFile_bitrate(VALUE self); VALUE cTagFileFile_samplerate(VALUE self); VALUE cTagFileFile_channels(VALUE self); void Init_rtaglib() { mTagFile = rb_define_module("TagFile"); cTagFileFile = rb_define_class_under(mTagFile, "File", rb_cObject); eBadPath = rb_define_class_under(mTagFile, "BadPath", rb_eIOError); eBadFile = rb_define_class_under(mTagFile, "BadFile", rb_eException); eBadTag = rb_define_class_under(mTagFile, "BadTag", rb_eException); eBadAudioProperties = rb_define_class_under(mTagFile, "BadAudioProperties", rb_eException); rb_define_singleton_method(cTagFileFile, "new", cTagFileFile_new, -1); rb_define_method(cTagFileFile, "initialize", cTagFileFile_init, 2); rb_define_method(cTagFileFile, "save", cTagFileFile_save, 0); rb_define_method(cTagFileFile, "close", cTagFileFile_close, 0); struct { const char *name; VALUE(*func) (); int args; } instance_methods[] = { { "title", cTagFileFile_title, 0}, { "title=", cTagFileFile_title_set, 1}, { "artist", cTagFileFile_artist, 0}, { "artist=", cTagFileFile_artist_set, 1}, { "album", cTagFileFile_album, 0}, { "album=", cTagFileFile_album_set, 1}, { "comment", cTagFileFile_comment, 0}, { "comment=", cTagFileFile_comment_set, 1}, { "genre", cTagFileFile_genre, 0}, { "genre=", cTagFileFile_genre_set, 1}, { "track", cTagFileFile_track, 0}, { "track=", cTagFileFile_track_set, 1}, { "year", cTagFileFile_year, 0}, { "year=", cTagFileFile_year_set, 1}, { "length", cTagFileFile_length, 0}, { "bitrate", cTagFileFile_bitrate, 0}, { "samplerate", cTagFileFile_samplerate, 0}, { "channels", cTagFileFile_channels, 0}, { 0, NULL, 0} }; int i = 0; for (i = 0; instance_methods[i].name; i++) { rb_define_method(cTagFileFile, instance_methods[i].name, instance_methods[i].func, instance_methods[i].args); } rb_define_attr(cTagFileFile, "path", 1, 0); rb_define_attr(cTagFileFile, "file_type", 1, 0); rb_define_const(mTagFile, "MPEG", INT2FIX(TagLib_File_MPEG)); rb_define_const(mTagFile, "OggVorbis", INT2FIX(TagLib_File_OggVorbis)); rb_define_const(mTagFile, "FLAC", INT2FIX(TagLib_File_FLAC)); rb_define_const(mTagFile, "MPC", INT2FIX(TagLib_File_MPC)); } VALUE cTagFileFile_new(int argc, VALUE * argv, VALUE class) { TagLib_File *tlf; VALUE path; VALUE file_type; char *cpath; rb_scan_args(argc, argv, "11", &path, &file_type); Check_Type(path, T_STRING); SafeStringValue(path); cpath = StringValuePtr(path); if (file_type != Qnil) { FIXNUM_P(file_type); tlf = taglib_file_new_type(cpath, FIX2INT(file_type)); } else { tlf = taglib_file_new(cpath); } if (NULL == tlf) { rb_raise(eBadFile, "Bad file"); return Qnil; } else { taglib_t *tl = ALLOC(taglib_t); tl->file = tlf; tl->tag = taglib_file_tag(tlf); tl->open = 1; if (NULL == tl->tag) { rb_raise(eBadTag, "Bad Tag"); } tl->audio = taglib_file_audioproperties(tlf); if (NULL == tl->tag) { rb_raise(eBadAudioProperties, "Bad Audio"); } VALUE c_argv[2]; VALUE tdata = Data_Wrap_Struct(class, 0, _tag_lib_file_free, tl); c_argv[0] = path; c_argv[1] = file_type; rb_obj_call_init(tdata, 2, c_argv); return tdata; } } VALUE cTagFileFile_init(VALUE self, VALUE path, VALUE file_type) { Check_Type(path, T_STRING); rb_iv_set(self, "@path", path); rb_iv_set(self, "@file_type", file_type); return self; } VALUE cTagFileFile_save(VALUE self) { GET_TL_CHECK(self, file); return (taglib_file_save(file) ? Qtrue : Qfalse); } VALUE cTagFileFile_close(VALUE self) { taglib_t *tl; Data_Get_Struct(self, taglib_t, tl); tl->open = 0; // taglib_file_free(tl->file); rb_iv_set(self, "@path", Qnil); rb_iv_set(self, "@file_type", Qnil); return Qtrue; } VALUE _get_string(VALUE self, char *(*func) ()) { VALUE string; GET_TL_TAG(self, tag); char *cstring = func(tag); string = rb_str_new2(cstring); taglib_tag_free_strings(); return string; } VALUE _get_uint(VALUE self, unsigned int (*func) ()) { GET_TL_TAG(self, tag); return INT2FIX(func(tag)); } VALUE _get_audio_int(VALUE self, int (*func) ()) { VALUE string; taglib_t *tl; Data_Get_Struct(self, taglib_t, tl); if (NULL == tl->file) { return Qnil; } else { return INT2FIX(func(tl->audio)); } } VALUE _set_string(VALUE self, void (*func) (TagLib_Tag *, const char *), VALUE texto) { VALUE string; taglib_t *tl; Data_Get_Struct(self, taglib_t, tl); if (NULL == tl) { return Qnil; } else { Check_Type(texto, T_STRING); func(tl->tag, StringValuePtr(texto)); return Qtrue; } } VALUE _set_uint(VALUE self, void (*func) (TagLib_Tag *, unsigned int), VALUE numero) { VALUE string; taglib_t *tl; Data_Get_Struct(self, taglib_t, tl); if (NULL == tl) { return Qnil; } else { FIXNUM_P(numero); func(tl->tag, FIX2INT(numero)); return Qtrue; } } VALUE cTagFileFile_title(VALUE self) { return _get_string(self, taglib_tag_title); } VALUE cTagFileFile_artist(VALUE self) { return _get_string(self, taglib_tag_artist); } VALUE cTagFileFile_album(VALUE self) { return _get_string(self, taglib_tag_album); } VALUE cTagFileFile_comment(VALUE self) { return _get_string(self, taglib_tag_comment); } VALUE cTagFileFile_genre(VALUE self) { return _get_string(self, taglib_tag_genre); } VALUE cTagFileFile_year(VALUE self) { return _get_uint(self, taglib_tag_year); } VALUE cTagFileFile_track(VALUE self) { return _get_uint(self, taglib_tag_track); } VALUE cTagFileFile_title_set(VALUE self, VALUE valor) { return _set_string(self, taglib_tag_set_title, valor); } VALUE cTagFileFile_artist_set(VALUE self, VALUE valor) { return _set_string(self, taglib_tag_set_artist, valor); } VALUE cTagFileFile_album_set(VALUE self, VALUE valor) { return _set_string(self, taglib_tag_set_album, valor); } VALUE cTagFileFile_comment_set(VALUE self, VALUE valor) { return _set_string(self, taglib_tag_set_comment, valor); } VALUE cTagFileFile_genre_set(VALUE self, VALUE valor) { return _set_string(self, taglib_tag_set_genre, valor); } VALUE cTagFileFile_year_set(VALUE self, VALUE valor) { return _set_uint(self, taglib_tag_set_year, valor); } VALUE cTagFileFile_track_set(VALUE self, VALUE valor) { return _set_uint(self, taglib_tag_set_track, valor); } VALUE cTagFileFile_length(VALUE self) { return _get_audio_int(self, taglib_audioproperties_length); } VALUE cTagFileFile_bitrate(VALUE self) { return _get_audio_int(self, taglib_audioproperties_bitrate); } VALUE cTagFileFile_samplerate(VALUE self) { return _get_audio_int(self, taglib_audioproperties_samplerate); } VALUE cTagFileFile_channels(VALUE self) { return _get_audio_int(self, taglib_audioproperties_channels); }