Reading and writing mp3 metadata

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Reading and writing mp3 metadata

luciano de souza-2
Hello all,
I am trying to create a small tool that reads and writes mp3 metadata.
It's really easy. The last 128 bytes of a mp3 file stores the required
information.
In Pascal, the structure representing mp3 metadata is:

type
TID3 = record
signature: array[0..2] of char;
title, artist, album: array[0..29] of char;
year: array[0..3] of char;
comment: array[0..29] of char;
genre: byte;
end;

My first difficult is: how to represent a Lua 128 bytes structure like that.
And how can I read the last 128 bytes of a file and attibutes it to a
structure, probably a table, with this fields, sized with the given
values?
In order words, I don't know what I should use to read and write a set
of bytes in Lua and I don't know how to represent C or Pascal
structures.
Best regards,
Luciano

Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

steve donovan
On Tue, Apr 30, 2013 at 1:00 PM, luciano de souza <[hidden email]> wrote:
In order words, I don't know what I should use to read and write a set
of bytes in Lua and I don't know how to represent C or Pascal
structures.

The struct library does the needed packing/unpacking:

http://www.inf.puc-rio.br/~roberto/struct/

If you need speed, then LuaJIT is an attractive proposition since you can feed its FFI a struct definition in C format.


Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

Luiz Henrique de Figueiredo
In reply to this post by luciano de souza-2
> TID3 = record
> signature: array[0..2] of char;
> title, artist, album: array[0..29] of char;
> year: array[0..3] of char;
> comment: array[0..29] of char;
> genre: byte;
> end;
>
> My first difficult is: how to represent a Lua 128 bytes structure like that.
> And how can I read the last 128 bytes of a file and attibutes it to a
> structure, probably a table, with this fields, sized with the given
> values?

function subl(s,i,l) return i+l,s:sub(i,i+l-1) end

f = io.open("foo.mp3","rb")
h = f:read(128)
f:close()
t = {}
i = 1
i,t.signature = subl(h,i,3)
i,t.title = subl(h,i,30)
i,t.artist = subl(h,i,30)
i,t.album = subl(h,i,30)
i,t.year = subl(h,i,4)
i,t.comment = subl(h,i,30)
i,t.genre = subl(h,i,1)

Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

luciano de souza-2
In reply to this post by steve donovan
I thank you very much. I will study this module and I am sure it will
solve my problem.


2013/4/30, steve donovan <[hidden email]>:

> On Tue, Apr 30, 2013 at 1:00 PM, luciano de souza
> <[hidden email]>wrote:
>
>> In order words, I don't know what I should use to read and write a set
>> of bytes in Lua and I don't know how to represent C or Pascal
>> structures.
>>
>> The struct library does the needed packing/unpacking:
>
> http://www.inf.puc-rio.br/~roberto/struct/
>
> If you need speed, then LuaJIT is an attractive proposition since you can
> feed its FFI a struct definition in C format.
>


--
Luciano de Souza

Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

Peter Cawley
In reply to this post by Luiz Henrique de Figueiredo
On Tue, Apr 30, 2013 at 12:51 PM, Luiz Henrique de Figueiredo
<[hidden email]> wrote:
> f = io.open("foo.mp3","rb")
> h = f:read(128)
> f:close()

Isn't h the first 128 bytes in this instance rather than the last 128 bytes?

Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

Luiz Henrique de Figueiredo
> On Tue, Apr 30, 2013 at 12:51 PM, Luiz Henrique de Figueiredo
> <[hidden email]> wrote:
> > f = io.open("foo.mp3","rb")
> > h = f:read(128)
> > f:close()
>
> Isn't h the first 128 bytes in this instance rather than the last 128 bytes?

Oops, I missed that. You need to seek before reading:
        f:seek("end",-128)
        h = f:read(128)

Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

Daurnimator
In reply to this post by luciano de souza-2
On 30 April 2013 07:00, luciano de souza <[hidden email]> wrote:

> Hello all,
> I am trying to create a small tool that reads and writes mp3 metadata.
> It's really easy. The last 128 bytes of a mp3 file stores the required
> information.
> In Pascal, the structure representing mp3 metadata is:
>
> type
> TID3 = record
> signature: array[0..2] of char;
> title, artist, album: array[0..29] of char;
> year: array[0..3] of char;
> comment: array[0..29] of char;
> genre: byte;
> end;
>
> My first difficult is: how to represent a Lua 128 bytes structure like that.
> And how can I read the last 128 bytes of a file and attibutes it to a
> structure, probably a table, with this fields, sized with the given
> values?
> In order words, I don't know what I should use to read and write a set
> of bytes in Lua and I don't know how to represent C or Pascal
> structures.
> Best regards,
> Luciano
>

Looks like you're trying to read ID3v1.
You may want to look to
https://github.com/daurnimator/lamt/blob/master/id3v1.lua#L53 for
inspiration.

Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

Luiz Henrique de Figueiredo
> You may want to look to
> https://github.com/daurnimator/lamt/blob/master/id3v1.lua#L53 for
> inspiration.

My code was indeed too complicated. Try this

f = io.open("foo.mp3","rb")
f:seek("end",-128)
t = {}
t.signature = f:read(3)
t.title     = f:read(30)
t.artist    = f:read(30)
t.album     = f:read(30)
t.year      = f:read(4)
t.comment   = f:read(30)
t.genre     = f:read(1)
f:close()

Reply | Threaded
Open this post in threaded view
|

Re: Reading and writing mp3 metadata

Daurnimator
On 30 April 2013 12:01, Luiz Henrique de Figueiredo
<[hidden email]> wrote:

>> You may want to look to
>> https://github.com/daurnimator/lamt/blob/master/id3v1.lua#L53 for
>> inspiration.
>
> My code was indeed too complicated. Try this
>
> f = io.open("foo.mp3","rb")
> f:seek("end",-128)
> t = {}
> t.signature = f:read(3)
> t.title     = f:read(30)
> t.artist    = f:read(30)
> t.album     = f:read(30)
> t.year      = f:read(4)
> t.comment   = f:read(30)
> t.genre     = f:read(1)
> f:close()
>

You will also need to post-process those strings by stripping trailing
whitespace and nulls and converting to the correct encoding (id3v1 is
usually created in the encoder's codepage.... and most id3v1 tags were
created back in the 90s)
Also genre should be looked up in this[1] table.

[1] https://github.com/daurnimator/lamt/blob/master/genrelist.lua