initial commit
[taglib.d.git] / taglib.d
blob31232962443ea73fa2a6270f559b657a2f11056d
1 ///WARING! this MAY BE 64-bit unsafe!
2 module taglib;
4 version(DigitalMars) {
5 pragma(lib, "tag_c");
6 pragma(lib, "tag");
10 ////////////////////////////////////////////////////////////////////////////////
11 import std.conv;
12 import std.string;
15 class TagLibException : Exception {
16 @safe pure nothrow this (string msg, string file=__FILE__, size_t line=__LINE__, Throwable next=null) {
17 super(msg, file, line, next);
22 struct TagFile {
23 enum FileType {
24 Autodetect=-1, // k8 extension, do not use in C API!
25 MPEG,
26 OggVorbis,
27 FLAC,
28 MPC,
29 OggFlac,
30 WavPack,
31 Speex,
32 TrueAudio,
33 MP4,
34 ASF
38 this (string fname, FileType type=FileType.Autodetect) {
39 loadInfo(fname, type);
42 ~this () {
43 clear();
46 void clear () {
47 if (mInited) {
48 mInited = false;
49 taglib_file_free(mFL);
50 mFL = null;
51 mTags = null;
52 mFName = mArtist = mAlbum = mTitle = mComment = mGenre = null;
53 mYear = mTrack = 0;
57 void save () {
58 if (!mInited) throw new TagLibException("can't save tags object to empty file");
59 if (!taglib_file_save(mFL)) throw new TagLibException("can't save tags object to file '"~mFName~"'");
62 @property bool valid () const nothrow { return mInited; }
64 @property string filename () const nothrow { return (mInited ? mFName : null); }
66 mixin(strPropMixin("artist"));
67 mixin(strPropMixin("album"));
68 mixin(strPropMixin("title"));
69 mixin(strPropMixin("genre"));
70 mixin(strPropMixin("comment"));
72 @property uint year () const nothrow { return (mInited ? mYear : 0); }
73 @property void year (uint v) {
74 if (!mInited) throw new TagLibException("can't set YEAR tag for empty file");
75 if (v > 0) {
76 uint ov;
77 if (v < 50) v += 2000;
78 else if (v < 100) v += 1900;
79 else if (v < 1930) v = 0;
80 if (v < 1930 || v > 2099) throw new TagLibException("invalid YEAR tag value: "~to!string(ov));
82 mYear = v;
83 taglib_tag_set_year(mTags, v);
86 @property uint track () const nothrow { return (mInited ? mTrack : 0); }
87 @property void track (uint v) {
88 if (!mInited) throw new TagLibException("can't set TRACK tag for empty file");
89 if (v > 999) throw new TagLibException("invalid TRACK tag value: "~to!string(v));
90 mTrack = v;
91 taglib_tag_set_track(mTags, v);
94 mixin(uintPropMixin("length")); // file length in seconds
95 mixin(uintPropMixin("channels")); // number of channels in file
96 mixin(uintPropMixin("bitrate")); // file bitrate in kb/s
97 mixin(uintPropMixin("samplerate")); // file samplerate in Hz
99 private:
100 static uintPropMixin (string propName) {
101 return
102 `@property uint `~propName~` () {`~
103 `if (!mInited) return 0;`~
104 `auto tp = taglib_file_audioproperties(mFL);`~
105 `if (!tp) throw new TagLibException("can't get audio properties for file '"~mFName~"'");`~
106 `auto r = taglib_audioproperties_`~propName~`(tp);`~
107 `return (r < 0 ? 0 : r);`~
108 `}`;
111 static strPropMixin (string propName) {
112 import std.string;
113 return
114 `@property void `~propName~` (string v) {`~
115 `if (!mInited) throw new TagLibException("can't set `~toUpper(propName)~` tag for empty file");`~
116 `string s = trimStr(v);`~
117 `taglib_tag_set_`~propName~`(mTags, s.toStringz);`~
118 `m`~capitalize(propName)~` = s.idup;`~
119 `}`~
120 `@property string `~propName~` () const nothrow { return (mInited ? m`~capitalize(propName)~` : null); }`;
123 static string stripL (string str) {
124 import std.uni;
125 foreach (i, dchar c; str) if (c != '_' && !std.uni.isWhite(c)) return str[i..$];
126 return str[$..$];
129 static string stripR (string str) {
130 import std.uni, std.utf;
131 foreach_reverse (i, dchar c; str) if (c != '_' && !std.uni.isWhite(c)) return str[0..i+codeLength!char(c)];
132 return str[0..0];
135 static string trimStr (string s) {
136 import std.array;
137 auto res = appender!string();
138 dchar pch = 0;
139 foreach (dchar ch; s) {
140 if (ch < ' ') ch = ' ';
141 // change all '/' to underlines
142 //if (ch == '/') ch = '_';
143 // remove duplicate underlines
144 if (pch == '_' && ch == '_') { pch = ch; continue; }
145 // remove duplicate spaces
146 if (pch == ' ' && ch == ' ') { pch = ch; continue; }
147 res.put(ch);
149 return stripL(stripR(res.data));
152 static string trimStr (char* s) {
153 if (s) {
154 auto res = trimStr(to!string(s));
155 taglib_free(s);
156 return res;
158 return "";
161 void loadInfo (string fname, FileType type=FileType.Autodetect) {
162 clear();
163 if (type == FileType.Autodetect) {
164 mFL = taglib_file_new(fname.toStringz);
165 } else {
166 mFL = taglib_file_new_type(fname.toStringz, cast(TagLibFileType)type);
168 scope(failure) clear();
169 if (!mFL) throw new TagLibException("can't open file '"~fname~"'");
170 mTags = taglib_file_tag(mFL);
171 if (!mTags) throw new TagLibException("can't init tags object for file '"~fname~"'");
172 mArtist = trimStr(taglib_tag_artist(mTags));
173 mAlbum = trimStr(taglib_tag_album(mTags));
174 mTitle = trimStr(taglib_tag_title(mTags));
175 mGenre = trimStr(taglib_tag_genre(mTags));
176 mYear = taglib_tag_year(mTags);
177 if (mYear > 0) {
178 if (mYear < 50) mYear += 2000;
179 else if (mYear < 100) mYear += 1900;
180 else if (mYear < 1930) mYear = 0;
182 if (mYear < 1930 || mYear > 2099) mYear = 0;
183 mTrack = taglib_tag_track(mTags);
184 if (mTrack > 999) mTrack = 0;
185 mFName = fname.idup;
186 mInited = true;
189 private:
190 bool mInited;
191 TagLibFile mFL;
192 TagLibTag mTags;
193 string mFName;
194 string mArtist;
195 string mAlbum;
196 string mTitle;
197 string mComment;
198 string mGenre;
199 uint mYear;
200 uint mTrack;
204 ////////////////////////////////////////////////////////////////////////////////
205 shared static this () {
206 taglib_set_strings_unicode(true);
207 taglib_set_string_management_enabled(false);
211 ////////////////////////////////////////////////////////////////////////////////
212 private:
213 extern(C):
215 struct TagLibFileT {}
216 struct TagLibTagT {}
217 struct TagLibAudioPropertiesT {}
219 alias TagLibFile = TagLibFileT*;
220 alias TagLibTag = TagLibTagT*;
221 alias TagLibAudioProperties = TagLibAudioPropertiesT*;
222 alias TagBool = uint;
226 * By default all strings coming into or out of TagLib's C API are in UTF8.
227 * However, it may be desirable for TagLib to operate on Latin1 (ISO-8859-1)
228 * strings in which case this should be set to FALSE.
230 void taglib_set_strings_unicode (TagBool unicode);
233 * TagLib can keep track of strings that are created when outputting tag values
234 * and clear them using taglib_tag_clear_strings(). This is enabled by default.
235 * However if you wish to do more fine grained management of strings, you can do
236 * so by setting \a management to FALSE.
238 void taglib_set_string_management_enabled (TagBool management);
241 * Explicitly free a string returned from TagLib
243 void taglib_free (void* pointer);
246 /*******************************************************************************
247 * File API
248 ******************************************************************************/
249 enum TagLibFileType {
250 MPEG,
251 OggVorbis,
252 FLAC,
253 MPC,
254 OggFlac,
255 WavPack,
256 Speex,
257 TrueAudio,
258 MP4,
263 * Creates a TagLib file based on \a filename. TagLib will try to guess the file
264 * type.
266 * \returns NULL if the file type cannot be determined or the file cannot
267 * be opened.
269 TagLibFile taglib_file_new (const(char)* filename);
272 * Creates a TagLib file based on \a filename. Rather than attempting to guess
273 * the type, it will use the one specified by \a type.
275 TagLibFile taglib_file_new_type (const(char)* filename, TagLibFileType type);
278 * Frees and closes the file.
280 void taglib_file_free (TagLibFile file);
283 * Returns true if the file is open and readble and valid information for
284 * the Tag and / or AudioProperties was found.
287 TagBool taglib_file_is_valid (const(TagLibFile) file);
290 * Returns a pointer to the tag associated with this file. This will be freed
291 * automatically when the file is freed.
293 TagLibTag taglib_file_tag (const(TagLibFile) file);
296 * Returns a pointer to the the audio properties associated with this file. This
297 * will be freed automatically when the file is freed.
299 const(TagLibAudioProperties) taglib_file_audioproperties (const(TagLibFile) file);
302 * Saves the \a file to disk.
304 TagBool taglib_file_save (TagLibFile file);
307 /******************************************************************************
308 * Tag API
309 ******************************************************************************/
312 * Returns a string with this tag's title.
314 * \note By default this string should be UTF8 encoded and its memory should be
315 * freed using taglib_tag_free_strings().
317 char *taglib_tag_title (const(TagLibTag) tag);
320 * Returns a string with this tag's artist.
322 * \note By default this string should be UTF8 encoded and its memory should be
323 * freed using taglib_tag_free_strings().
325 char *taglib_tag_artist (const(TagLibTag) tag);
328 * Returns a string with this tag's album name.
330 * \note By default this string should be UTF8 encoded and its memory should be
331 * freed using taglib_tag_free_strings().
333 char *taglib_tag_album (const(TagLibTag) tag);
336 * Returns a string with this tag's comment.
338 * \note By default this string should be UTF8 encoded and its memory should be
339 * freed using taglib_tag_free_strings().
341 char *taglib_tag_comment (const(TagLibTag) tag);
344 * Returns a string with this tag's genre.
346 * \note By default this string should be UTF8 encoded and its memory should be
347 * freed using taglib_tag_free_strings().
349 char *taglib_tag_genre (const(TagLibTag) tag);
352 * Returns the tag's year or 0 if year is not set.
354 uint taglib_tag_year (const(TagLibTag) tag);
357 * Returns the tag's track number or 0 if track number is not set.
359 uint taglib_tag_track (const(TagLibTag) tag);
362 * Sets the tag's title.
364 * \note By default this string should be UTF8 encoded.
366 void taglib_tag_set_title (TagLibTag tag, const(char)* title);
369 * Sets the tag's artist.
371 * \note By default this string should be UTF8 encoded.
373 void taglib_tag_set_artist (TagLibTag tag, const(char)* artist);
376 * Sets the tag's album.
378 * \note By default this string should be UTF8 encoded.
380 void taglib_tag_set_album (TagLibTag tag, const(char)* album);
383 * Sets the tag's comment.
385 * \note By default this string should be UTF8 encoded.
387 void taglib_tag_set_comment (TagLibTag tag, const(char)* comment);
390 * Sets the tag's genre.
392 * \note By default this string should be UTF8 encoded.
394 void taglib_tag_set_genre (TagLibTag tag, const(char)* genre);
397 * Sets the tag's year. 0 indicates that this field should be cleared.
399 void taglib_tag_set_year (TagLibTag tag, uint year);
402 * Sets the tag's track number. 0 indicates that this field should be cleared.
404 void taglib_tag_set_track (TagLibTag tag, uint track);
407 * Frees all of the strings that have been created by the tag.
409 void taglib_tag_free_strings ();
412 /******************************************************************************
413 * Audio Properties API
414 ******************************************************************************/
417 * Returns the length of the file in seconds.
419 int taglib_audioproperties_length (const(TagLibAudioProperties) audioProperties);
422 * Returns the bitrate of the file in kb/s.
424 int taglib_audioproperties_bitrate (const(TagLibAudioProperties) audioProperties);
427 * Returns the sample rate of the file in Hz.
429 int taglib_audioproperties_samplerate (const(TagLibAudioProperties) audioProperties);
432 * Returns the number of channels in the audio stream.
434 int taglib_audioproperties_channels (const(TagLibAudioProperties) audioProperties);
437 /*******************************************************************************
438 * Special convenience ID3v2 functions
439 *******************************************************************************/
440 enum TagLibID3v2Encoding {
441 Latin1,
442 UTF16,
443 UTF16BE,
444 UTF8
449 * This sets the default encoding for ID3v2 frames that are written to tags.
451 void taglib_id3v2_set_default_text_encoding (TagLibID3v2Encoding encoding);