cosmetix
[taglib.d.git] / taglib.d
blob1d53c68254a8418710662064250f27ee1b416a63
1 ///WARING! this MAY BE 64-bit unsafe!
2 module taglib;
4 pragma(lib, "tag_c");
5 pragma(lib, "tag");
8 ////////////////////////////////////////////////////////////////////////////////
9 import std.conv;
10 import std.string;
13 class TagLibException : Exception {
14 @safe pure nothrow this (string msg, string file=__FILE__, size_t line=__LINE__, Throwable next=null) {
15 super(msg, file, line, next);
20 struct TagFile {
21 enum FileType {
22 Autodetect=-1, // k8 extension, do not use in C API!
23 MPEG,
24 OggVorbis,
25 FLAC,
26 MPC,
27 OggFlac,
28 WavPack,
29 Speex,
30 TrueAudio,
31 MP4,
32 ASF
36 this (string fname, FileType type=FileType.Autodetect) {
37 loadInfo(fname, type);
40 ~this () {
41 clear();
44 void clear () {
45 if (mInited) {
46 mInited = false;
47 taglib_file_free(mFL);
48 mFL = null;
49 mTags = null;
50 mFName = mArtist = mAlbum = mTitle = mComment = mGenre = null;
51 mYear = mTrack = 0;
55 void save () {
56 if (!mInited) throw new TagLibException("can't save tags object to empty file");
57 if (!taglib_file_save(mFL)) throw new TagLibException("can't save tags object to file '"~mFName~"'");
60 @property bool valid () const nothrow { return mInited; }
62 @property string filename () const nothrow { return (mInited ? mFName : null); }
64 mixin(strPropMixin("artist"));
65 mixin(strPropMixin("album"));
66 mixin(strPropMixin("title"));
67 mixin(strPropMixin("genre"));
68 mixin(strPropMixin("comment"));
70 @property uint year () const nothrow { return (mInited ? mYear : 0); }
71 @property void year (uint v) {
72 if (!mInited) throw new TagLibException("can't set YEAR tag for empty file");
73 if (v > 0) {
74 uint ov;
75 if (v < 50) v += 2000;
76 else if (v < 100) v += 1900;
77 else if (v < 1930) v = 0;
78 if (v < 1930 || v > 2099) throw new TagLibException("invalid YEAR tag value: "~to!string(ov));
80 mYear = v;
81 taglib_tag_set_year(mTags, v);
84 @property uint track () const nothrow { return (mInited ? mTrack : 0); }
85 @property void track (uint v) {
86 if (!mInited) throw new TagLibException("can't set TRACK tag for empty file");
87 if (v > 999) throw new TagLibException("invalid TRACK tag value: "~to!string(v));
88 mTrack = v;
89 taglib_tag_set_track(mTags, v);
92 mixin(uintPropMixin("length")); // file length in seconds
93 mixin(uintPropMixin("channels")); // number of channels in file
94 mixin(uintPropMixin("bitrate")); // file bitrate in kb/s
95 mixin(uintPropMixin("samplerate")); // file samplerate in Hz
97 private:
98 static uintPropMixin (string propName) {
99 return
100 `@property uint `~propName~` () {`~
101 `if (!mInited) return 0;`~
102 `auto tp = taglib_file_audioproperties(mFL);`~
103 `if (!tp) throw new TagLibException("can't get audio properties for file '"~mFName~"'");`~
104 `auto r = taglib_audioproperties_`~propName~`(tp);`~
105 `return (r < 0 ? 0 : r);`~
106 `}`;
109 static strPropMixin (string propName) {
110 import std.string;
111 return
112 `@property void `~propName~` (string v) {`~
113 `if (!mInited) throw new TagLibException("can't set `~toUpper(propName)~` tag for empty file");`~
114 `string s = trimStr(v);`~
115 `taglib_tag_set_`~propName~`(mTags, s.toStringz);`~
116 `m`~capitalize(propName)~` = s.idup;`~
117 `}`~
118 `@property string `~propName~` () const nothrow { return (mInited ? m`~capitalize(propName)~` : null); }`;
121 static string stripL (string str) {
122 import std.uni;
123 foreach (i, dchar c; str) if (c != '_' && !std.uni.isWhite(c)) return str[i..$];
124 return str[$..$];
127 static string stripR (string str) {
128 import std.uni, std.utf;
129 foreach_reverse (i, dchar c; str) if (c != '_' && !std.uni.isWhite(c)) return str[0..i+codeLength!char(c)];
130 return str[0..0];
133 static string trimStr (string s) {
134 import std.array;
135 auto res = appender!string();
136 dchar pch = 0;
137 foreach (dchar ch; s) {
138 if (ch < ' ') ch = ' ';
139 // change all '/' to underlines
140 //if (ch == '/') ch = '_';
141 // remove duplicate underlines
142 if (pch == '_' && ch == '_') { pch = ch; continue; }
143 // remove duplicate spaces
144 if (pch == ' ' && ch == ' ') { pch = ch; continue; }
145 res.put(ch);
147 return stripL(stripR(res.data));
150 static string trimStr (char* s) {
151 if (s) {
152 auto res = trimStr(to!string(s));
153 taglib_free(s);
154 return res;
156 return "";
159 void loadInfo (string fname, FileType type=FileType.Autodetect) {
160 clear();
161 if (type == FileType.Autodetect) {
162 mFL = taglib_file_new(fname.toStringz);
163 } else {
164 mFL = taglib_file_new_type(fname.toStringz, cast(TagLibFileType)type);
166 scope(failure) clear();
167 if (!mFL) throw new TagLibException("can't open file '"~fname~"'");
168 mTags = taglib_file_tag(mFL);
169 if (!mTags) throw new TagLibException("can't init tags object for file '"~fname~"'");
170 mArtist = trimStr(taglib_tag_artist(mTags));
171 mAlbum = trimStr(taglib_tag_album(mTags));
172 mTitle = trimStr(taglib_tag_title(mTags));
173 mGenre = trimStr(taglib_tag_genre(mTags));
174 mYear = taglib_tag_year(mTags);
175 if (mYear > 0) {
176 if (mYear < 50) mYear += 2000;
177 else if (mYear < 100) mYear += 1900;
178 else if (mYear < 1930) mYear = 0;
180 if (mYear < 1930 || mYear > 2099) mYear = 0;
181 mTrack = taglib_tag_track(mTags);
182 if (mTrack > 999) mTrack = 0;
183 mFName = fname.idup;
184 mInited = true;
187 private:
188 bool mInited;
189 TagLibFile mFL;
190 TagLibTag mTags;
191 string mFName;
192 string mArtist;
193 string mAlbum;
194 string mTitle;
195 string mComment;
196 string mGenre;
197 uint mYear;
198 uint mTrack;
202 ////////////////////////////////////////////////////////////////////////////////
203 shared static this () {
204 taglib_set_strings_unicode(true);
205 taglib_set_string_management_enabled(false);
209 ////////////////////////////////////////////////////////////////////////////////
210 private:
211 extern(C):
213 struct TagLibFileT {}
214 struct TagLibTagT {}
215 struct TagLibAudioPropertiesT {}
217 alias TagLibFile = TagLibFileT*;
218 alias TagLibTag = TagLibTagT*;
219 alias TagLibAudioProperties = TagLibAudioPropertiesT*;
220 alias TagBool = uint;
224 * By default all strings coming into or out of TagLib's C API are in UTF8.
225 * However, it may be desirable for TagLib to operate on Latin1 (ISO-8859-1)
226 * strings in which case this should be set to FALSE.
228 void taglib_set_strings_unicode (TagBool unicode);
231 * TagLib can keep track of strings that are created when outputting tag values
232 * and clear them using taglib_tag_clear_strings(). This is enabled by default.
233 * However if you wish to do more fine grained management of strings, you can do
234 * so by setting \a management to FALSE.
236 void taglib_set_string_management_enabled (TagBool management);
239 * Explicitly free a string returned from TagLib
241 void taglib_free (void* pointer);
244 /*******************************************************************************
245 * File API
246 ******************************************************************************/
247 enum TagLibFileType {
248 MPEG,
249 OggVorbis,
250 FLAC,
251 MPC,
252 OggFlac,
253 WavPack,
254 Speex,
255 TrueAudio,
256 MP4,
261 * Creates a TagLib file based on \a filename. TagLib will try to guess the file
262 * type.
264 * \returns NULL if the file type cannot be determined or the file cannot
265 * be opened.
267 TagLibFile taglib_file_new (const(char)* filename);
270 * Creates a TagLib file based on \a filename. Rather than attempting to guess
271 * the type, it will use the one specified by \a type.
273 TagLibFile taglib_file_new_type (const(char)* filename, TagLibFileType type);
276 * Frees and closes the file.
278 void taglib_file_free (TagLibFile file);
281 * Returns true if the file is open and readble and valid information for
282 * the Tag and / or AudioProperties was found.
285 TagBool taglib_file_is_valid (const(TagLibFile) file);
288 * Returns a pointer to the tag associated with this file. This will be freed
289 * automatically when the file is freed.
291 TagLibTag taglib_file_tag (const(TagLibFile) file);
294 * Returns a pointer to the the audio properties associated with this file. This
295 * will be freed automatically when the file is freed.
297 const(TagLibAudioProperties) taglib_file_audioproperties (const(TagLibFile) file);
300 * Saves the \a file to disk.
302 TagBool taglib_file_save (TagLibFile file);
305 /******************************************************************************
306 * Tag API
307 ******************************************************************************/
310 * Returns a string with this tag's title.
312 * \note By default this string should be UTF8 encoded and its memory should be
313 * freed using taglib_tag_free_strings().
315 char *taglib_tag_title (const(TagLibTag) tag);
318 * Returns a string with this tag's artist.
320 * \note By default this string should be UTF8 encoded and its memory should be
321 * freed using taglib_tag_free_strings().
323 char *taglib_tag_artist (const(TagLibTag) tag);
326 * Returns a string with this tag's album name.
328 * \note By default this string should be UTF8 encoded and its memory should be
329 * freed using taglib_tag_free_strings().
331 char *taglib_tag_album (const(TagLibTag) tag);
334 * Returns a string with this tag's comment.
336 * \note By default this string should be UTF8 encoded and its memory should be
337 * freed using taglib_tag_free_strings().
339 char *taglib_tag_comment (const(TagLibTag) tag);
342 * Returns a string with this tag's genre.
344 * \note By default this string should be UTF8 encoded and its memory should be
345 * freed using taglib_tag_free_strings().
347 char *taglib_tag_genre (const(TagLibTag) tag);
350 * Returns the tag's year or 0 if year is not set.
352 uint taglib_tag_year (const(TagLibTag) tag);
355 * Returns the tag's track number or 0 if track number is not set.
357 uint taglib_tag_track (const(TagLibTag) tag);
360 * Sets the tag's title.
362 * \note By default this string should be UTF8 encoded.
364 void taglib_tag_set_title (TagLibTag tag, const(char)* title);
367 * Sets the tag's artist.
369 * \note By default this string should be UTF8 encoded.
371 void taglib_tag_set_artist (TagLibTag tag, const(char)* artist);
374 * Sets the tag's album.
376 * \note By default this string should be UTF8 encoded.
378 void taglib_tag_set_album (TagLibTag tag, const(char)* album);
381 * Sets the tag's comment.
383 * \note By default this string should be UTF8 encoded.
385 void taglib_tag_set_comment (TagLibTag tag, const(char)* comment);
388 * Sets the tag's genre.
390 * \note By default this string should be UTF8 encoded.
392 void taglib_tag_set_genre (TagLibTag tag, const(char)* genre);
395 * Sets the tag's year. 0 indicates that this field should be cleared.
397 void taglib_tag_set_year (TagLibTag tag, uint year);
400 * Sets the tag's track number. 0 indicates that this field should be cleared.
402 void taglib_tag_set_track (TagLibTag tag, uint track);
405 * Frees all of the strings that have been created by the tag.
407 void taglib_tag_free_strings ();
410 /******************************************************************************
411 * Audio Properties API
412 ******************************************************************************/
415 * Returns the length of the file in seconds.
417 int taglib_audioproperties_length (const(TagLibAudioProperties) audioProperties);
420 * Returns the bitrate of the file in kb/s.
422 int taglib_audioproperties_bitrate (const(TagLibAudioProperties) audioProperties);
425 * Returns the sample rate of the file in Hz.
427 int taglib_audioproperties_samplerate (const(TagLibAudioProperties) audioProperties);
430 * Returns the number of channels in the audio stream.
432 int taglib_audioproperties_channels (const(TagLibAudioProperties) audioProperties);
435 /*******************************************************************************
436 * Special convenience ID3v2 functions
437 *******************************************************************************/
438 enum TagLibID3v2Encoding {
439 Latin1,
440 UTF16,
441 UTF16BE,
442 UTF8
447 * This sets the default encoding for ID3v2 frames that are written to tags.
449 void taglib_id3v2_set_default_text_encoding (TagLibID3v2Encoding encoding);