ftblog

:: widerstand zwecklos ::
email jabber gpgkey
hackergotchi

March 10, 2008

audio helpers

Filed under: computer -- 10:53

Being sick in bed tends to have the slightly positive effect, that
I am working on hobby related issues, rather than work related ones
(work still being university and everything, that goes along with it).

This time, the little helpers I use for audio file meta information
manipulation (read: playing with tags) underwent noticeable changes.
Actually, I am almost at the point, where I would say they are more or
less feature complete.

Oh, and this text will be rather longish... So, if you're not interested
in either program, stop reading now. Seriously, this became too long. :-)

I'll take a closer look at what they are, what they can do and how I use
them myself.


So, what's this all about?

Dealing with audio file tags on the command line tends to be quite a pain
in the ass. If you focus on three of the major audio file formats (being
mp3, ogg vorbis and flac), you get no less than (yes, you expected it)
three tools to deal with these formats' meta information. All of these use
different tag names and options and/or behave substantially different from
each other.

This is exactly where the zsh function atag() comes into play.

atag() provides a consistent way to the aforementioned file formats meta
information; well, that's partly a lie. It provides consistent access to
the, in my humble opinion, most important tags used in audio files (being:
artist, album, track number, track title, compilation name, year and
genre). And those are really the only tags *I* care about. If you want
others to be supported, send a clean patch. (Oh, and the number one
requirement is, that the tag must be present in all three file formats.)

In addition to that, atag can provide the meta information from the files
to the calling shell instance. That means, that atag, while being a
frontend for the manipulation tools, can be heavily scripted by all means
zsh provides and thus be a backend for highlevel tools (see below).

Note: Yes, this is really limited to zsh. If you do not use zsh, atag() is
not for you (if you try to use it with bash, bash won't be able to
correctly parse atag, at all. sorry). If you are, though, you'll be happy
to hear, that atag comes with a useful completion widget, which can guide
you through the process of using it.


Another thing, that has really bothered me for quite some time now, is how
to get meta information out of the audio files and create a consistent
file name of them automatically and for the same three file formats atag()
supports. ...and so, arename.pl was born.

arename.pl takes a format string, which describes, how the destination
file name should look like, gets the meta information from the files fills
in expressions within the format string with the according data and rename
the file in question accordingly (creating needed subdirectories in the
process).

The arename package also provides a utility script (ataglist.pl), which is
used by atag() to provide the '-e' functionality (which is the feature,
that makes tag information know to the calling shell). That shows, that
these two helpers are related to each other and together provide a powerful
interface to audio file meta information and their according file names.


Um, okay... Well, why arename.pl? Can't you just let abcde produce a
useful filename for you while you're ripping your CDs to disk?


I could.

However, the problem is, that I am using different naming schemes for
different types of audio files (music has its own scheme and audio books
get their own, too, which is different from the one music uses).

Also, I like to let abcde rip the data from the CD to a single folder,
where I can then inspect the produced files, for correctness and after that
move them to my main archive. That is kind of my workflow when I'm ripping
audio CDs.

And finally, I tend to change my mind over time. Thus a naming scheme,
which was perfect a year ago might seem totally ugly to me today. With
arename.pl it is trivial to change the naming scheme, because all the
program needs are properly set up tags.

arename.pl can be fairly flexibly configured via different configuration
files, as well as Perl code, that can be registered to hooks (code that is
called at certain events during the execution of the script). You have one
"global" configuration file (~/.arenamerc) which does the default setup,
that you would like to be in place always. And then, you can place a
"local" config file into every working directory, you'd like
(./.arename.local), where you can setup arename.pl's parameters according
to the needs of that special directory. The same is true for
hook-definition files (although the local hook-definition files are
disabled by default).


Right. So, what can atag() do for me?

Well... it tags audio files for you, as I said above.

% atag "Foo - Bar - Baz.flac" artist='Foo'

...sets the tag, that reflects the name of the artist in the audio file to
'Foo'. No need to figure out, how to metaflac deals with that.

While this is simple and useful, you might argue, why to bother with
atag(), when there are other programs, that do just the same. That is a
valid doubt. So lets think about a slightly more complicated example.

Let's say, you just ripped two Albums, one by Peter Gabriel, the other by
Frank Zappa. Imagine the guys, who submitted the cddb data for the CDs,
which abcde (or whatever cd ripping tool) used to make up the tagging data,
happened to like the 'surname, first-name' notation. ...and you just
happened to miss that, when you were ripping the discs. But you really
really really prefer to see 'first-name surname'.

Let's say these files (we'll assume .ogg) where ripped to /tmp/encode.

