Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: flac tags in perl (Read 3779 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

flac tags in perl

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

flac tags in perl

Reply #1
You asked, and so you receive: some code I had 'lying around' for just this purpose.

Code: [Select]
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;
}

flac tags in perl

Reply #2
Thank you very much,  it would have taken me months to get that done.  I really appreciate it.

--Stephen

flac tags in perl

Reply #3
you don't need this overhead.

Code: [Select]
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.

flac tags in perl

Reply #4
Perl Fan:

Very Good Script, Thanks for these one too. B)

flac tags in perl

Reply #5
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.