MP3_Id
[ class tree: MP3_Id ] [ index: MP3_Id ] [ all elements ]

Source for file Id.php

Documentation is available at Id.php

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This code is released under the GNU LGPL Go read it over here:       |
  9. // | http://www.gnu.org/copyleft/lesser.html                              |
  10. // +----------------------------------------------------------------------+
  11. // | Authors: Sandy McArthur Jr. <Leknor@Leknor.com>                      |
  12. // +----------------------------------------------------------------------+
  13. //
  14. // $Id: Id.php 315617 2011-08-27 14:36:36Z alexmerz $
  15. //
  16.  
  17. // Uncomment the folling define if you want the class to automatically
  18. // read the MPEG frame info to get bitrate, mpeg version, layer, etc.
  19. //
  20. // NOTE: This is needed to maintain pre-version 1.0 behavior which maybe
  21. // needed if you are using info that is from the mpeg frame. This includes
  22. // the length of the song.
  23. //
  24. // This is discouraged because it will siginfincantly lengthen script
  25. // execution time if all you need is the ID3 tag info.
  26. // define('ID3_AUTO_STUDY', true);
  27.  
  28. // Uncomment the following define if you want tons of debgging info.
  29. // Tip: make sure you use a <PRE> block so the print_r's are readable.
  30. // define('ID3_SHOW_DEBUG', true);
  31.  
  32. require_once "PEAR.php" ;
  33.  
  34. /**
  35. * File not opened
  36. @const PEAR_MP3_ID_FNO
  37. */
  38. define('PEAR_MP3_ID_FNO'1);
  39.  
  40. /**
  41. * Read error
  42. @const PEAR_MP3_ID_RE
  43. */
  44. define('PEAR_MP3_ID_RE'2);
  45.  
  46. /**
  47. * Tag not found
  48. @const PEAR_MP3_ID_TNF
  49. */
  50. define('PEAR_MP3_ID_TNF'3);
  51.  
  52. /**
  53. * File is not a MP3 file (corrupted?)
  54. @const PEAR_MP3_ID_NOMP3
  55. */
  56. define('PEAR_MP3_ID_NOMP3'4);
  57.  
  58. /**
  59.  * A Class for reading/writing MP3 ID3 tags
  60.  *
  61.  * Note: This code doesn't try to deal with corrupt mp3s. So if you get
  62.  * incorrect length times or something else it may be your mp3. To fix just
  63.  * re-enocde from the CD. :~)
  64.  *
  65.  * eg:
  66.  * require_once("MP3/Id.php");
  67.  * $file = "Some Song.mp3";
  68.  *
  69.  * $id3 = &new MP3_Id();
  70.  * $id3->read($file);
  71.  * print_r($id3);
  72.  *
  73.  * echo $id3->getTag('artists');
  74.  *
  75.  * $id3->comment = "Be gentle with that file.";
  76.  * $id3->write();
  77.  * $id3->read($file);
  78.  * print_r($id3 );
  79.  *
  80.  * @package MP3_Id
  81.  * @author Sandy McArthur Jr. <Leknor@Leknor.com>
  82.  * @version $Id: Id.php 315617 2011-08-27 14:36:36Z alexmerz $
  83.  */
  84. class MP3_Id {
  85.  
  86.     /**
  87.     * mp3/mpeg file name
  88.     * @var boolean 
  89.     */
  90.     var $file = false;
  91.     /**
  92.     * ID3 v1 tag found? (also true if v1.1 found)
  93.     * @var boolean 
  94.     */
  95.     var $id3v1 = false;
  96.     /**
  97.     * ID3 v1.1 tag found?
  98.     * @var boolean 
  99.     */
  100.     var $id3v11 = false;
  101.     /**
  102.     * ID3 v2 tag found? (not used yet)
  103.     * @var boolean 
  104.     */
  105.     var $id3v2 = false;
  106.  
  107.     // ID3v1.1 Fields:
  108.     /**
  109.     * trackname
  110.     * @var string 
  111.     */
  112.     var $name = '';
  113.     /**
  114.     * artists
  115.     * @var string 
  116.     */
  117.     var $artists = '';
  118.     /**
  119.     * album
  120.     * @var string 
  121.     */
  122.     var $album = '';
  123.     /**
  124.     * year
  125.     * @var string 
  126.     */
  127.     var $year = '';
  128.     /**
  129.     * comment
  130.     * @var string 
  131.     */
  132.     var $comment = '';
  133.     /**
  134.     * track number
  135.     * @var integer 
  136.     */
  137.     var $track = 0;
  138.     /**
  139.     * genre name
  140.     * @var string 
  141.     */
  142.     var $genre = '';
  143.     /**
  144.     * genre number
  145.     * @var integer 
  146.     */
  147.     var $genreno = 255;
  148.  
  149.     // MP3 Frame Stuff
  150.     /**
  151.     * Was the file studied to learn more info?
  152.     * @var boolean 
  153.     */
  154.     var $studied = false;
  155.  
  156.     /**
  157.     * version of mpeg
  158.     * @var integer 
  159.     */
  160.     var $mpeg_ver = 0;
  161.     /**
  162.     * version of layer
  163.     * @var integer 
  164.     */
  165.     var $layer = 0;
  166.     /**
  167.     * version of bitrate
  168.     * @var integer 
  169.     */
  170.     var $bitrate = 0;
  171.     /**
  172.     * Frames are crc protected?
  173.     * @var boolean 
  174.     */
  175.     var $crc = false;
  176.     /**
  177.     * frequency
  178.     * @var integer 
  179.     */
  180.     var $frequency = 0;
  181.     /**
  182.     * encoding type (CBR or VBR)
  183.     * @var string 
  184.     */
  185.     var $encoding_type = 0;
  186.     /**
  187.     * number of samples per MPEG audio frame
  188.     * @var integer 
  189.     */
  190.     var $samples_per_frame = 0;
  191.     /**
  192.     * samples in file
  193.     * @var integer 
  194.     */
  195.     var $samples = 0;
  196.     /**
  197.     * Bytes in file without tag overhead
  198.     * @var integer 
  199.     */
  200.     var $musicsize = -1;
  201.     /**
  202.     * number of MPEG audio frames
  203.     * @var integer 
  204.     */
  205.     var $frames = 0;
  206.     /**
  207.     * quality indicator (0% - 100%)
  208.     * @var integer 
  209.     */
  210.     var $quality = 0;
  211.     /**
  212.     * Frames padded
  213.     * @var boolean 
  214.     */
  215.     var $padding = false;
  216.     /**
  217.     * private bit set
  218.     * @var boolean 
  219.     */
  220.     var $private = false;
  221.     /**
  222.     * Mode (Stero etc)
  223.     * @var string 
  224.     */
  225.     var $mode = '';
  226.     /**
  227.     * Copyrighted
  228.     * @var string 
  229.     */
  230.     var $copyright = false;
  231.     /**
  232.     * On Original Media? (never used)
  233.     * @var boolean 
  234.     */
  235.     var $original = false;
  236.     /**
  237.     * Emphasis (also never used)
  238.     * @var boolean 
  239.     */
  240.     var $emphasis = '';
  241.     /**
  242.     * Bytes in file
  243.     * @var integer 
  244.     */
  245.     var $filesize = -1;
  246.     /**
  247.     * Byte at which the first mpeg header was found
  248.     * @var integer 
  249.     */
  250.     var $frameoffset = -1;
  251.      /**
  252.     * length of mp3 format hh:mm:ss
  253.     * @var string 
  254.     */
  255.     var $lengthh = false;
  256.     /**
  257.     * length of mp3 format mm:ss
  258.     * @var string 
  259.     */
  260.     var $length = false;
  261.     /**
  262.     * length of mp3 in seconds
  263.     * @var string 
  264.     */
  265.     var $lengths = false;
  266.  
  267.     /**
  268.     * if any errors they will be here
  269.     * @var string 
  270.     */
  271.     var $error = false;
  272.  
  273.     /**
  274.     * print debugging info?
  275.     * @var boolean 
  276.     */
  277.     var $debug = false;
  278.     /**
  279.     * print debugg
  280.     * @var string 
  281.     */
  282.     var $debugbeg = '<DIV STYLE="margin: 0.5 em; padding: 0.5 em; border-width: thin; border-color: black; border-style: solid">';
  283.     /**
  284.     * print debugg
  285.     * @var string 
  286.     */
  287.     var $debugend = '</DIV>';
  288.  
  289.     /*
  290.      * creates a new id3 object
  291.      * and loads a tag from a file.
  292.      *
  293.      * @param string    $study  study the mpeg frame to get extra info like bitrate and frequency
  294.      *                          You should advoid studing alot of files as it will siginficantly
  295.      *                          slow this down.
  296.      * @access public
  297.      */
  298.     function MP3_Id($study = false{
  299.         if(defined('ID3_SHOW_DEBUG')) $this->debug = true;
  300.         $this->study=($study || defined('ID3_AUTO_STUDY'));
  301.  
  302.     // id3()
  303.  
  304.     /**
  305.     * reads the given file and parse it
  306.     *
  307.     * @param    string  $file the name of the file to parse
  308.     * @return   mixed   PEAR_Error on error
  309.     * @access   public
  310.     */
  311.     function read$file=""{
  312.         if ($this->debugprint($this->debugbeg . "id3('$file')<HR>\n");
  313.  
  314.         if(!empty($file))$this->file = $file;
  315.         if ($this->debugprint($this->debugend);
  316.  
  317.         return $this->_read_v1();
  318.     }
  319.  
  320.     /**
  321.     * sets a field
  322.     *
  323.     * possible names of tags are:
  324.     * artists   - Name of band or artist
  325.     * album     - Name of the album
  326.     * year      - publishing year of the album or song
  327.     * comment   - song comment
  328.     * track     - the number of the track
  329.     * genre     - genre of the song
  330.     * genreno   - Number of the genre
  331.     *
  332.     * @param    mixed   $name   Name of the tag to set or hash with the key as fieldname
  333.     * @param    mixed   $value  the value to set
  334.     *
  335.     * @access   public
  336.     */
  337.     function setTag($name$value{
  338.         ifis_array($name)) {
  339.             foreach$name as $n => $v{
  340.                 $this -> $n $v ;
  341.                 }
  342.         else {
  343.             $this -> $name $value ;
  344.         }
  345.     }
  346.  
  347.     /**
  348.     * get the value of a tag
  349.     *
  350.     * @param    string  $name       the name of the field to get
  351.     * @param    mixed   $default    returned if the field not exists
  352.     *
  353.     * @return   mixed   The value of the field
  354.     * @access   public
  355.     * @see      setTag
  356.     */
  357.     function getTag($name$default = 0{
  358.         if(empty($this -> $name)) {
  359.             return $default ;
  360.         else {
  361.             return $this -> $name ;
  362.         }
  363.     }
  364.  
  365.     /**
  366.      * update the id3v1 tags on the file.
  367.      * Note: If/when ID3v2 is implemented this method will probably get another
  368.      *       parameters.
  369.      *
  370.      * @param boolean $v1   if true update/create an id3v1 tag on the file. (defaults to true)
  371.      *
  372.      * @access public
  373.      */
  374.     function write($v1 = true{
  375.     if ($this->debugprint($this->debugbeg . "write()<HR>\n");
  376.     if ($v1{
  377.         $this->_write_v1();
  378.     }
  379.     if ($this->debugprint($this->debugend);
  380.     // write()
  381.  
  382.     /**
  383.      * study() - does extra work to get the MPEG frame info.
  384.      *
  385.      * @access public
  386.      */
  387.     function study({
  388.     $this->studied = true;
  389.     $this->_readframe();
  390.     // study()
  391.  
  392.     /**
  393.      * copy($from) - set's the ID3 fields to the same as the fields in $from
  394.      *
  395.      * @param string    $from   fields to copy
  396.      * @access public
  397.      */
  398.     function copy($from{
  399.     if ($this->debugprint($this->debugbeg . "copy(\$from)<HR>\n");
  400.     $this->name = $from->name;
  401.     $this->artists  = $from->artists;
  402.     $this->album    = $from->album;
  403.     $this->year = $from->year;
  404.     $this->comment  = $from->comment;
  405.     $this->track    = $from->track;
  406.     $this->genre    = $from->genre;
  407.     $this->genreno  = $from->genreno;
  408.     if ($this->debugprint($this->debugend);
  409.     // copy($from)
  410.  
  411.     /**
  412.      * remove - removes the id3 tag(s) from a file.
  413.      *
  414.      * @param boolean   $id3v1  true to remove the tag
  415.      * @param boolean   $id3v2  true to remove the tag (Not yet implemented)
  416.      *
  417.      * @access public
  418.      */
  419.     function remove($id3v1 = true$id3v2 = true{
  420.     if ($this->debugprint($this->debugbeg . "remove()<HR>\n");
  421.  
  422.     if ($id3v1{
  423.         $this->_remove_v1();
  424.     }
  425.  
  426.     if ($id3v2{
  427.         // TODO: write ID3v2 code
  428.     }
  429.  
  430.     if ($this->debugprint($this->debugend);
  431.     // remove
  432.  
  433.  
  434.     /**
  435.      * read a ID3 v1 or v1.1 tag from a file
  436.      *
  437.      * $file should be the path to the mp3 to look for a tag.
  438.      * When in doubt use the full path.
  439.      *
  440.      * @return mixed    PEAR_Error if fails
  441.      * @access private
  442.      */
  443.     function _read_v1({
  444.     if ($this->debugprint($this->debugbeg . "_read_v1()<HR>\n");
  445.  
  446.     if (($f @fopen($this->file'rb')) ) {
  447.         return PEAR::raiseError"Unable to open " $this->filePEAR_MP3_ID_FNO);
  448.     }
  449.  
  450.     if (fseek($f-128SEEK_END== -1{
  451.         return PEAR::raiseError'Unable to see to end - 128 of ' $this->filePEAR_MP3_ID_RE);
  452.     }
  453.  
  454.     $r fread($f128);
  455.     fclose($f);
  456.  
  457.     if ($this->debug{
  458.         $unp unpack('H*raw'$r);
  459.         print_r($unp);
  460.     }
  461.  
  462.     $id3tag $this->_decode_v1($r);
  463.  
  464.     if(!PEAR::isError$id3tag)) {
  465.         $this->id3v1 = true;
  466.  
  467.         $tmp explode(Chr(0)$id3tag['NAME']);
  468.         $this->name = $tmp[0];
  469.  
  470.         $tmp explode(Chr(0)$id3tag['ARTISTS']);
  471.         $this->artists = $tmp[0];
  472.  
  473.         $tmp explode(Chr(0)$id3tag['ALBUM']);
  474.         $this->album = $tmp[0];
  475.  
  476.         $tmp explode(Chr(0)$id3tag['YEAR']);
  477.         $this->year = $tmp[0];
  478.  
  479.         $tmp explode(Chr(0)$id3tag['COMMENT']);
  480.         $this->comment = $tmp[0];
  481.  
  482.         if (isset($id3tag['TRACK'])) {
  483.         $this->id3v11 = true;
  484.         $this->track = $id3tag['TRACK'];
  485.         }
  486.  
  487.         $this->genreno = $id3tag['GENRENO'];
  488.         $this->genre = $id3tag['GENRE'];
  489.     else {
  490.         return $id3tag ;
  491.         }
  492.  
  493.     if ($this->debugprint($this->debugend);
  494.     // _read_v1()
  495.  
  496.     /**
  497.      * decodes that ID3v1 or ID3v1.1 tag
  498.      *
  499.      * false will be returned if there was an error decoding the tag
  500.      * else an array will be returned
  501.      *
  502.      * @param   string  $rawtag    tag to decode
  503.      * @return  string  decoded tag
  504.      * @access  private
  505.      */
  506.     function _decode_v1($rawtag{
  507.     if ($this->debugprint($this->debugbeg . "_decode_v1(\$rawtag)<HR>\n");
  508.  
  509.     if ($rawtag[125== Chr(0and $rawtag[126!= Chr(0)) {
  510.         // ID3 v1.1
  511.         $format 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a28COMMENT/x1/C1TRACK/C1GENRENO';
  512.     else {
  513.         // ID3 v1
  514.         $format 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a30COMMENT/C1GENRENO';
  515.     }
  516.  
  517.     $id3tag unpack($format$rawtag);
  518.     if ($this->debugprint_r($id3tag);
  519.  
  520.     if ($id3tag['TAG'== 'TAG'{
  521.         $id3tag['GENRE'$this->getgenre($id3tag['GENRENO']);
  522.     else {
  523.         $id3tag = PEAR::raiseError'TAG not found'PEAR_MP3_ID_TNF);
  524.     }
  525.     if ($this->debugprint($this->debugend);
  526.     return $id3tag;
  527.     // _decode_v1()
  528.  
  529.  
  530.     /**
  531.      * writes a ID3 v1 or v1.1 tag to a file
  532.      *
  533.      * @return mixed    returns PEAR_Error when fails
  534.      * @access private
  535.      */
  536.     function _write_v1({
  537.     if ($this->debugprint($this->debugbeg . "_write_v1()<HR>\n");
  538.  
  539.     $file $this->file;
  540.  
  541.     if (($f @fopen($file'r+b')) ) {
  542.         return PEAR::raiseError"Unable to open " $filePEAR_MP3_ID_FNO);
  543.     }
  544.  
  545.     if (fseek($f-128SEEK_END== -1{
  546. //        $this->error = 'Unable to see to end - 128 of ' . $file;
  547.         return PEAR::raiseError"Unable to see to end - 128 of " $filePEAR_MP3_ID_RE);
  548.     }
  549.  
  550.     $this->genreno = $this->getgenreno($this->genre$this->genreno);
  551.  
  552.     $newtag $this->_encode_v1();
  553.  
  554.     $r fread($f128);
  555.  
  556.     if !PEAR::isError$this->_decode_v1($r))) {
  557.         if (fseek($f-128SEEK_END== -1{
  558. //        $this->error = 'Unable to see to end - 128 of ' . $file;
  559.         return PEAR::raiseError"Unable to see to end - 128 of " $filePEAR_MP3_ID_RE);
  560.         }
  561.         fwrite($f$newtag);
  562.     else {
  563.         if (fseek($f0SEEK_END== -1{
  564. //        $this->error = 'Unable to see to end of ' . $file;
  565.         return PEAR::raiseError"Unable to see to end of " $filePEAR_MP3_ID_RE);
  566.         }
  567.         fwrite($f$newtag);
  568.     }
  569.     fclose($f);
  570.  
  571.     if ($this->debugprint($this->debugend);
  572.     // _write_v1()
  573.  
  574.     /*
  575.      * encode the ID3 tag
  576.      *
  577.      * the newly built tag will be returned
  578.      *
  579.      * @return string the new tag
  580.      * @access private
  581.      */
  582.     function _encode_v1({
  583.     if ($this->debugprint($this->debugbeg . "_encode_v1()<HR>\n");
  584.  
  585.     if ($this->track{
  586.         // ID3 v1.1
  587.         $id3pack 'a3a30a30a30a4a28x1C1C1';
  588.         $newtag pack($id3pack,
  589.             'TAG',
  590.             $this->name,
  591.             $this->artists,
  592.             $this->album,
  593.             $this->year,
  594.             $this->comment,
  595.             $this->track,
  596.             $this->genreno
  597.               );
  598.     else {
  599.         // ID3 v1
  600.         $id3pack 'a3a30a30a30a4a30C1';
  601.         $newtag pack($id3pack,
  602.             'TAG',
  603.             $this->name,
  604.             $this->artists,
  605.             $this->album,
  606.             $this->year,
  607.             $this->comment,
  608.             $this->genreno
  609.               );
  610.     }
  611.  
  612.     if ($this->debug{
  613.         print('id3pack: ' $id3pack "\n");
  614.         $unp unpack('H*new'$newtag);
  615.         print_r($unp);
  616.     }
  617.  
  618.     if ($this->debugprint($this->debugend);
  619.     return $newtag;
  620.     // _encode_v1()
  621.  
  622.     /**
  623.      * if exists it removes an ID3v1 or v1.1 tag
  624.      *
  625.      * returns true if the tag was removed or none was found
  626.      * else false if there was an error
  627.      *
  628.      * @return boolean true, if the tag was removed
  629.      * @access private
  630.      */
  631.     function _remove_v1({
  632.     if ($this->debugprint($this->debugbeg . "_remove_v1()<HR>\n");
  633.  
  634.     $file $this->file;
  635.  
  636.     if (($f fopen($file'r+b')) ) {
  637.         return PEAR::raiseError"Unable to open " $filePEAR_MP3_ID_FNO);
  638.     }
  639.  
  640.     if (fseek($f-128SEEK_END== -1{
  641.         return PEAR::raiseError'Unable to see to end - 128 of ' $filePEAR_MP3_ID_RE);
  642.     }
  643.  
  644.     $r fread($f128);
  645.  
  646.     $success = false;
  647.     if !PEAR::isError$this->_decode_v1($r))) {
  648.         $size filesize($this->file- 128;
  649.         if ($this->debugprint('size: old: ' filesize($this->file));
  650.         $success ftruncate($f$size);
  651.         clearstatcache();
  652.         if ($this->debugprint(' new: ' filesize($this->file));
  653.     }
  654.     fclose($f);
  655.  
  656.     if ($this->debugprint($this->debugend);
  657.     return $success;
  658.     // _remove_v1()
  659.  
  660.     /**
  661.     * reads a frame from the file
  662.     *
  663.     * @return mixed PEAR_Error when fails
  664.     * @access private
  665.     */
  666.     function _readframe({
  667.     if ($this->debugprint($this->debugbeg . "_readframe()<HR>\n");
  668.  
  669.     $file $this->file;
  670.  
  671.     if (($f fopen($file'rb')) ) {
  672.         if ($this->debugprint($this->debugend);
  673.         return PEAR::raiseError"Unable to open " $filePEAR_MP3_ID_FNO;
  674.     }
  675.  
  676.     $this->filesize = filesize($file);
  677.  
  678.     do {
  679.         while (fread($f,1!= Chr(255)) // Find the first frame
  680.         if ($this->debugecho "Find...\n";
  681.         if (feof($f)) {
  682.             if ($this->debugprint($this->debugend);
  683.             return PEAR::raiseError"No mpeg frame found"PEAR_MP3_ID_NOMP3;
  684.         }
  685.         }
  686.         fseek($fftell($f- 1)// back up one byte
  687.  
  688.         $frameoffset ftell($f);
  689.  
  690.         $r fread($f4);
  691.         // Binary to Hex to a binary sting. ugly but best I can think of.
  692.         // $bits = unpack('H*bits', $r);
  693.         // $bits =  base_convert($bits['bits'],16,2);
  694.         $bits sprintf("%'08b%'08b%'08b%'08b"ord($r{0})ord($r{1})ord($r{2})ord($r{3}));
  695.     while (!$bits[8and !$bits[9and !$bits[10])// 1st 8 bits true from the while
  696.     if ($this->debugprint('Bits: ' $bits "\n");
  697.  
  698.     $this->frameoffset = $frameoffset;
  699.  
  700.     // Detect VBR header
  701.     if ($bits[11== 0{
  702.         if (($bits[24== 1&& ($bits[25== 1)) {
  703.             $vbroffset = 9; // MPEG 2.5 Mono
  704.         else {
  705.             $vbroffset = 17; // MPEG 2.5 Stereo
  706.         }
  707.     else if ($bits[12== 0{
  708.         if (($bits[24== 1&& ($bits[25== 1)) {
  709.             $vbroffset = 9; // MPEG 2 Mono
  710.         else {
  711.             $vbroffset = 17; // MPEG 2 Stereo
  712.         }
  713.     else {
  714.         if (($bits[24== 1&& ($bits[25== 1)) {
  715.             $vbroffset = 17; // MPEG 1 Mono
  716.         else {
  717.             $vbroffset = 32; // MPEG 1 Stereo
  718.         }
  719.     }
  720.  
  721.     fseek($fftell($f$vbroffset);
  722.     $r fread($f4);
  723.  
  724.     switch ($r{
  725.         case 'Xing':
  726.             $this->encoding_type = 'VBR';
  727.         case 'Info':
  728.             // Extract info from Xing header
  729.  
  730.             if ($this->debugprint('Encoding Header: ' $r "\n");
  731.  
  732.             $r fread($f4);
  733.             $vbrbits sprintf("%'08b"ord($r{3}));
  734.  
  735.             if ($this->debugprint('XING Header Bits: ' $vbrbits "\n");
  736.  
  737.             if ($vbrbits[7== 1{
  738.                 // Next 4 bytes contain number of frames
  739.                 $r fread($f4);
  740.                 $this->frames = unpack('N'$r);
  741.                 $this->frames = $this->frames[1];
  742.             }
  743.  
  744.             if ($vbrbits[6== 1{
  745.                 // Next 4 bytes contain number of bytes
  746.                 $r fread($f4);
  747.                 $this->musicsize = unpack('N'$r);
  748.                 $this->musicsize = $this->musicsize[1];
  749.             }
  750.  
  751.             if ($vbrbits[5== 1{
  752.                 // Next 100 bytes contain TOC entries, skip
  753.                 fseek($fftell($f+ 100);
  754.             }
  755.  
  756.             if ($vbrbits[4== 1{
  757.                 // Next 4 bytes contain Quality Indicator
  758.                 $r fread($f4);
  759.                 $this->quality = unpack('N'$r);
  760.                 $this->quality = $this->quality[1];
  761.             }
  762.  
  763.             break;
  764.  
  765.         case 'VBRI':
  766.         default:
  767.             if ($vbroffset != 32{
  768.                 // VBRI Header is fixed after 32 bytes, so maybe we are looking at the wrong place.
  769.                 fseek($fftell($f+ 32 - $vbroffset);
  770.                 $r fread($f4);
  771.  
  772.                 if ($r != 'VBRI'{
  773.                     $this->encoding_type = 'CBR';
  774.                     break;
  775.                 }
  776.             else {
  777.                 $this->encoding_type = 'CBR';
  778.                 break;
  779.             }
  780.  
  781.             if ($this->debugprint('Encoding Header: ' $r "\n");
  782.  
  783.             $this->encoding_type = 'VBR';
  784.  
  785.             // Next 2 bytes contain Version ID, skip
  786.             fseek($fftell($f+ 2);
  787.  
  788.             // Next 2 bytes contain Delay, skip
  789.             fseek($fftell($f+ 2);
  790.  
  791.             // Next 2 bytes contain Quality Indicator
  792.             $r fread($f2);
  793.             $this->quality = unpack('n'$r);
  794.             $this->quality = $this->quality[1];
  795.  
  796.             // Next 4 bytes contain number of bytes
  797.             $r fread($f4);
  798.             $this->musicsize = unpack('N'$r);
  799.             $this->musicsize = $this->musicsize[1];
  800.  
  801.             // Next 4 bytes contain number of frames
  802.             $r fread($f4);
  803.             $this->frames = unpack('N'$r);
  804.             $this->frames = $this->frames[1];
  805.     }
  806.  
  807.     fclose($f);
  808.  
  809.     if ($bits[11== 0{
  810.         $this->mpeg_ver = "2.5";
  811.         $bitrates = array(
  812.             '1' => array(03248566480961121281441601761922242560),
  813.             '2' => array(0,  81624324048,  56,  64,  80,  961121281441600),
  814.             '3' => array(0,  81624324048,  56,  64,  80,  961121281441600),
  815.                  );
  816.     else if ($bits[12== 0{
  817.         $this->mpeg_ver = "2";
  818.         $bitrates = array(
  819.             '1' => array(03248566480961121281441601761922242560),
  820.             '2' => array(0,  81624324048,  56,  64,  80,  961121281441600),
  821.             '3' => array(0,  81624324048,  56,  64,  80,  961121281441600),
  822.                  );
  823.     else {
  824.         $this->mpeg_ver = "1";
  825.         $bitrates = array(
  826.             '1' => array(03264961281601922242562883203523844164480),
  827.             '2' => array(0324856,  64,  80,  961121281601922242563203840),
  828.             '3' => array(0324048,  56,  64,  80,  961121281601922242563200),
  829.                  );
  830.     }
  831.     if ($this->debugprint('MPEG' $this->mpeg_ver . "\n");
  832.  
  833.     $layer = array(
  834.         array(0,3),
  835.         array(2,1),
  836.               );
  837.     $this->layer = $layer[$bits[13]][$bits[14]];
  838.     if ($this->debugprint('layer: ' $this->layer . "\n");
  839.  
  840.     if ($bits[15== 0{
  841.         // It's backwards, if the bit is not set then it is protected.
  842.         if ($this->debugprint("protected (crc)\n");
  843.         $this->crc = true;
  844.     }
  845.  
  846.     $bitrate = 0;
  847.     if ($bits[16== 1$bitrate += 8;
  848.     if ($bits[17== 1$bitrate += 4;
  849.     if ($bits[18== 1$bitrate += 2;
  850.     if ($bits[19== 1$bitrate += 1;
  851.     $this->bitrate = $bitrates[$this->layer][$bitrate];
  852.  
  853.     $frequency = array(
  854.         '1' => array(
  855.             '0' => array(4410048000),
  856.             '1' => array(320000),
  857.                 ),
  858.         '2' => array(
  859.             '0' => array(2205024000),
  860.             '1' => array(160000),
  861.                 ),
  862.         '2.5' => array(
  863.             '0' => array(1102512000),
  864.             '1' => array(80000),
  865.                   ),
  866.           );
  867.     $this->frequency = $frequency[$this->mpeg_ver][$bits[20]][$bits[21]];
  868.  
  869.     $this->padding = $bits[22];
  870.     $this->private = $bits[23];
  871.  
  872.     $mode = array(
  873.         array('Stereo''Joint Stereo'),
  874.         array('Dual Channel''Mono'),
  875.              );
  876.     $this->mode = $mode[$bits[24]][$bits[25]];
  877.  
  878.     // XXX: I dunno what the mode extension is for bits 26,27
  879.  
  880.     $this->copyright = $bits[28];
  881.     $this->original = $bits[29];
  882.  
  883.     $emphasis = array(
  884.         array('none''50/15ms'),
  885.         array('''CCITT j.17'),
  886.              );
  887.     $this->emphasis = $emphasis[$bits[30]][$bits[31]];
  888.  
  889.     $samplesperframe = array(
  890.         '1' => array(
  891.             '1' => 384,
  892.             '2' => 1152,
  893.             '3' => 1152
  894.         ),
  895.         '2' => array(
  896.             '1' => 384,
  897.             '2' => 1152,
  898.             '3' => 576
  899.         ),
  900.         '2.5' => array(
  901.             '1' => 384,
  902.             '2' => 1152,
  903.             '3' => 576
  904.         ),
  905.     );
  906.     $this->samples_per_frame = $samplesperframe[$this->mpeg_ver][$this->layer];
  907.  
  908.     if ($this->encoding_type != 'VBR'{
  909.         if ($this->bitrate == 0{
  910.             $s = -1;
  911.         else {
  912.             $s ((8*filesize($this->file))/1000$this->bitrate;
  913.         }
  914.         $this->length = sprintf('%02d:%02d',floor($s/60),floor($s-(floor($s/60)*60)));
  915.         $this->lengthh = sprintf('%02d:%02d:%02d',floor($s/3600),floor($s/60),floor($s-(floor($s/60)*60)));
  916.         $this->lengths = (int)$s;
  917.  
  918.         $this->samples = ceil($this->lengths * $this->frequency);
  919.         if(0 != $this->samples_per_frame{
  920.             $this->frames = ceil($this->samples / $this->samples_per_frame);
  921.         else {
  922.             $this->frames = 0;
  923.         }
  924.         $this->musicsize = ceil($this->lengths * $this->bitrate * 1000 / 8);
  925.     else {
  926.         $this->samples = $this->samples_per_frame * $this->frames;
  927.         $s $this->samples / $this->frequency;
  928.  
  929.         $this->length = sprintf('%02d:%02d',floor($s/60),floor($s-(floor($s/60)*60)));
  930.         $this->lengthh = sprintf('%02d:%02d:%02d',floor($s/3600),floor($s/60),floor($s-(floor($s/60)*60)));
  931.         $this->lengths = (int)$s;
  932.  
  933.         $this->bitrate = (int)(($this->musicsize / $s* 8 / 1000);
  934.     }
  935.  
  936.     if ($this->debugprint($this->debugend);
  937.     // _readframe()
  938.  
  939.     /**
  940.      * getGenre - return the name of a genre number
  941.      *
  942.      * if no genre number is specified the genre number from
  943.      * $this->genreno will be used.
  944.      *
  945.      * the genre is returned or false if an error or not found
  946.      * no error message is ever returned
  947.      *
  948.      * @param   integer $genreno Number of the genre
  949.      * @return  mixed   false, if no genre found, else string
  950.      *
  951.      * @access public
  952.      */
  953.     function getGenre($genreno{
  954.     if ($this->debugprint($this->debugbeg . "getgenre($genreno)<HR>\n");
  955.  
  956.     $genres $this->genres();
  957.     if (isset($genres[$genreno])) {
  958.         $genre $genres[$genreno];
  959.         if ($this->debugprint($genre "\n");
  960.     else {
  961.         $genre '';
  962.     }
  963.  
  964.     if ($this->debugprint($this->debugend);
  965.     return $genre;
  966.     // getGenre($genreno)
  967.  
  968.     /*
  969.      * getGenreNo - return the number of the genre name
  970.      *
  971.      * the genre number is returned or 0xff (255) if a match is not found
  972.      * you can specify the default genreno to use if one is not found
  973.      * no error message is ever returned
  974.      *
  975.      * @param   string  $genre      Name of the genre
  976.      * @param   integer $default    Genre number in case of genre not found
  977.      *
  978.      * @access public
  979.      */
  980.     function getGenreNo($genre$default = 0xff{
  981.     if ($this->debugprint($this->debugbeg . "getgenreno('$genre',$default)<HR>\n");
  982.  
  983.     $genres $this->genres();
  984.     $genreno = false;
  985.     if ($genre{
  986.         foreach ($genres as $no => $name{
  987.         if (strtolower($genre== strtolower($name)) {
  988.             if ($this->debugprint("$no:'$name' == '$genre'");
  989.             $genreno $no;
  990.         }
  991.         }
  992.     }
  993.     if ($genreno === false$genreno $default;
  994.     if ($this->debugprint($this->debugend);
  995.     return $genreno;
  996.     // getGenreNo($genre, $default = 0xff)
  997.  
  998.     /*
  999.      * genres - returns an array of the ID3v1 genres
  1000.      *
  1001.      * @return array
  1002.      *
  1003.      * @access public
  1004.      */
  1005.     function genres({
  1006.     return array(
  1007.         0   => 'Blues',
  1008.         1   => 'Classic Rock',
  1009.         2   => 'Country',
  1010.         3   => 'Dance',
  1011.         4   => 'Disco',
  1012.         5   => 'Funk',
  1013.         6   => 'Grunge',
  1014.         7   => 'Hip-Hop',
  1015.         8   => 'Jazz',
  1016.         9   => 'Metal',
  1017.         10  => 'New Age',
  1018.         11  => 'Oldies',
  1019.         12  => 'Other',
  1020.         13  => 'Pop',
  1021.         14  => 'R&B',
  1022.         15  => 'Rap',
  1023.         16  => 'Reggae',
  1024.         17  => 'Rock',
  1025.         18  => 'Techno',
  1026.         19  => 'Industrial',
  1027.         20  => 'Alternative',
  1028.         21  => 'Ska',
  1029.         22  => 'Death Metal',
  1030.         23  => 'Pranks',
  1031.         24  => 'Soundtrack',
  1032.         25  => 'Euro-Techno',
  1033.         26  => 'Ambient',
  1034.         27  => 'Trip-Hop',
  1035.         28  => 'Vocal',
  1036.         29  => 'Jazz+Funk',
  1037.         30  => 'Fusion',
  1038.         31  => 'Trance',
  1039.         32  => 'Classical',
  1040.         33  => 'Instrumental',
  1041.         34  => 'Acid',
  1042.         35  => 'House',
  1043.         36  => 'Game',
  1044.         37  => 'Sound Clip',
  1045.         38  => 'Gospel',
  1046.         39  => 'Noise',
  1047.         40  => 'Alternative Rock',
  1048.         41  => 'Bass',
  1049.         42  => 'Soul',
  1050.         43  => 'Punk',
  1051.         44  => 'Space',
  1052.         45  => 'Meditative',
  1053.         46  => 'Instrumental Pop',
  1054.         47  => 'Instrumental Rock',
  1055.         48  => 'Ethnic',
  1056.         49  => 'Gothic',
  1057.         50  => 'Darkwave',
  1058.         51  => 'Techno-Industrial',
  1059.         52  => 'Electronic',
  1060.         53  => 'Pop-Folk',
  1061.         54  => 'Eurodance',
  1062.         55  => 'Dream',
  1063.         56  => 'Southern Rock',
  1064.         57  => 'Comedy',
  1065.         58  => 'Cult',
  1066.         59  => 'Gangsta',
  1067.         60  => 'Top 40',
  1068.         61  => 'Christian Rap',
  1069.         62  => 'Pop/Funk',
  1070.         63  => 'Jungle',
  1071.         64  => 'Native US',
  1072.         65  => 'Cabaret',
  1073.         66  => 'New Wave',
  1074.         67  => 'Psychadelic',
  1075.         68  => 'Rave',
  1076.         69  => 'Showtunes',
  1077.         70  => 'Trailer',
  1078.         71  => 'Lo-Fi',
  1079.         72  => 'Tribal',
  1080.         73  => 'Acid Punk',
  1081.         74  => 'Acid Jazz',
  1082.         75  => 'Polka',
  1083.         76  => 'Retro',
  1084.         77  => 'Musical',
  1085.         78  => 'Rock & Roll',
  1086.         79  => 'Hard Rock',
  1087.         80  => 'Folk',
  1088.         81  => 'Folk-Rock',
  1089.         82  => 'National Folk',
  1090.         83  => 'Swing',
  1091.         84  => 'Fast Fusion',
  1092.         85  => 'Bebob',
  1093.         86  => 'Latin',
  1094.         87  => 'Revival',
  1095.         88  => 'Celtic',
  1096.         89  => 'Bluegrass',
  1097.         90  => 'Avantgarde',
  1098.         91  => 'Gothic Rock',
  1099.         92  => 'Progressive Rock',
  1100.         93  => 'Psychedelic Rock',
  1101.         94  => 'Symphonic Rock',
  1102.         95  => 'Slow Rock',
  1103.         96  => 'Big Band',
  1104.         97  => 'Chorus',
  1105.         98  => 'Easy Listening',
  1106.         99  => 'Acoustic',
  1107.         100 => 'Humour',
  1108.         101 => 'Speech',
  1109.         102 => 'Chanson',
  1110.         103 => 'Opera',
  1111.         104 => 'Chamber Music',
  1112.         105 => 'Sonata',
  1113.         106 => 'Symphony',
  1114.         107 => 'Booty Bass',
  1115.         108 => 'Primus',
  1116.         109 => 'Porn Groove',
  1117.         110 => 'Satire',
  1118.         111 => 'Slow Jam',
  1119.         112 => 'Club',
  1120.         113 => 'Tango',
  1121.         114 => 'Samba',
  1122.         115 => 'Folklore',
  1123.         116 => 'Ballad',
  1124.         117 => 'Power Ballad',
  1125.         118 => 'Rhytmic Soul',
  1126.         119 => 'Freestyle',
  1127.         120 => 'Duet',
  1128.         121 => 'Punk Rock',
  1129.         122 => 'Drum Solo',
  1130.         123 => 'Acapella',
  1131.         124 => 'Euro-House',
  1132.         125 => 'Dance Hall',
  1133.         126 => 'Goa',
  1134.         127 => 'Drum & Bass',
  1135.         128 => 'Club-House',
  1136.         129 => 'Hardcore',
  1137.         130 => 'Terror',
  1138.         131 => 'Indie',
  1139.         132 => 'BritPop',
  1140.         133 => 'Negerpunk',
  1141.         134 => 'Polsk Punk',
  1142.         135 => 'Beat',
  1143.         136 => 'Christian Gangsta Rap',
  1144.         137 => 'Heavy Metal',
  1145.         138 => 'Black Metal',
  1146.         139 => 'Crossover',
  1147.         140 => 'Contemporary Christian',
  1148.         141 => 'Christian Rock',
  1149.         142 => 'Merengue',
  1150.         143 => 'Salsa',
  1151.         144 => 'Trash Metal',
  1152.         145 => 'Anime',
  1153.         146 => 'Jpop',
  1154.         147 => 'Synthpop'
  1155.             );
  1156.     // genres
  1157. // end of id3
  1158.  
  1159. ?>

Documentation generated on Mon, 11 Mar 2019 15:44:35 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.