Help - Search - Members - Calendar
Full Version: flac tags in perl
Hydrogenaudio Forums > Lossless Audio Compression > FLAC
jsj123
I lost my drive that contained all of my mp3's and flac files last weekend. All I had been backing up was the flac files, thinking I could easily transcode to mp3 if needed.

I didn't know Perl, so it has been an entertaining couple of days. I stole some Perl from Josh (thanks much) that uses mp3::info to extract tags from the flac files. It doesn't find the tags, which leads me to believe that I don't have mp3 tags in my flac files. DBPower Amp says I have flac tags, and I used tag.exe to create the tags.

How do I extract flac tags in perl?

Thanks you very much.

--Stephen
Cerebus
You asked, and so you receive: some code I had 'lying around' for just this purpose.

CODE

my $last_block_flag = 1 << 31;
my $block_type_flag = 127 << 24;
my $m_len_flag = 255 + 256*255 + 256*256*255;

my $STREAMINFO=0;
my $PADDING=1;
my $APPLICATION=2;
my $SEEKTABLE=3;
my $VORBIS_COMMENT=4;
my $CUESHEET=5;

# Only argument is filename, with full path
sub read_flac
{
my $filename = shift;
my $fileinfo = {};
my ($flac_indicator,$tmp);
my ($meta_head,$meta_last,$meta_type,$meta_size,$meta_contents);
my ($meta_list,$numheads,$thr,@retlist);


# Check for existence & readability
-e $filename or return -1;
-r $filename or return -2;

$fileinfo->{filename} = $filename;

if (-w $filename)
{
 $fileinfo->{mode} = "Read/Write";
}
else
{
 $fileinfo->{mode} = "Read Only";
}

open(FLACFILE,$filename) or return -5;
binmode FLACFILE;

read FLACFILE, $flac_indicator,4 or return -3;

if ($flac_indicator ne "fLaC")
{
 close FLACFILE;
 return -4;
}

$meta_list=[];

$numheads = 0;

while(1)
{

 read FLACFILE, $tmp, 4 or return -3;

 $meta_head = unpack "N",$tmp;

 # What's the info stored here?
 $meta_last = ($last_block_flag & $meta_head)>>31;
 $meta_type = ($block_type_flag & $meta_head)>>24;
 $meta_size = $m_len_flag & $meta_head;

 read FLACFILE,$meta_contents,$meta_size or return -3;

 $thr =  {Last => $meta_last,
    Type => $meta_type,
    Size => $meta_size,
    Contents => $meta_contents};

 $meta_list->[$numheads] = $thr;
 $numheads++;
 
 if ($meta_type==4)
 {
  # This is the Vorbis tag
  $fileinfo->{tags} = parse_vorbis_header($meta_contents);
 }

 if ($meta_last)
 {
  last;
 }
}

$fileinfo->{start} = tell FLACFILE;

close FLACFILE;

$fileinfo->{headers} = $meta_list;

return $fileinfo;
}

sub parse_vorbis_header
{
# All Vorbis tags are in little-endian format

# first, vendor length
my $tagstring = shift;
my ($vendor_length,$vendor_string);
my ($numtags,$i);
my ($lnlen,$lnstr);
my ($tag_key, $tag_val);
my $taghash = {};
my @list;

$vendor_length = substr($tagstring,0,4);
$vendor_length = unpack "L",$vendor_length;

$tagstring = substr($tagstring,4);

$vendor_string = substr($tagstring,0,$vendor_length);

$taghash->{Vendor} = $vendor_string;

$tagstring = substr($tagstring,$vendor_length);

$numtags = substr($tagstring,0,4);
$numtags = unpack "L",$numtags;

$tagstring = substr($tagstring,4);

for ($i=0;$i<$numtags;$i++)
{
 $lnlen = substr($tagstring,0,4);
 $tagstring = substr($tagstring,4);
 $lnlen = unpack "L",$lnlen;

 $lnstr = substr($tagstring,0,$lnlen);
 $tagstring = substr($tagstring,$lnlen);

 # parse for '='
 if ($lnstr =~ /(.*?)=(.*)/)
 {
  $tag_key = $1;
  $tag_key =~ tr/a-z/A-Z/;
  $tag_val = $2;
  $taghash->{$tag_key} = $tag_val;
 }
}

return $taghash;
}
jsj123
Thank you very much, it would have taken me months to get that done. I really appreciate it.

--Stephen
BadHorsie
you don't need this overhead.

CODE

my @buffer = split /\=/, `metaflac --show-vc-field=artist \"file.flac\"`;
my $artist = chomp $buffer[1];


your artist is stored in $artist ;-)
whit this code you need only one line for every entry.

BadHorsie

BTW: the mp3::info module works just for id3 tags. usually flac uses vorbis tags. i would let the encoder write the tags and use metaflac to display them. metaflac can also write/remove replaygain informations.
Sniffer
Perl Fan:

Very Good Script, Thanks for these one too. B)
Cerebus
I was trying to do it *without* metaflac. In the process, I learned a lot about a number of things, and could handle things for my purposes at a much lower level...but, as usual, there are lots of ways to do things with perl. wink.gif
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2008 Invision Power Services, Inc.