utfutil: added simple upcase/locase checks and conversions for cyrillic UTF-8
[iv.d.git] / taglib.d
blobae12be4271f04785116546ab05f050d00708c523
1 /* *********************************************************************** *
2 * This library is free software; you can redistribute it and/or modify *
3 * it under the terms of the GNU Lesser General Public License version *
4 * 2.1 as published by the Free Software Foundation. *
5 * *
6 * This library is distributed in the hope that it will be useful, but *
7 * WITHOUT ANY WARRANTY; without even the implied warranty of *
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
9 * Lesser General Public License for more details. *
10 * *
11 * You should have received a copy of the GNU Lesser General Public *
12 * License along with this library; if not, write to the Free Software *
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
14 * USA *
15 * *********************************************************************** */
16 // wrapper coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
17 ///WARING! this MAY BE 64-bit unsafe!
18 module iv.taglib /*is aliced*/;
20 pragma(lib, "tag_c");
21 pragma(lib, "tag");
24 // ////////////////////////////////////////////////////////////////////////// //
25 import iv.alice;
26 //import iv.exex;
28 mixin(NewExceptionClass!"TagLibException");
31 // ////////////////////////////////////////////////////////////////////////// //
32 struct TagFile {
33 enum FileType {
34 Autodetect = -1, // k8 extension, do not use in C API!
35 MPEG = 0,
36 OggVorbis,
37 FLAC,
38 MPC,
39 OggFlac,
40 WavPack,
41 Speex,
42 TrueAudio,
43 MP4,
44 ASF
48 this (string fname, FileType type=FileType.Autodetect) {
49 loadInfo(fname, type);
52 ~this () {
53 clear();
56 void clear () @trusted {
57 if (mInited) {
58 mInited = false;
59 taglib_file_free(mFL);
60 this = this.init;
64 void save () {
65 if (!mInited) throw new TagLibException("can't save tags object to empty file");
66 if (!taglib_file_save(mFL)) throw new TagLibException("can't save tags object to file '"~mFName~"'");
69 @property bool valid () const @safe pure nothrow { return mInited; }
71 @property string filename () const @safe pure nothrow { return (mInited ? mFName : null); }
73 mixin(strPropMixin!"artist");
74 mixin(strPropMixin!"album");
75 mixin(strPropMixin!"title");
76 mixin(strPropMixin!"genre");
77 mixin(strPropMixin!"comment");
79 @property uint year () const @safe pure nothrow { return (mInited ? mYear : 0); }
80 @property void year (uint v) {
81 if (!mInited) throw new TagLibException("can't set YEAR tag for empty file");
82 if (v > 0) {
83 uint ov;
84 if (v < 50) v += 2000;
85 else if (v < 100) v += 1900;
86 else if (v < 1930) v = 0;
87 if (v < 1930 || v > 2099) {
88 import std.conv : to;
89 throw new TagLibException("invalid YEAR tag value: "~to!string(ov));
92 mYear = v;
93 taglib_tag_set_year(mTags, v);
96 @property uint track () const @safe pure nothrow { return (mInited ? mTrack : 0); }
97 @property void track (uint v) {
98 if (!mInited) throw new TagLibException("can't set TRACK tag for empty file");
99 if (v > 999) {
100 import std.conv : to;
101 throw new TagLibException("invalid TRACK tag value: "~to!string(v));
103 mTrack = v;
104 taglib_tag_set_track(mTags, v);
107 mixin(uintPropMixin!"length"); // file length in seconds
108 mixin(uintPropMixin!"channels"); // number of channels in file
109 mixin(uintPropMixin!"bitrate"); // file bitrate in kb/s
110 mixin(uintPropMixin!"samplerate"); // file samplerate in Hz
112 private:
113 enum uintPropMixin(string propName) =
114 `@property uint `~propName~` () {`~
115 `if (!mInited) return 0;`~
116 `auto tp = taglib_file_audioproperties(mFL);`~
117 `if (!tp) throw new TagLibException("can't get audio properties for file '"~mFName~"'");`~
118 `auto r = taglib_audioproperties_`~propName~`(tp);`~
119 `return (r < 0 ? 0 : r);`~
120 `}`;
122 template strPropMixin (string propName) {
123 import std.string : capitalize, toUpper;
124 enum strPropMixin =
125 `@property void `~propName~` (string v) {`~
126 `import std.string : toStringz;`~
127 `if (!mInited) throw new TagLibException("can't set `~toUpper(propName)~` tag for empty file");`~
128 `auto s = trimStr(v);`~
129 `taglib_tag_set_`~propName~`(mTags, s.toStringz);`~
130 `m`~capitalize(propName)~` = s.idup;`~
131 `}`~
132 `@property string `~propName~` () const @safe pure nothrow { return (mInited ? m`~capitalize(propName)~` : null); }`;
135 static string stripL() (string str) {
136 import std.uni : isWhite;
137 foreach (immutable i, immutable dchar c; str) {
138 if (c != 0 && c != '_' && !isWhite(c)) return str[i..$];
140 return null;
143 static string stripR() (string str) {
144 import std.uni : isWhite;
145 import std.utf : codeLength;
146 foreach_reverse (immutable i, immutable dchar c; str) {
147 if (c != 0 && c != '_' && !isWhite(c)) return str[0..i+codeLength!char(c)];
149 return null;
152 static string trimStr() (string s) {
153 import std.array : appender;
154 auto res = appender!string();
155 dchar pch = 0;
156 foreach (dchar ch; s) {
157 if (ch < ' ') ch = ' ';
158 // remove duplicate underlines
159 if (pch == '_' && ch == '_') { pch = ch; continue; }
160 // remove duplicate spaces
161 if (pch == ' ' && ch == ' ') { pch = ch; continue; }
162 res.put(ch);
164 return stripL(stripR(res.data));
167 static string trimStr() (char* s) {
168 if (s !is null) {
169 import std.conv : to;
170 auto res = trimStr(to!string(s));
171 taglib_free(s);
172 return res;
174 return null;
177 void loadInfo (string fname, FileType type=FileType.Autodetect) {
178 import std.string : toStringz;
179 clear();
180 if (type == FileType.Autodetect) {
181 mFL = taglib_file_new(fname.toStringz);
182 } else {
183 mFL = taglib_file_new_type(fname.toStringz, cast(TagLibFileType)type);
185 scope(failure) clear();
186 if (mFL is null) throw new TagLibException("can't open file '"~fname~"'");
187 mTags = taglib_file_tag(mFL);
188 if (mTags is null) throw new TagLibException("can't init tags object for file '"~fname~"'");
189 mArtist = trimStr(taglib_tag_artist(mTags));
190 mAlbum = trimStr(taglib_tag_album(mTags));
191 mTitle = trimStr(taglib_tag_title(mTags));
192 mGenre = trimStr(taglib_tag_genre(mTags));
193 mYear = taglib_tag_year(mTags);
194 if (mYear > 0) {
195 if (mYear < 50) mYear += 2000;
196 else if (mYear < 100) mYear += 1900;
197 else if (mYear < 1930) mYear = 0;
199 if (mYear < 1930 || mYear > 2099) mYear = 0;
200 mTrack = taglib_tag_track(mTags);
201 if (mTrack > 999) mTrack = 0;
202 mFName = fname.idup;
203 mInited = true;
206 private:
207 bool mInited;
208 TagLibFile mFL;
209 TagLibTag mTags;
210 string mFName;
211 string mArtist;
212 string mAlbum;
213 string mTitle;
214 string mComment;
215 string mGenre;
216 uint mYear;
217 uint mTrack;
221 // ////////////////////////////////////////////////////////////////////////// //
222 shared static this () {
223 taglib_set_strings_unicode(true);
224 taglib_set_string_management_enabled(false);
228 // ////////////////////////////////////////////////////////////////////////// //
229 private:
230 extern(C):
231 nothrow:
232 @trusted:
233 @nogc:
235 //typedef TagLibFile = void*;
236 alias TagLibFile = void*;
237 //typedef TagLibTag = void*;
238 alias TagLibTag = void*;
239 //typedef TagLibAudioProperties = void*;
240 alias TagLibAudioProperties = void*;
241 //typedef TagBool = uint;
242 alias TagBool = uint;
243 alias TagCString = const(char)*; // can't use typedef here
247 * By default all strings coming into or out of TagLib's C API are in UTF8.
248 * However, it may be desirable for TagLib to operate on Latin1 (ISO-8859-1)
249 * strings in which case this should be set to FALSE.
251 void taglib_set_strings_unicode (TagBool unicode);
254 * TagLib can keep track of strings that are created when outputting tag values
255 * and clear them using taglib_tag_clear_strings(). This is enabled by default.
256 * However if you wish to do more fine grained management of strings, you can do
257 * so by setting \a management to FALSE.
259 void taglib_set_string_management_enabled (TagBool management);
262 * Explicitly free a string returned from TagLib
264 void taglib_free (void* pointer);
267 /*******************************************************************************
268 * File API
269 ******************************************************************************/
270 enum TagLibFileType {
271 MPEG,
272 OggVorbis,
273 FLAC,
274 MPC,
275 OggFlac,
276 WavPack,
277 Speex,
278 TrueAudio,
279 MP4,
284 * Creates a TagLib file based on \a filename. TagLib will try to guess the file
285 * type.
287 * \returns NULL if the file type cannot be determined or the file cannot
288 * be opened.
290 TagLibFile taglib_file_new (TagCString filename);
293 * Creates a TagLib file based on \a filename. Rather than attempting to guess
294 * the type, it will use the one specified by \a type.
296 TagLibFile taglib_file_new_type (TagCString filename, TagLibFileType type);
299 * Frees and closes the file.
301 void taglib_file_free (TagLibFile file);
304 * Returns true if the file is open and readble and valid information for
305 * the Tag and / or AudioProperties was found.
308 TagBool taglib_file_is_valid (const(TagLibFile) file);
311 * Returns a pointer to the tag associated with this file. This will be freed
312 * automatically when the file is freed.
314 TagLibTag taglib_file_tag (const(TagLibFile) file);
317 * Returns a pointer to the the audio properties associated with this file. This
318 * will be freed automatically when the file is freed.
320 const(TagLibAudioProperties) taglib_file_audioproperties (const(TagLibFile) file);
323 * Saves the \a file to disk.
325 TagBool taglib_file_save (TagLibFile file);
328 /******************************************************************************
329 * Tag API
330 ******************************************************************************/
333 * Returns a string with this tag's title.
335 * \note By default this string should be UTF8 encoded and its memory should be
336 * freed using taglib_tag_free_strings().
338 char *taglib_tag_title (const(TagLibTag) tag);
341 * Returns a string with this tag's artist.
343 * \note By default this string should be UTF8 encoded and its memory should be
344 * freed using taglib_tag_free_strings().
346 char *taglib_tag_artist (const(TagLibTag) tag);
349 * Returns a string with this tag's album name.
351 * \note By default this string should be UTF8 encoded and its memory should be
352 * freed using taglib_tag_free_strings().
354 char *taglib_tag_album (const(TagLibTag) tag);
357 * Returns a string with this tag's comment.
359 * \note By default this string should be UTF8 encoded and its memory should be
360 * freed using taglib_tag_free_strings().
362 char *taglib_tag_comment (const(TagLibTag) tag);
365 * Returns a string with this tag's genre.
367 * \note By default this string should be UTF8 encoded and its memory should be
368 * freed using taglib_tag_free_strings().
370 char *taglib_tag_genre (const(TagLibTag) tag);
373 * Returns the tag's year or 0 if year is not set.
375 uint taglib_tag_year (const(TagLibTag) tag);
378 * Returns the tag's track number or 0 if track number is not set.
380 uint taglib_tag_track (const(TagLibTag) tag);
383 * Sets the tag's title.
385 * \note By default this string should be UTF8 encoded.
387 void taglib_tag_set_title (TagLibTag tag, TagCString title);
390 * Sets the tag's artist.
392 * \note By default this string should be UTF8 encoded.
394 void taglib_tag_set_artist (TagLibTag tag, TagCString artist);
397 * Sets the tag's album.
399 * \note By default this string should be UTF8 encoded.
401 void taglib_tag_set_album (TagLibTag tag, TagCString album);
404 * Sets the tag's comment.
406 * \note By default this string should be UTF8 encoded.
408 void taglib_tag_set_comment (TagLibTag tag, TagCString comment);
411 * Sets the tag's genre.
413 * \note By default this string should be UTF8 encoded.
415 void taglib_tag_set_genre (TagLibTag tag, TagCString genre);
418 * Sets the tag's year. 0 indicates that this field should be cleared.
420 void taglib_tag_set_year (TagLibTag tag, uint year);
423 * Sets the tag's track number. 0 indicates that this field should be cleared.
425 void taglib_tag_set_track (TagLibTag tag, uint track);
428 * Frees all of the strings that have been created by the tag.
430 void taglib_tag_free_strings ();
433 /******************************************************************************
434 * Audio Properties API
435 ******************************************************************************/
438 * Returns the length of the file in seconds.
440 int taglib_audioproperties_length (const(TagLibAudioProperties) audioProperties);
443 * Returns the bitrate of the file in kb/s.
445 int taglib_audioproperties_bitrate (const(TagLibAudioProperties) audioProperties);
448 * Returns the sample rate of the file in Hz.
450 int taglib_audioproperties_samplerate (const(TagLibAudioProperties) audioProperties);
453 * Returns the number of channels in the audio stream.
455 int taglib_audioproperties_channels (const(TagLibAudioProperties) audioProperties);
458 /*******************************************************************************
459 * Special convenience ID3v2 functions
460 *******************************************************************************/
461 enum TagLibID3v2Encoding {
462 Latin1,
463 UTF16,
464 UTF16BE,
465 UTF8
470 * This sets the default encoding for ID3v2 frames that are written to tags.
472 void taglib_id3v2_set_default_text_encoding (TagLibID3v2Encoding encoding);