Version: 1

Type: Class

Category: File Management

License: Other

Description: Extract, splice and tag MP3 files using PHP (ONLY). LGPL licensed Originally posted on: http://www.sourcerally.net/Scripts/20-PHP-MP3-Class



<?php
/*
//Merge two files
$path = 'path.mp3';
$path1 = 'path1.mp3';
$mp3 = new mp3($path);

$newpath = 'path.mp3';
$mp3->striptags();

$mp3_1 = new mp3($path1);
$mp3->mergeBehind($mp3_1);
$mp3->striptags();
$mp3->setIdv3_2('01','Track Title','Artist','Album','Year','Genre','Comments','Composer','OrigArtist',
'Copyright','url','encodedBy');
$mp3->save($newpath);


//Extract 30 seconds starting after 10 seconds.
$path = 'path.mp3';
$mp3 = new mp3($path);
$mp3_1 = $mp3->extract(10,30);
$mp3_1->save('newpath.mp3');

*/
class mp3
{
    var $str;
    var $time;
    var $frames;
    
    function mp3($path="")
    {
        if($path!="")
        {
            $this->str = file_get_contents($path);
        }
    }
    
    function setStr($str)
    {
        $this->str = $str;
    }
    
    function setFileInfoExact()
    {
        $maxStrLen = strlen($this->str);
        $currentStrPos = strpos($this->str,chr(255));
        $framesCount=0;
        $time = 0;
        while($currentStrPos < $maxStrLen)
        {
            $str = substr($this->str,$currentStrPos,4);
            $strlen = strlen($str);
            $parts = array();
            for($i=0;$i < $strlen;$i++)
            {
                $parts[] = $this->decbinFill(ord($str[$i]),8);
            }
            if($parts[0] != "11111111")
            {
                if(($maxStrLen-128) > $currentStrPos)
                {
                    return false;
                }
                else
                {
                    $this->time = $time;
                    $this->frames = $framesCount;
                    return true;
                }
            }
            $a = $this->doFrameStuff($parts);
            $currentStrPos += $a[0];
            $time += $a[1];
            $framesCount++;
        }
        $this->time = $time;
        $this->frames = $framesCount;
        return true;
    }
    
    function extract($start,$length)
    {
        $maxStrLen = strlen($this->str);
        $currentStrPos = strpos($this->str,chr(255));
        $framesCount=0;
        $time = 0;
        $startCount = -1;
        $endCount = -1;
        while($currentStrPos < $maxStrLen)
        {
            if($startCount==-1&&$time>=$start)
            {
                $startCount = $currentStrPos;
            }
            if($endCount==-1&&$time>=($start+$length))
            {
                $endCount = $currentStrPos-$startCount;
            }
            $doFrame = true;
            $str = substr($this->str,$currentStrPos,4);
            $strlen = strlen($str);
            $parts = array();
            for($i=0;$i < $strlen;$i++)
            {
                $parts[] = $this->decbinFill(ord($str[$i]),8);
            }
            if($parts[0] != "11111111")
            {
                if(($maxStrLen-128) > $currentStrPos)
                {
                    $doFrame = false;
                }
                else
                {
                    $doFrame = false;
                }
            }
            if($doFrame)
            {
                $a = $this->doFrameStuff($parts);
                $currentStrPos += $a[0];
                $time += $a[1];
                $framesCount++;
            }
        }
        $mp3 = new mp3();
        if($endCount == -1)
        {
            $endCount = $maxStrLen-$startCount;
        }
        if($startCount!=-1&&$endCount!=-1)
        {
            $mp3->setStr(substr($this->str,$startCount,$endCount));
        }
        return $mp3;
    }
    
    function decbinFill($dec,$length=0)
    {
        $str = decbin($dec);
        $nulls = $length-strlen($str);
        if($nulls>0)
        {
            for($i=0;$i<$nulls;$i++)
            {
                $str = '0'.$str;
            }
        }
        return $str;
    }
    
    function doFrameStuff($parts)
    {
        //Get Audio Version
        $errors = array();
        switch(substr($parts[1],3,2))
        {
            case '01':
            $errors[]='Reserved audio version';
            break;
            case '00':
            $audio = 2.5;
            break;
            case '10':
            $audio = 2;
            break;
            case '11':
            $audio = 1;
            break;
        }
        //Get Layer
        switch(substr($parts[1],5,2))
        {
            case '01':
            $layer = 3;
            break;
            case '00':
            $errors[]='Reserved layer';
            break;
            case '10':
            $layer = 2;
            break;
            case '11':
            $layer = 1;
            break;
        }
        //Get Bitrate
        $bitFlag = substr($parts[2],0,4);
        $bitArray = array(
    '0000'    => array(free,    free,    free,    free,    free),
    '0001'    => array(32,    32,    32,    32,    8),
    '0010'    => array(64,    48,    40,    48,    16),
    '0011'    => array(96,    56,    48,    56,    24),
    '0100'    => array(128,    64,    56,    64,    32),
    '0101'    => array(160,    80,    64,    80,    40),
    '0110'    => array(192,    96,    80,    96,    48),
    '0111'    => array(224,    112,    96,    112,    56),
    '1000'    => array(256,    128,    112,    128,    64),
    '1001'    => array(288,    160,    128,    144,    80),
    '1010'    => array(320,    192,    160,    160,    96),
    '1011'    => array(352,    224,    192,    176,    112),
    '1100'    => array(384,    256,    224,    192,    128),
    '1101'    => array(416,    320,    256,    224,    144),
    '1110'    => array(448,    384,    320,    256,    160),
    '1111'    => array(bad,    bad,    bad,    bad,    bad)
    );
        $bitPart = $bitArray[$bitFlag];
        $bitArrayNumber;
        if($audio==1)
        {
            switch($layer)
            {
                case 1:
                $bitArrayNumber=0;
                break;
                case 2:
                $bitArrayNumber=1;
                break;
                case 3:
                $bitArrayNumber=2;
                break;
            }
        }
        else
        {
            switch($layer)
            {
                case 1:
                $bitArrayNumber=3;
                break;
                case 2:
                $bitArrayNumber=4;
                break;
                case 3:
                $bitArrayNumber=4;
                break;
            }
        }
        $bitRate = $bitPart[$bitArrayNumber];
        //Get Frequency
        $frequencies = array(
        1=>array('00'=>44100,
        '01'=>48000,
        '10'=>32000,
        '11'=>'reserved'),
        2=>array(),
        2.5=>array());
        $freq = $frequencies[$audio][substr($parts[2],4,2)];
        //IsPadded?
        $padding = substr($parts[2],6,1);
        if($layer==3||$layer==2)
        {
            //FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
            $frameLength = 144 * $bitRate * 1000 / $freq + $padding;
        }
        $frameLength = floor($frameLength);
        $seconds += $frameLength*8/($bitRate*1000);
        return array($frameLength,$seconds);
        //Calculate next when next frame starts.
        //Capture next frame.    
    }
    
