Discussion:
[mad-user] rendering using libid3tag
Dominic Mazzoni
2002-04-11 05:26:28 UTC
Permalink
Hi,

In developing Audacity (a cross-platform audio editor), I've
continued to have nothing but good experiences with libmad.
I recently added support for 24-bit and 32-bit samples in
Audacity, and it's great that using libmad I can take
advantage of these sample formats.

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.

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.

1. 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.

2. 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?)

3. When I try to enable the ID3_TAG_OPTION_ID3V1,
the rendering fails. Is it supported?

4. 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?

I'm including some of my source code below. Thanks for
any help anyone can offer.

- Dominic



struct id3_frame *MakeID3Frame(const char *name, const char *data)
{
struct id3_frame *frame;
union id3_field *field;
id3_ucs4_t *ustr;
int i;

ustr = (id3_ucs4_t *)malloc(sizeof(id3_ucs4_t)*(strlen(data)+1));
for(i=0; i<strlen(data)+1; i++)
ustr[i] = (id3_ucs4_t)data[i];

field = (union id3_field *)calloc(1, sizeof(union id3_field));
field->type = ID3_FIELD_TYPE_STRINGLIST;
id3_field_setstrings(field, 1, &ustr);

frame = (struct id3_frame *)calloc(1, sizeof(struct id3_frame));
strncpy(frame->id, name, 4);
frame->nfields = 1;
frame->fields = field;

return frame;
}

// returns buffer len; caller frees
int Tags::ExportID3(char **buffer, bool *endOfFile)
{
struct id3_tag *tp;
struct id3_frame *frame;

tp = id3_tag_new();

id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_TITLE, mTitle));
id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_ARTIST, mArtist));
id3_tag_attachframe(tp, MakeID3Frame(ID3_FRAME_ALBUM, mAlbum));

if (mID3V2) {
tp->options |= ID3_TAG_OPTION_COMPRESSION;
*endOfFile = false;
}
else {
tp->options |= ID3_TAG_OPTION_ID3V1;
*endOfFile = true;
}

id3_length_t len;

len = id3_tag_render(tp, 0);
*buffer = (char *)malloc(len);
len = id3_tag_render(tp, (id3_byte_t *)*buffer);

id3_tag_delete(tp);

return len;
}
Rob Leslie
2002-04-11 07:50:07 UTC
Permalink
[This thread belongs on mad-dev; note Reply-To. Dominic, I'm not sure
whether you're subscribed there...]
Post by Dominic Mazzoni
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.
Post by Dominic Mazzoni
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.
1. 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.
Post by Dominic Mazzoni
2. 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().
Post by Dominic Mazzoni
3. 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...
Post by Dominic Mazzoni
4. 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.
Post by Dominic Mazzoni
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
***@mars.org

Loading...