#!/usr/bin/perl # Reference taglib-1.9.1 doc TagLib::MPEG::Header # and http://www.mp3-tech.org/programmer/frame_header.html package MPEG_Header; my %header = ( 'FrameSync' => [31,21], # Frame sync (all bits must be set) 'VersionID' => [20,19], # MPEG Audio version ID 'Layer' => [18,17], # Layer description 'Protection' => [16,16], # Protection bit 'BitRate' => [15,12], # Bitrate index 'SamplingRate' => [11,10], # Sampling rate frequency index 'Padding' => [9,9], # Padding bit 'Private' => [8,8], # Private bit. This one is only informative. 'ChannelMode' => [7,6], # Channel Mode 'ModeExtension' => [5,4], # Mode extension (Only used in Joint stereo) 'Copyright' => [3,3], # Copyright 'Original' => [2,2], # Original 'Emphasis' => [1,0], # Emphasis ); my %VersionID = ('2.5' => 0b00, '2' => 0b10, '1' => 0b11, ); my %Layer = ('III' => 0b01, 'II' => 0b10, 'I' => 0b11, ); my %Padding = ('Pad' => 0b1, 'NoPad' => 0b0, ); my %Protection = ('Protected' => 0b0, 'NotProtected' => 0b1, ); my %ChannelMode = ('Stereo' => 0b00, 'JointStereo' => 0b01, 'DualChannel' => 0b10, 'SingleChannel' => 0b11, ); my %Copyright = ('No', => 0b0, 'Yes' => 0b1, ); my %Original = ('Copy' => 0b0, 'Original' => 0b1, ); my %Emphasis = ('None' => 0b00, '5015' => 0b01, 'CCIT' => 0b11, ); sub _set_header_field { my ($hdr, $field, $value) = @_; warn "Field $field is not defined in the MPEG header\n" unless $header{$field}; my $first = $header{$field}->[0]; my $last = $header{$field}->[1]; $hdr = pack("B*", "0"x32) unless defined $hdr; my ($pos, $off); if ( defined $value ) { # Field value assignment # Possible symbolic reference no strict 'refs'; # For symbolic reference $value = $$field{$value} if exists $$field{$value}; my $width = $first - $last + 1; for ($pos = $first; $width; $width --, $pos --) { $off = 31 - $pos; vec($hdr, $off, 1) = vec($value, $width - 1, 1); } return $hdr; } # Fill field with 1s for ($pos = $first; $pos >= $last; $pos --) { $off = 31 - $pos; vec($hdr, $off, 1) = 1; } return $hdr; } sub build_header { my %args = @_; my $header; $header = _set_header_field( $header, 'FrameSync' ); # All headers have this foreach my $key ( keys %args ) { $header = _set_header_field( $header, $key, $args{$key} ); } return $header; } 1; =if 0 #! /usr/bin/perl use lib '.'; use MPEG_Header; my $mpeg_header = MPEG_Header::build_header( 'VersionID' => 2, 'Layer' => 'III', 'Protection' => 'NotProtected', 'BitRate' => 0b1000, # 64 kbps for V2 and L3 'SamplingRate' => 0b10, # 16000 Hz for V2 'Padding' => 'Pad', 'ChannelMode' => 'Stereo', 'Copyright' => 'No', 'Original' => 'Yes', 'Emphasis' => 'CCIT', ); printf "b %-s\n", unpack("b*", $mpeg_header); printf "B %-s\n", unpack("B*", $mpeg_header); Spaces added. Unpack with b vs B. b 11111111 11110010 10001000 11000111 00001100 B 11111111 01001111 00010001 11100011 00110000 =cut