    function setIdv3_2($track,$title,$artist,$album,$year,$genre,$comments,$composer,$origArtist,
$copyright,$url,$encodedBy)
    {
        $urlLength = (int)(strlen($url)+2);
        $copyrightLength = (int)(strlen($copyright)+1);
        $origArtistLength = (int)(strlen($origArtist)+1);
        $composerLength = (int)(strlen($composer)+1);
        $commentsLength = (int)strlen($comments)+5;
        $titleLength = (int) strlen($title)+1;
        $artistLength = (int)strlen($artist)+1;
        $albumLength = (int) strlen($album)+1;
        $genreLength = (int) strlen($genre)+1;
        $encodedByLength = (int)(strlen($encodedBy)+1);
        $trackLength = (int) strlen($track) + 1;
        $yearLength = (int) strlen($year)+1;
        $str .= chr(73);//I
        $str .= chr(68);//D
        $str .= chr(51);//3
        $str .= chr(3);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(8);//
        $str .= chr(53);//5
        $str .= chr(84);//T
        $str .= chr(82);//R
        $str .= chr(67);//C
        $str .= chr(75);//K
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($trackLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $track;
        $str .= chr(84);//T
        $str .= chr(69);//E
        $str .= chr(78);//N
        $str .= chr(67);//C
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($encodedByLength);//
        $str .= chr(64);//@
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $encodedBy;
        $str .= chr(87);//W
        $str .= chr(88);//X
        $str .= chr(88);//X
        $str .= chr(88);//X
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($urlLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $url;
        $str .= chr(84);//T
        $str .= chr(67);//C
        $str .= chr(79);//O
        $str .= chr(80);//P
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($copyrightLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $copyright;
        $str .= chr(84);//T
        $str .= chr(79);//O
        $str .= chr(80);//P
        $str .= chr(69);//E
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($origArtistLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $origArtist;
        $str .= chr(84);//T
        $str .= chr(67);//C
        $str .= chr(79);//O
        $str .= chr(77);//M
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($composerLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $composer;
        $str .= chr(67);//C
        $str .= chr(79);//O
        $str .= chr(77);//M
        $str .= chr(77);//M
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($commentsLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(9);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $comments;
        $str .= chr(84);//T

        $str .= chr(67);//C
        $str .= chr(79);//O
        $str .= chr(78);//N
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($genreLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $genre;
        $str .= chr(84);//T
        $str .= chr(89);//Y
        $str .= chr(69);//E
        $str .= chr(82);//R
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($yearLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $year;
        $str .= chr(84);//T
        $str .= chr(65);//A
        $str .= chr(76);//L
        $str .= chr(66);//B
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($albumLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $album;
        $str .= chr(84);//T
        $str .= chr(80);//P
        $str .= chr(69);//E
        $str .= chr(49);//1
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($artistLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $artist;
        $str .= chr(84);//T
        $str .= chr(73);//I
        $str .= chr(84);//T
        $str .= chr(50);//2
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr($titleLength);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= chr(0);//
        $str .= $title;
        $this->str = $str.$this->str;
    }
    
    function mergeBehind(mp3 $mp3)
    {
        $this->str .= $mp3->str;
    }
    
    function mergeInfront(mp3 $mp3)
    {
        $this->str = $mp3->str.$this->str;
    }
    
    function getIdvEnd()
    {
        $strlen = strlen($this->str);
        $str = substr($this->str,($strlen-128));
        $str1 = substr($str,0,3);
        if(strtolower($str1) == strtolower('TAG'))
        {
            return $str;
        }
        else
        {
            return false;
        }
    }
    
    function getStart()
    {
        $strlen = strlen($this->str);
        for($i=0;$i<$strlen;$i++)
        {
            $v = substr($this->str,$i,1);
            $value = ord($v);
            if($value == 255)
            {
                return $i;
            }
        }
    }
    
    function striptags()
    {
        //Remove start stuff...
        $newStr = '';
        $s = $start = $this->getStart();
        if($s===false)
        {
            return false;
        }
        else
        {
            $this->str = substr($this->str,$start);
        }
        //Remove end tag stuff
        $end = $this->getIdvEnd();
        if($end!==false)
        {
            $this->str = substr($this->str,0,(strlen($this->str)-129));
        }
    }
    
    function save($path)
    {
        $fp = fopen($path,'w');
        fwrite($fp,$this->str);
        fclose($fp);
    }
}
?>