% for file in /tmp/encode/*.ogg ; do
for>   atag ${file} -e
for>   atag ${file} ar=${_ar/(#b)(*), (*)/${match[2]} ${match[1]}}
for> done

Done. The '-e' call makes meta information known to the calling shell (like
the name of the artist in $_ar). The 2nd atag()-call uses some
zsh-expansion magic, to rewrite the artist name to the wanted format.

So, if you are comfortable with zsh scripting, your possibilities are
virtually boundless. And even if you are not, that can still be used to do
simpler fixes.

Another example:
Let's say, you got this big mp3 from a podcast. Three hours. You decide to
use mp3splt to split it into logical parts. While mp3splt can write tags to
its output files itself, we'll ignore that for now; we can do it more
flexibly anyway.

% integer e ; (( e = 1 ))
% parts=(out-*.mp3)
% atag "My podcast input file.mp3" -e
% for i in $parts ; do
for>   _tn=${(l:2::::0:)$((e++))}
for>   _tt="Part ${_tn}of${#parts}"
for>   atag $i ar=$_ar al=$_al tt=$_tt tn=$_tn y=$_yr g=$_gr
for> done

Or, a useful but a lot simpler one:

% for i in *.ogg ; do
for>   atag $i -e
for>   atag $i -f al=$_al ar=$_ar tt=$_tt tn=$_tn y=$_yr comp=$_comp g=$_gr
for> done

...will result in the removal of all tags in the matched ogg-files, that
are not supported by atag(). This maybe useful to remove unwanted tags,
like comments or cover pictures.

When cleaning up my music folder, I found that useful enough to create a
frontend function to atag(), which does exactly that: atag-reset()

So, in short, the following does exactly the same, as the loop above:

% atag-reset *.ogg

This is probably too simple, to really call this a frontend. A more
advanced frontend would be atag-editor().

atag-editor() takes a list of file names, reads their meta information and
writes it to a temp-file, on which it then starts an editor. When you exit
the editor, it re-reads the temp-file and sets new tags based on the
information in the edited file. Everything based on atag(). This way, users
who are not familiar with zsh scripting, can still do stunts like the
artist-name-format change, in the earlier example (if their favorite editor
can do it; vim and emacs can, of course).

Let's imagine, we got some files, in which the tags are not exactly the way
we want them to be; so, let's launch atag-editor on them:

atag-editor 0

That will drop us into our favourite editor (vim in my case):

atag-editor 1

Now we decide, that 'the', 'in' and 'of' really don't need to be
uppercased. (You don't have to remove all other tags as I did, of course. I
only did it to let it fit into the screenshot):

atag-editor 2

The moment we save&exit the editor, the modified data is read and atag()
takes over:

atag-editor 3

atag(), atag-reset() and atag-editor() all come with full working
completion widgets for zsh's compsys. All options and arguments are
supported.

Simple enough, I would say.


Okay, that's atag(). But what about arename.pl? How do you use it?

In its simplest form:

% arename.pl /tmp/encode/*.ogg

And that's it.
arename.pl is fairly well documented, so let me get straight to what I am
doing with it. Like renaming music I just ripped:

% cd /mnt/extern/audio/music
% arename.pl -d /mnt/extern/tmp/encode/*.(#i)(ogg|mp3|flac)
    [..check, check, check..]
% arename.pl /mnt/extern/tmp/encode/*.(#i)(ogg|mp3|flac)

...well, pretty much the simplest form, you saw above. Just with a dry-run
before the actual run (which is something I normally do, just to be
double-damn sure, I didn't screw up).

And you know what? That's about the same procedure, I use when I'm renaming
audio-books, that abcde just ripped to my harddisk:

% cd /mnt/extern/audio/hoerspiel
% arename.pl -d /mnt/extern/tmp/encode/*.(#i)(ogg|mp3|flac)
    [..check, check, check..]
% arename.pl /mnt/extern/tmp/encode/*.(#i)(ogg|mp3|flac)

Just the same. The difference is the working directory. With arename.pl,
that makes a big difference, because I happen to have a .arename.local in
both of those directories. In my case, these files set up appropriate
template strings so I get the naming scheme I want for either content type.

That means, I am using three different templates, without even bothering to
use the '-t' or '-T' options (which I still could, if that would be
required).

Now, for mass renaming (in case I want to change a naming scheme), another
problem comes into play. The maximum length for argument lists to external
programs. With atag() etc that was not an issue, because as zsh functions,
they are not external programs. arename.pl however, is a perl script, which
means it runs as an external program call. If I run into that limit
problem, I normally do this:

% zargs -- **/*.(ogg|mp3|flac) -- arename.pl -[options]

Yeah, I'm a zsh-nut... You can do about the same, using find and its -exec
option; or find and xargs, if you insist. But starting with version 1.1 of
the script, you don't have to. You can just do:

% find -name "*.mp3" -print | arename.pl -s -[options]

It's important that '-s' is used along with the other options to
arename.pl. It causes it to read filenames from the standard input; one
file name per line.

A huge issue for a lot of people are whitespace in file names (which I
still fail to see why). I like them. It looks a lot more natural to me, and
seriously, if you are able to write proper shell scripts, whitespace is
really just another character. Because of that, arename.pl was not able to
replace whitespace with underscores (I just couldn't motivate myself to
invent a useful replacement implementation).

With version 1.1 it got the ability to define hooks; Perl code, which is
called at certain events during the script's execution. And guess what:
Perl has this crazily flexible regular expression engine. BAM, there you
got your replacements.

Lets say, you got this in ~/.arename.hooks:

sub replace_spaces_by_underscore {
    my ($namespace, $templateref, $datref) = @_;
    $$templateref =~ s/\s+/_/g;
}
register_hook('post_expand_template', \&replace_spaces_by_underscore);

...and you're done.

Hooks can do all sorts of stuff and there are more then 25 events in the
code when they are triggered. If you solve a problem by using hooks, let me
know. The example hooks file in the arename.pl package can always use new
entries. :-)


Alright, this should give you a little more insight on how you could use
those little helpers. They really do work for me and better than anything
else I used before. And I use them on my own audio files. So, yes I
consider them stable enough to handle my data. I do use the dry-run options
to both programs very regularly, though. Safety first.


If you read your way down here, you really seem to be interested. :-)
That means someone needs to tell you where to get those two:

As mentioned earlier in this blog, arename.pl can be found on its homepage.
Just grab the latest stable release and use it. Installation instructions
can be found in the README file. It's trivial. Honestly.

atag() is a bit different. Upto now, it was only part of my zsh-setup.
But since it does not rely on anything in my config, I thought, it would be
useful to have a seperate tarball, to ease fetching the functions.
The tarball does *not* create a subdirectory. Just extract it somewhere in
your shell's $fpath, restart zsh and things should work.

Powered by zblog
valid css | valid xhtml | utf-8 encoded | best viewed with anybrowser