[This thread belongs on mad-dev; note Reply-To. Dominic, I'm not sure whether you're subscribed there...]
On Wednesday, April 10, 2002, at 10:26 PM, Dominic Mazzoni wrote:
I'd like to also switch over to using libid3tag. We had been using id3lib, but it's buggy and has trouble compiling on a lot of systems.
Our needs are minimal. We're not trying to be the ultimate ID3 editor; we just want to be able to read and write the most common tags for convenience.
I didn't see any documentation on libid3tag...did I miss something? The sample code only uses a small subset of its features.
I documented some of the interface here:
http://www.mars.org/mailman/public/mad-dev/2002-January/000439.html
Although this doesn't cover rendering tags, it may answer some questions about the data structures.
Anyway, I was able to figure out how to use libid3tag to import tags from a file. But I'm stuck trying to render them using id3_tag_render.
First of all, the only way I was able to figure out to add new frames was to muck around in the data structures. Is this correct? It might be nice if there were more API functions to make it easier...
For example, id3lib has a "simple API" which provides functions that let you add and/or query the most common tags (Title, Artist, etc.), without mucking in the data structure at all.
You shouldn't need to muck with the data structures. The general approach to adding a frame is:
frame = id3_frame_new("XXXX"); id3_tag_attachframe(tag, frame);
By indicating the frame ID ("XXXX" above), libid3tag knows automatically which fields to create in the frame. For text frames, there are two fields, a text encoding and a string list. If you're using Unicode, you should be sure to set the text encoding accordingly:
id3_field_settextencoding(&frame->fields[0], ID3_FIELD_TEXTENCODING_UTF_16);
To manipulate the string list field, you can either make an array of id3_ucs4_t pointers and call id3_field_setstrings(), or you can call id3_field_addstring() once for each string. In either case, the strings you pass are copied, so it is your responsibility to dispose of them.
- What's the proper way to convert an ASCII string to an id3_ucs4_t string? (I used a for loop, casting chars to longs...is that OK?)
Instead of your own loop, you can call id3_latin1_decode().
- When I try to enable the ID3_TAG_OPTION_ID3V1, the rendering fails. Is it supported?
Yes, it is supported. Probably it failed for you because mucking around in the data structures corrupted them...
- Finally, I do get some bytes back from id3_tag_render without the ID3V1 option, but when I prepend them to the beginning of my MP3 file, programs don't recognize them. In fact even libid3tag doesn't even load any tags from the resulting file. Is there something else I need to do to the id3_tag_render output?
Nope; again I think the problem stems from corrupt data structures.
I'm including some of my source code below. Thanks for any help anyone can offer.
Your ::ExportID3() looks good; try the following MakeID3Frame() instead:
struct id3_frame *MakeID3Frame(const char *name, const char *data) { struct id3_frame *frame; id3_latin1_t *latin1; id3_ucs4_t *ucs4;
frame = id3_frame_new(name);
latin1 = data; ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); if (ucs4) { id3_latin1_decode(latin1, ucs4); id3_field_setstrings(&frame->fields[1], 1, &ucs4); free(ucs4); }
return frame; }
-- Rob Leslie rob@mars.org
Rob,
Thanks for your fast response! [BTW, I'm on mad-dev now...]
I documented some of the interface here:
http://www.mars.org/mailman/public/mad-dev/2002-January/000439.html
Thanks, this is very helpful.
frame = id3_frame_new("XXXX"); id3_tag_attachframe(tag, frame);
It's funny, I didn't notice id3_frame_new because I assumed that all of the functions I would need were in id3tag.h (since most of them were already there).
Your ::ExportID3() looks good; try the following MakeID3Frame() instead:
Strange, I tried to add your functions and I'm getting linker errors with all of the functions I try to call which are not in id3tag.h. Does this make any sense? (It's possible it's my fault, but I did a make clean, I'm linking to libid3tag.a from mad-0.14.2b, and there were no compiler warnings...):
obj/Tags.o: In function `MakeID3Frame(char const *, char const *)': /home/dmazzoni/audacity/src/Tags.cpp:214: undefined reference to `id3_frame_new(char const *)' /home/dmazzoni/audacity/src/Tags.cpp:217: undefined reference to `id3_latin1_length(unsigned char const *)' /home/dmazzoni/audacity/src/Tags.cpp:219: undefined reference to `id3_latin1_decode(unsigned char const *, unsigned long *)' collect2: ld returned 1 exit status
Is it possible that these functions are not being exported?
- Dominic
struct id3_frame *MakeID3Frame(const char *name, const char *data) { struct id3_frame *frame; id3_latin1_t *latin1; id3_ucs4_t *ucs4;
frame = id3_frame_new(name);
latin1 = data; ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); if (ucs4) { id3_latin1_decode(latin1, ucs4); id3_field_setstrings(&frame->fields[1], 1, &ucs4); free(ucs4); }
return frame; }
-- Rob Leslie rob@mars.org
On Thursday, April 11, 2002, at 01:50 AM, Dominic Mazzoni wrote:
It's funny, I didn't notice id3_frame_new because I assumed that all of the functions I would need were in id3tag.h (since most of them were already there).
Hmm, this is an oversight. The prototype should have been put in id3tag.h.
Your ::ExportID3() looks good; try the following MakeID3Frame() instead:
Strange, I tried to add your functions and I'm getting linker errors with all of the functions I try to call which are not in id3tag.h. Does this make any sense? (It's possible it's my fault, but I did a make clean, I'm linking to libid3tag.a from mad-0.14.2b, and there were no compiler warnings...):
obj/Tags.o: In function `MakeID3Frame(char const *, char const *)': /home/dmazzoni/audacity/src/Tags.cpp:214: undefined reference to `id3_frame_new(char const *)' /home/dmazzoni/audacity/src/Tags.cpp:217: undefined reference to `id3_latin1_length(unsigned char const *)' /home/dmazzoni/audacity/src/Tags.cpp:219: undefined reference to `id3_latin1_decode(unsigned char const *, unsigned long *)' collect2: ld returned 1 exit status
Is it possible that these functions are not being exported?
Probably since they do not appear in id3tag.h, the prototype is being inferred from use, and since you're using C++ the compiler assumes they are C++ functions and does name mangling prior to linking.
I think you can work around this by explicitly adding some prototypes:
extern "C" { struct id3_frame *id3_frame_new(char const *); id3_length_t id3_latin1_length(id3_latin1_t const *); void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *); }
Sorry about this. I'll have to update the library to put the prototypes in id3tag.h.
-- Rob Leslie rob@mars.org
Yes, it works great now, thanks!
- Dominic
Rob Leslie wrote:
On Thursday, April 11, 2002, at 01:50 AM, Dominic Mazzoni wrote:
It's funny, I didn't notice id3_frame_new because I assumed that all of the functions I would need were in id3tag.h (since most of them were already there).
Hmm, this is an oversight. The prototype should have been put in id3tag.h.
Your ::ExportID3() looks good; try the following MakeID3Frame() instead:
Strange, I tried to add your functions and I'm getting linker errors with all of the functions I try to call which are not in id3tag.h. Does this make any sense? (It's possible it's my fault, but I did a make clean, I'm linking to libid3tag.a from mad-0.14.2b, and there were no compiler warnings...):
obj/Tags.o: In function `MakeID3Frame(char const *, char const *)': /home/dmazzoni/audacity/src/Tags.cpp:214: undefined reference to `id3_frame_new(char const *)' /home/dmazzoni/audacity/src/Tags.cpp:217: undefined reference to `id3_latin1_length(unsigned char const *)' /home/dmazzoni/audacity/src/Tags.cpp:219: undefined reference to `id3_latin1_decode(unsigned char const *, unsigned long *)' collect2: ld returned 1 exit status
Is it possible that these functions are not being exported?
Probably since they do not appear in id3tag.h, the prototype is being inferred from use, and since you're using C++ the compiler assumes they are C++ functions and does name mangling prior to linking.
I think you can work around this by explicitly adding some prototypes:
extern "C" { struct id3_frame *id3_frame_new(char const *); id3_length_t id3_latin1_length(id3_latin1_t const *); void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *); }
Sorry about this. I'll have to update the library to put the prototypes in id3tag.h.
-- Rob Leslie rob@mars.org
Rob,
I finished writing my libid3tag code, and it seems to work pretty well.
A couple of notes:
* I couldn't get the "comment" tag to work. I tried to import "comment" from files that I know have valid ID3V1 comments, and got nothing, and I tried to export both ID3V1 and ID3V2 comments and nothing got written.
All of the other standard tags I tried worked. Have you seen this problem before? Can you reproduce it?
* To keep things simple, Audacity provides the user with a choice control to set the genre - i.e. they can't type in their own. This keeps the dialog box compatible with both ID3V1 and ID3V2.
It would be nice if libid3tag made it easier to work with genres by number. Currently I'm using the id3_genre_name function in a rather roundabout way - when I want to retrieve the 29th genre name, I sprintf 29 to a string, convert it to a ucs4 string, then pass that to id3_genre_name.
All I want is for you to export two functions: one which returns the number of genres, and another which returns the nth genre.
* I discovered that if I try to output a genre name to an ID3V1 file, nothing gets written. However, if I output a genre number (i.e. the string "29") it works.
For symmetry, it seems that if I try to write a genre name which is in the list, libid3tag should write out the appropriate index number to the ID3V1 tag.
Thanks, Dominic
Rob Leslie wrote:
On Thursday, April 11, 2002, at 01:50 AM, Dominic Mazzoni wrote:
It's funny, I didn't notice id3_frame_new because I assumed that all of the functions I would need were in id3tag.h (since most of them were already there).
Hmm, this is an oversight. The prototype should have been put in id3tag.h.
Your ::ExportID3() looks good; try the following MakeID3Frame() instead:
Strange, I tried to add your functions and I'm getting linker errors with all of the functions I try to call which are not in id3tag.h. Does this make any sense? (It's possible it's my fault, but I did a make clean, I'm linking to libid3tag.a from mad-0.14.2b, and there were no compiler warnings...):
obj/Tags.o: In function `MakeID3Frame(char const *, char const *)': /home/dmazzoni/audacity/src/Tags.cpp:214: undefined reference to `id3_frame_new(char const *)' /home/dmazzoni/audacity/src/Tags.cpp:217: undefined reference to `id3_latin1_length(unsigned char const *)' /home/dmazzoni/audacity/src/Tags.cpp:219: undefined reference to `id3_latin1_decode(unsigned char const *, unsigned long *)' collect2: ld returned 1 exit status
Is it possible that these functions are not being exported?
Probably since they do not appear in id3tag.h, the prototype is being inferred from use, and since you're using C++ the compiler assumes they are C++ functions and does name mangling prior to linking.
I think you can work around this by explicitly adding some prototypes:
extern "C" { struct id3_frame *id3_frame_new(char const *); id3_length_t id3_latin1_length(id3_latin1_t const *); void id3_latin1_decode(id3_latin1_t const *, id3_ucs4_t *); }
Sorry about this. I'll have to update the library to put the prototypes in id3tag.h.
-- Rob Leslie rob@mars.org
On Sunday, April 14, 2002, at 01:51 AM, Dominic Mazzoni wrote:
I couldn't get the "comment" tag to work. I tried to import "comment" from files that I know have valid ID3V1 comments, and got nothing, and I tried to export both ID3V1 and ID3V2 comments and nothing got written.
All of the other standard tags I tried worked. Have you seen this problem before? Can you reproduce it?
Comment frames ("COMM") are not like the other text frames; they have a different structure. See section 4.10 of the ID3v2.4.0 native frames document for details, but in brief: there are four fields. The fourth field is the actual comment text. The third field is a short content description (e.g. "ID3v1 Comment" -- or just leave it empty). The second field is a 3-byte language identifier (which you can ignore if the language is unknown), and the first field is the text encoding.
There can be more than one comment frame in an ID3v2 tag, but only one with the same language and content description. When writing ID3v1 tags, libid3tag writes the first comment frame only.
To keep things simple, Audacity provides the user with a choice control to set the genre - i.e. they can't type in their own. This keeps the dialog box compatible with both ID3V1 and ID3V2.
It would be nice if libid3tag made it easier to work with genres by number. Currently I'm using the id3_genre_name function in a rather roundabout way - when I want to retrieve the 29th genre name, I sprintf 29 to a string, convert it to a ucs4 string, then pass that to id3_genre_name.
All I want is for you to export two functions: one which returns the number of genres, and another which returns the nth genre.
Yes, this is something I was planning to add. Instead of two functions, I was only going to add one which returned a null pointer after the last valid genre number.
I discovered that if I try to output a genre name to an ID3V1 file, nothing gets written. However, if I output a genre number (i.e. the string "29") it works.
For symmetry, it seems that if I try to write a genre name which is in the list, libid3tag should write out the appropriate index number to the ID3V1 tag.
This is a reasonable expectation. I'll see if I can get the next release to behave this way.
Thanks for your feedback,
-- Rob Leslie rob@mars.org
Rob:
Briefly, I just joined the list. I'm using libid3tag for an application I am building which is a gtk-based manager for Creative Nomad II series players (transfer + a bit of file management). Just like Dominic, I tried id3lib, but it was a nightmare to get to work. In contrast, I already have your id3 library up and running! If you need any help with anything, let me know. In particular, I think you should include some kind of API reference with the package, as well as an explicit, simple example program.
On Sun, 2002-04-14 at 04:43, Rob Leslie wrote:
To keep things simple, Audacity provides the user with a choice control to set the genre - i.e. they can't type in their own. This keeps the dialog box compatible with both ID3V1 and ID3V2.
It would be nice if libid3tag made it easier to work with genres by number. Currently I'm using the id3_genre_name function in a rather roundabout way - when I want to retrieve the 29th genre name, I sprintf 29 to a string, convert it to a ucs4 string, then pass that to id3_genre_name.
All I want is for you to export two functions: one which returns the number of genres, and another which returns the nth genre.
Yes, this is something I was planning to add. Instead of two functions, I was only going to add one which returned a null pointer after the last valid genre number.
To have a nice clean API, I think Dominic's idea is better. This would totally insulate the user from any of the data structures, and give some nice clean functionality. I don't have all of the functions committed to memory to yet, but it _may_ also be helpful to have a function that returns the number (int 29, or whatever) that corresponds to a given genre ("blues").
Regardless of any critical comments I make, your lib is great. Like I said, let me know if you need any help.
Neil Hodge nhodge@attbi.com
Just to clarify something about comment frames...
Text frames use string lists, but comment frames use the other two kinds of Unicode strings: an ordinary string for the content description, and a "full" string for the actual comment text. The difference between these two kinds of strings is that a "full" string is allowed to contain newline characters, while the other is not.
Use id3_field_getstring() and id3_field_setstring() to manipulate the content description, and id3_field_getfullstring() and id3_field_setfullstring() to manipulate the actual comment text.
-- Rob Leslie rob@mars.org
Hi Rob,
Just curious if you or anyone you may know of has plans to do a FP version of the Vorbis CODEC? They claim to have a FP version but it is for ARM only and is not public domain.
Thanks,
-john
John,
I think you mean non-FP right? And yes Xiph (www.xiph.org) are the only people I'm aware of who currently have a fully working integer decoder and yes it's not free/open source.
There are some basics here though: http://ivdev.sourceforge.net
HTH Christian
-----Original Message----- From: mad-dev-admin@lists.mars.org [mailto:mad-dev-admin@lists.mars.org]On Behalf Of john cooper Sent: Thursday, 18 April 2002 11:41 AM To: Rob Leslie Cc: mad-dev@lists.mars.org Subject: [mad-dev] Question on Vorbis?
Hi Rob,
Just curious if you or anyone you may know of has plans to do a FP version of the Vorbis CODEC? They claim to have a FP version but it is for ARM only and is not public domain.
Thanks,
-john
http://www.vorbis.com/
-- John Cooper johncooper@tivo.com
Christian Hack wrote:
John,
I think you mean non-FP right? And yes Xiph (www.xiph.org) are the only people I'm aware of who currently have a fully working integer decoder and yes it's not free/open source.
Sorry for the aliased terminology (FP -> fixed point).
There are some basics here though: http://ivdev.sourceforge.net
Sure looks like a work in progress, but thanks for the pointer. I wonder how the ARM licensing got tangled into the FP work..
-john
Christian,
He could mean either. FP can mean Fixed Point or Floating Point. I'm guessing he meant Fixed Point, and you mean Floating Point given the context. :)
John Stewart
----- Original Message ----- From: "Christian Hack" christianh@pdd.edmi.com.au To: mad-dev@lists.mars.org Sent: Wednesday, April 17, 2002 10:55 PM Subject: RE: [mad-dev] Question on Vorbis?
John,
I think you mean non-FP right? And yes Xiph (www.xiph.org) are the only people I'm aware of who currently have a fully working integer decoder and yes it's not free/open source.
There are some basics here though: http://ivdev.sourceforge.net
HTH Christian
-----Original Message----- From: mad-dev-admin@lists.mars.org [mailto:mad-dev-admin@lists.mars.org]On Behalf Of john cooper Sent: Thursday, 18 April 2002 11:41 AM To: Rob Leslie Cc: mad-dev@lists.mars.org Subject: [mad-dev] Question on Vorbis?
Hi Rob,
Just curious if you or anyone you may know of has plans to do a FP version of the Vorbis CODEC? They claim to have a FP version but it is for ARM only and is not public domain.
Thanks,
-john
http://www.vorbis.com/
-- John Cooper johncooper@tivo.com
Hi John,
Just curious if you or anyone you may know of has plans to do a FP version of the Vorbis CODEC? They claim to have a FP version but it is for ARM only and is not public domain.
Funny you should ask; I am in the middle of writing an article about why this is currently impossible. Until a complete specification for Vorbis is published, any independent implementation would have to be reverse-engineered, and would necessarily be inferior to the existing reference implementation, which is still evolving.
This is the reason I haven't written a fixed-point Vorbis implementation, and the reason I can't recommend any of the current ones either.
I should have my article finished soon with more details.
-rob
Rob, Thanks for the quick response. Point well taken. Certainly would like to get a copy of your article when complete.
Thanks,
-john
Rob Leslie wrote:
Hi John,
Just curious if you or anyone you may know of has plans to do a FP version of the Vorbis CODEC? They claim to have a FP version but it is for ARM only and is not public domain.
Funny you should ask; I am in the middle of writing an article about why this is currently impossible. Until a complete specification for Vorbis is published, any independent implementation would have to be reverse-engineered, and would necessarily be inferior to the existing reference implementation, which is still evolving.
This is the reason I haven't written a fixed-point Vorbis implementation, and the reason I can't recommend any of the current ones either.
I should have my article finished soon with more details.
-rob
* Rob Leslie (rob@mars.org) wrote:
Hi John,
Just curious if you or anyone you may know of has plans to do a FP version of the Vorbis CODEC? They claim to have a FP version but it is for ARM only and is not public domain.
Funny you should ask; I am in the middle of writing an article about why this is currently impossible. Until a complete specification for Vorbis is published, any independent implementation would have to be reverse-engineered, and would necessarily be inferior to the existing reference implementation, which is still evolving.
This is the reason I haven't written a fixed-point Vorbis implementation, and the reason I can't recommend any of the current ones either.
Wow, is this intentionally being withheld by Xiph so they can sell their fixed-point decoder without competition, or is a specification forthcoming?
I should have my article finished soon with more details.
Please announce it once you have!
Joshua
On Thursday, April 18, 2002, at 12:58 AM, Joshua Haberman wrote:
Wow, is this intentionally being withheld by Xiph so they can sell their fixed-point decoder without competition, or is a specification forthcoming?
I doubt the specification is being intentionally withheld, but the situation does beg the question.
I should have my article finished soon with more details.
Please announce it once you have!
I'm currently planning to submit the article to Advogato and K5. I'll be sure to send a link once the article is posted.
-rob
On Thu, 18 Apr 2002, Rob Leslie wrote:
On Thursday, April 18, 2002, at 12:58 AM, Joshua Haberman wrote:
Wow, is this intentionally being withheld by Xiph so they can sell their fixed-point decoder without competition, or is a specification forthcoming?
I doubt the specification is being intentionally withheld, but the situation does beg the question.
From the FAQ, it reads like Vorbis is a perpetual "work in progress", and
that they intend to codify it at certain "stable points" (that is, of course, my -reading- of the FAQ; your interpretation may vary :) ). In particular, this question and its answer lead me to that conclusion:
Why a forward adaptive format?
For maximum flexibility. Vorbis is meant to be actively researched and improved, so the engine, specification and algorithms are generalized to an unusual level. Although forward adaptive algorithms are probably slightly anachronistic today, their flexibility can't be beat.
On Thu, Apr 11, 2002 at 12:50:07AM -0700, Rob Leslie wrote:
Your ::ExportID3() looks good; try the following MakeID3Frame() instead:
struct id3_frame *MakeID3Frame(const char *name, const char *data) { struct id3_frame *frame; id3_latin1_t *latin1; id3_ucs4_t *ucs4;
frame = id3_frame_new(name);
latin1 = data; ucs4 = malloc((id3_latin1_length(latin1) + 1) * sizeof(*ucs4)); if (ucs4) { id3_latin1_decode(latin1, ucs4); id3_field_setstrings(&frame->fields[1], 1, &ucs4); free(ucs4); }
return frame; }
Rob,
id3_frame_new and id3_latin1_decode don't seem to be in the public id3lib.h. At least not in 0.14.2b-2.
Also, I was wondering if you could allow access to the array of genres. This is useful for writing id3 editors that want to offer the user a list of available genres.
I am implementing the tag editor for my xmms plugin which (BTW) now matched the mpglib based one feature for feature (almost ;)
cheers sam
Apologies for my last message in which I asked two questions that had already been asked in this thread :)
Mailman had temporally suspended delivery (due my DNS troubles) so I never saw the rest of the thread.
Anyway, thanks Rob for answering the questions.
sam