php длительность музыкальной дорожки

Разработка своих веб-приложений и страничек

php длительность музыкальной дорожки

Сообщение Alexsandrit » 31 авг 2008, 19:57

как узнать длительность музыкальной дорожки с помощью пхп? mp3 wav (по файлу)
Изображение
:roll:
Alexsandrit
Активный участник
 
Сообщения: 256
Зарегистрирован: 29 сен 2007, 16:47
Домен: http://proekts.vfose.ru/

Re: php длительность музыкальной дорожки

Сообщение zk » 31 авг 2008, 20:40

Есть множество библиотек для чтения информации и тегов из mp3 файлов, в том числе они могут показать длину дорожки.
zk
Администратор
 
Сообщения: 1971
Зарегистрирован: 02 сен 2007, 16:04
Домен: vfose.ru

Re: php длительность музыкальной дорожки

Сообщение Alexsandrit » 31 авг 2008, 21:51

а название библиотек история умалчивает... :oops:
Изображение
:roll:
Alexsandrit
Активный участник
 
Сообщения: 256
Зарегистрирован: 29 сен 2007, 16:47
Домен: http://proekts.vfose.ru/

Re: php длительность музыкальной дорожки

Сообщение zk » 31 авг 2008, 22:01

История да, а вот гугл расскажет любому кто его спросит :wink:

Ну а потом можешь нам выложить библиотеку которая тебе понравилась, с примерами её использования :roll:
zk
Администратор
 
Сообщения: 1971
Зарегистрирован: 02 сен 2007, 16:04
Домен: vfose.ru

Re: php длительность музыкальной дорожки

Сообщение Alexsandrit » 04 сен 2008, 19:01

Библиотека:
Код: Выделить всёРазвернуть
<?php
//
// +----------------------------------------------------------------------+
// | PHP Version 4                                                        |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group                                |
// +----------------------------------------------------------------------+
// | This code is released under the GNU LGPL Go read it over here:       |
// | http://www.gnu.org/copyleft/lesser.html                              |
// +----------------------------------------------------------------------+
// | Authors: Sandy McArthur Jr. <Leknor@xxxxxxxxxx>                      |
// +----------------------------------------------------------------------+
//
// $Id: Id.php,v 1.1 2003/05/22 07:52:56 alexmerz Exp $
//

// Uncomment the folling define if you want the class to automatically
// read the MPEG frame info to get bitrate, mpeg version, layer, etc.
//
// NOTE: This is needed to maintain pre-version 1.0 behavior which maybe
// needed if you are using info that is from the mpeg frame. This includes
// the length of the song.
//
// This is discouraged because it will siginfincantly lengthen script
// execution time if all you need is the ID3 tag info.
// define('ID3_AUTO_STUDY', true);

// Uncomment the following define if you want tons of debgging info.
// Tip: make sure you use a <PRE> block so the print_r's are readable.
// define('ID3_SHOW_DEBUG', true);

include "PEAR.php" ;

/**
* File not opened
* @define PEAR_MP3_ID_FNO 1
*/
define('PEAR_MP3_ID_FNO', 1);

/**
* Read error
* @define PEAR_MP3_ID_RE 2
*/
define('PEAR_MP3_ID_RE', 2);

/**
* Tag not found
* @define PEAR_MP3_ID_TNF 3
*/
define('PEAR_MP3_ID_TNF', 3);

/**
* File is not a MP3 file (corrupted?)
* @define PEAR_MP3_ID_NOMP3 4
*/
define('PEAR_MP3_ID_NOMP3', 4);

/**
* A Class for reading/writing MP3 ID3 tags
*
* Note: This code doesn't try to deal with corrupt mp3s. So if you get
* incorrect length times or something else it may be your mp3. To fix just
* re-enocde from the CD. :~)
*
* eg:
* require_once("MP3/Id.php");
* $file = "Some Song.mp3";
*
* $id3 = &new MP3_Id();
* $id3->read($file);
* print_r($id3);
*
* echo $id3->getTag('artists');
*
* $id3->comment = "Be gentle with that file.";
* $id3->write();
* $id3->read($file);
* print_r($id3 );
*
* @package MP3
* @author Sandy McArthur Jr. <Leknor@xxxxxxxxxx>
* @version $Version$
*/
class MP3_Id {

    /**
    * mp3/mpeg file name
    * @var boolean
    */
    var $file = false;     
    /**
    * ID3 v1 tag found? (also true if v1.1 found)
    * @var boolean
    */
    var $id3v1 = false;     
    /**
    * ID3 v1.1 tag found?
    * @var boolean
    */   
    var $id3v11 = false;
    /**
    * ID3 v2 tag found? (not used yet)
    * @var boolean
    */       
    var $id3v2 = false; 

    // ID3v1.1 Fields:
    /**
    * trackname
    * @var string
    */       
    var $name = '';
    /**
    * artists
    * @var string
    */           
    var $artists = '';
    /**
    * album
    * @var string
    */               
    var $album = '';
    /**
    * year
    * @var string
    */               
    var $year = ''; 
    /**
    * comment
    * @var string
    */               
    var $comment = '';
    /**
    * track number
    * @var integer
    */               
    var $track = 0;
    /**
    * genre name
    * @var string
    */               
    var $genre = '';
    /**
    * genre number
    * @var integer
    */                   
    var $genreno = 255;

    // MP3 Frame Stuff
    /**
    * Was the file studied to learn more info?
    * @var boolean
    */
    var $studied = false;
    /**
    * version of mpeg
    * @var integer
    */   
    var $mpeg_ver = 0;
    /**
    * version of layer
    * @var integer
    */       
    var $layer = 0;
    /**
    * version of bitrate
    * @var integer
    */       
    var $bitrate = 0;
    /**
    * Frames are crc protected?
    * @var boolean
    */           
    var $crc = false;
    /**
    * frequency
    * @var integer
    */               
    var $frequency = 0;
    /**
    * Frames padded
    * @var boolean
    */               
    var $padding = false;
    /**
    * private bit set
    * @var boolean
    */                   
    var $private = false;
    /**
    * Mode (Stero etc)
    * @var string
    */                   
    var $mode = '';
    /**
    * Copyrighted
    * @var string
    */                       
    var $copyright = false;
    /**
    * On Original Media? (never used)
    * @var boolean
    */                       
    var $original = false;
    /**
    * Emphasis (also never used)
    * @var boolean
    */                       
    var $emphasis = '';     
    /**
    * Bytes in file
    * @var integer
    */                           
    var $filesize = -1;
    /**
    * Byte at which the first mpeg header was found
    * @var integer
    */                           
    var $frameoffset = -1;
    /**
    * length of mp3 format hh:ss
    * @var string
    */                           
    var $length = false;
    /**
    * length of mp3 in seconds
    * @var string
    */                           
    var $lengths = false;

    /**
    * if any errors they will be here
    * @var string
    */
    var $error = false;   

    /**
    * print debugging info?
    * @var boolean
    */
    var $debug = false;
    /**
    * print debugg
    * @var string
    */   
    var $debugbeg = '<DIV STYLE="margin: 0.5 em; padding: 0.5 em; border-width: thin; border-color: black; border-style: solid">';
    /**
    * print debugg
    * @var string
    */   
    var $debugend = '</DIV>';

    /*
     * creates a new id3 object
     * and maybe loads a tag from a file.
     *
     * @param string    $file   the path to the mp3/mpeg file. When in doubt use a full path.
     * @param string    $study  study the mpeg frame to get extra info like bitrate and frequency
     *                          You should advoid studing alot of files as it will siginficantly
     *                          slow this down.
     * @access public
     */
    function MP3_Id($study = false) {
        if (defined('ID3_SHOW_DEBUG')) $this->debug = true;   
        if ($study or defined('ID3_AUTO_STUDY'))
            $this->study();
   
    } // id3()

    /**
    * reads the given file and parse it
    *
    * @param    string  $file the name of the file to parse
    * @return   mixed   PEAR_Error on error
    * @access   public
    */
    function read( $file) {
        if ($this->debug) print($this->debugbeg . "id3('$file')<HR>\n");
       
        $this->file = $file;
        if ($this->debug) print($this->debugend);       
       
        return $this->_read_v1();                       
    }
   
    /**
    * sets a field
    *
    * possible names of tags are:
    * artists   - Name of band or artist
    * album     - Name of the album
    * year      - publishing year of the album or song
    * comment   - song comment
    * track     - the number of the track
    * genre     - genre of the song
    * genreno   - Number of the genre
    *
    * @param    mixed   $name   Name of the tag to set or hash with the key as fieldname
    * @param    mixed   $value  the value to set
    *
    * @access   public
    */
    function setTag($name, $value) {
        if( is_array($name)) {
            foreach( $name as $n => $v) {
                $this -> $n = $v ;
                }
        } else {
            $this -> $name = $value ;       
        }
    }
   
    /**
    * get the value of a tag
    *
    * @param    string  $name       the name of the field to get
    * @param    mixed   $default    returned if the field not exists
    *
    * @return   mixed   The value of the field
    * @access   public
    * @see      setTag
    */
    function getTag($name, $default = 0) {
        if(empty($this -> $name)) {
            return $default ;
        } else {
            return $this -> $name ;
        }
    }       
   
    /*
     * update the id3v1 tags on the file.
     * Note: If/when ID3v2 is implemented this method will probably get another
     *       parameters.
     *     
     * @param boolean $v1   if true update/create an id3v1 tag on the file. (defaults to true)
     *
     * @access public
     */
    function write($v1 = true) {
    if ($this->debug) print($this->debugbeg . "write()<HR>\n");
    if ($v1) {
        $this->_write_v1();
    }
    if ($this->debug) print($this->debugend);
    } // write()

    /*
     * study() - does extra work to get the MPEG frame info.
     *
     * @access public
     */
    function study() {
    $this->studied = true;
    $this->_readframe();
    } // study()

    /*
     * copy($from) - set's the ID3 fields to the same as the fields in $from
     *
     * @param string    $from   fields to copy
     */
    function copy($from) {
    if ($this->debug) print($this->debugbeg . "copy(\$from)<HR>\n");
    $this->name = $from->name;
    $this->artists  = $from->artists;
    $this->album    = $from->album;
    $this->year = $from->year;
    $this->comment  = $from->comment;
    $this->track    = $from->track;
    $this->genre    = $from->genre;
    $this->genreno  = $from->genreno;
    if ($this->debug) print($this->debugend);
    } // copy($from)

    /*
     * remove - removes the id3 tag(s) from a file.
     *
     * @param boolean   $id3v1  true to remove the tag
     * @param boolean   $id3v2  true to remove the tag (Not yet implemented)
     *
     * @access public
     */
    function remove($id3v1 = true, $id3v2 = true) {
    if ($this->debug) print($this->debugbeg . "remove()<HR>\n");

    if ($id3v1) {
        $this->_remove_v1();
    }

    if ($id3v2) {
        // TODO: write ID3v2 code
    }

    if ($this->debug) print($this->debugend);
    } // remove


    /*
     * read a ID3 v1 or v1.1 tag from a file
     *
     * $file should be the path to the mp3 to look for a tag.
     * When in doubt use the full path.
     *
     * @return mixed    PEAR_Error if fails
     */
    function _read_v1() {
    if ($this->debug) print($this->debugbeg . "_read_v1()<HR>\n");

    if (! ($f = @fopen($this->file, 'rb')) ) {
        return PEAR::raiseError( "Unable to open " . $file, PEAR_MP3_ID_FNO);
    }

    if (fseek($f, -128, SEEK_END) == -1) {
        return PEAR::raiseError( 'Unable to see to end - 128 of ' . $file, PEAR_MP3_ID_RE);
    }

    $r = fread($f, 128);
    fclose($f);

    if ($this->debug) {
        $unp = unpack('H*raw', $r);
        print_r($unp);
    }

    $id3tag = $this->_decode_v1($r);

    if(!PEAR::isError( $id3tag)) {
        $this->id3v1 = true;

        $tmp = explode(Chr(0), $id3tag['NAME']);
        $this->name = $tmp[0];

        $tmp = explode(Chr(0), $id3tag['ARTISTS']);
        $this->artists = $tmp[0];

        $tmp = explode(Chr(0), $id3tag['ALBUM']);
        $this->album = $tmp[0];

        $tmp = explode(Chr(0), $id3tag['YEAR']);
        $this->year = $tmp[0];

        $tmp = explode(Chr(0), $id3tag['COMMENT']);
        $this->comment = $tmp[0];

        if (isset($id3tag['TRACK'])) {
        $this->id3v11 = true;
        $this->track = $id3tag['TRACK'];
        }

        $this->genreno = $id3tag['GENRENO'];
        $this->genre = $id3tag['GENRE'];
    } else {
        return $id3tag ;
        }

    if ($this->debug) print($this->debugend);
    } // _read_v1()

    /*
     * decodes that ID3v1 or ID3v1.1 tag
     *
     * false will be returned if there was an error decoding the tag
     * else an array will be returned
     *
     * @param   string  $rawtag    tag to decode
     * @return  string  decoded tag
     */
    function _decode_v1($rawtag) {
    if ($this->debug) print($this->debugbeg . "_decode_v1(\$rawtag)<HR>\n");

    if ($rawtag[125] == Chr(0) and $rawtag[126] != Chr(0)) {
        // ID3 v1.1
        $format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a28COMMENT/x1/C1TRACK/C1GENRENO';
    } else {
        // ID3 v1
        $format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a30COMMENT/C1GENRENO';
    }

    $id3tag = unpack($format, $rawtag);
    if ($this->debug) print_r($id3tag);

    if ($id3tag['TAG'] == 'TAG') {
        $id3tag['GENRE'] = $this->getgenre($id3tag['GENRENO']);
    } else {
        $id3tag = PEAR::raiseError( 'TAG not found', PEAR_MP3_ID_TNF);
    }
    if ($this->debug) print($this->debugend);
    return $id3tag;
    } // _decode_v1()


    /*
     * writes a ID3 v1 or v1.1 tag to a file
     *
     * @return mixed    returns PEAR_Error when fails
     */
    function _write_v1() {
    if ($this->debug) print($this->debugbeg . "_write_v1()<HR>\n");

    $file = $this->file;

    if (! ($f = @fopen($file, 'r+b')) ) {
        return PEAR::raiseError( "Unable to open " . $file, PEAR_MP3_ID_FNO);
    }

    if (fseek($f, -128, SEEK_END) == -1) {
//        $this->error = 'Unable to see to end - 128 of ' . $file;
        return PEAR::raiseError( "Unable to see to end - 128 of " . $file, PEAR_MP3_ID_RE);
    }

    $this->genreno = $this->getgenreno($this->genre, $this->genreno);

    $newtag = $this->_encode_v1();

    $r = fread($f, 128);

    if ( !PEAR::isError( $this->_decode_v1($r))) {
        if (fseek($f, -128, SEEK_END) == -1) {
//        $this->error = 'Unable to see to end - 128 of ' . $file;
        return PEAR::raiseError( "Unable to see to end - 128 of " . $file, PEAR_MP3_ID_RE);
        }
        fwrite($f, $newtag);
    } else {
        if (fseek($f, 0, SEEK_END) == -1) {
//        $this->error = 'Unable to see to end of ' . $file;
        return PEAR::raiseError( "Unable to see to end of " . $file, PEAR_MP3_ID_RE);
        }
        fwrite($f, $newtag);
    }
    fclose($f);


    if ($this->debug) print($this->debugend);
    } // _write_v1()

    /*
     * encode the ID3 tag
     *
     * the newly built tag will be returned
     *
     * @return string the new tag
     */
    function _encode_v1() {
    if ($this->debug) print($this->debugbeg . "_encode_v1()<HR>\n");

    if ($this->track) {
        // ID3 v1.1
        $id3pack = 'a3a30a30a30a4a28x1C1C1';
        $newtag = pack($id3pack,
            'TAG',
            $this->name,
            $this->artists,
            $this->album,
            $this->year,
            $this->comment,
            $this->track,
            $this->genreno
              );
    } else {
        // ID3 v1
        $id3pack = 'a3a30a30a30a4a30C1';
        $newtag = pack($id3pack,
            'TAG',
            $this->name,
            $this->artists,
            $this->album,
            $this->year,
            $this->comment,
            $this->genreno
              );
    }

    if ($this->debug) {
        print('id3pack: ' . $id3pack . "\n");
        $unp = unpack('H*new', $newtag);
        print_r($unp);
    }

    if ($this->debug) print($this->debugend);
    return $newtag;
    } // _encode_v1()

    /*
     * if exists it removes an ID3v1 or v1.1 tag
     *
     * returns true if the tag was removed or none was found
     * else false if there was an error
     *
     * @return boolean true, if the tag was removed
     */
    function _remove_v1() {
    if ($this->debug) print($this->debugbeg . "_remove_v1()<HR>\n");

    $file = $this->file;

    if (! ($f = fopen($file, 'r+b')) ) {
        return PEAR::raiseError( "Unable to open " . $file, PEAR_MP3_ID_FNO);
    }

    if (fseek($f, -128, SEEK_END) == -1) {
        return PEAR::raiseError( 'Unable to see to end - 128 of ' . $file, PEAR_MP3_ID_RE);
    }

    $r = fread($f, 128);

    $success = false;
    if ( !PEAR::isError( $this->_decode_v1($r))) {
        $size = filesize($this->file) - 128;
        if ($this->debug) print('size: old: ' . filesize($this->file));
        $success = ftruncate($f, $size);   
        clearstatcache();
        if ($this->debug) print(' new: ' . filesize($this->file));
    }
    fclose($f);
    if ($this->debug) print($this->debugend);
    return $success;
    } // _remove_v1()

    /**
    * reads a frame from the file
    *
    * @return mixed PEAR_Error when fails
    */
    function _readframe() {
    if ($this->debug) print($this->debugbeg . "_readframe()<HR>\n");

    $file = $this->file;

    if (! ($f = fopen($file, 'rb')) ) {
        if ($this->debug) print($this->debugend);
        return PEAR::raiseError( "Unable to open " . $file, PEAR_MP3_ID_FNO) ;
    }

    $this->filesize = filesize($file);

    do {
        while (fread($f,1) != Chr(255)) { // Find the first frame
        if ($this->debug) echo "Find...\n";
        if (feof($f)) {
            if ($this->debug) print($this->debugend);
            return PEAR::raiseError( "No mpeg frame found", PEAR_MP3_ID_NOMP3) ;
        }
        }
        fseek($f, ftell($f) - 1); // back up one byte

        $frameoffset = ftell($f);

        $r = fread($f, 4);
        // Binary to Hex to a binary sting. ugly but best I can think of.
        $bits = unpack('H*bits', $r);
        $bits =  base_convert($bits['bits'],16,2);
    } while (!$bits[8] and !$bits[9] and !$bits[10]); // 1st 8 bits true from the while
    if ($this->debug) print('Bits: ' . $bits . "\n");

    $this->frameoffset = $frameoffset;

    fclose($f);

    if ($bits[11] == 0) {
        $this->mpeg_ver = "2.5";
        $bitrates = array(
            '1' => array(0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0),
            '2' => array(0,  8, 16, 24, 32, 40, 48,  56,  64,  80,  96, 112, 128, 144, 160, 0),
            '3' => array(0,  8, 16, 24, 32, 40, 48,  56,  64,  80,  96, 112, 128, 144, 160, 0),
                 );
    } else if ($bits[12] == 0) {
        $this->mpeg_ver = "2";
        $bitrates = array(
            '1' => array(0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0),
            '2' => array(0,  8, 16, 24, 32, 40, 48,  56,  64,  80,  96, 112, 128, 144, 160, 0),
            '3' => array(0,  8, 16, 24, 32, 40, 48,  56,  64,  80,  96, 112, 128, 144, 160, 0),
                 );
    } else {
        $this->mpeg_ver = "1";
        $bitrates = array(
            '1' => array(0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0),
            '2' => array(0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, 0),
            '3' => array(0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 0),
                 );
    }
    if ($this->debug) print('MPEG' . $this->mpeg_ver . "\n");

    $layer = array(
        array(0,3),
        array(2,1),
              );
    $this->layer = $layer[$bits[13]][$bits[14]];
    if ($this->debug) print('layer: ' . $this->layer . "\n");

    if ($bits[15] == 0) {
        // It's backwards, if the bit is not set then it is protected.
        if ($this->debug) print("protected (crc)\n");
        $this->crc = true;
    }

    $bitrate = 0;
    if ($bits[16] == 1) $bitrate += 8;
    if ($bits[17] == 1) $bitrate += 4;
    if ($bits[18] == 1) $bitrate += 2;
    if ($bits[19] == 1) $bitrate += 1;
    $this->bitrate = $bitrates[$this->layer][$bitrate];

    $frequency = array(
        '1' => array(
            '0' => array(44100, 48000),
            '1' => array(32000, 0),
                ),
        '2' => array(
            '0' => array(22050, 24000),
            '1' => array(16000, 0),
                ),
        '2.5' => array(
            '0' => array(11025, 12000),
            '1' => array(8000, 0),
                  ),
          );
    $this->frequency = $frequency[$this->mpeg_ver][$bits[20]][$bits[21]];

    $this->padding = $bits[22];
    $this->private = $bits[23];

    $mode = array(
        array('Stereo', 'Joint Stereo'),
        array('Dual Channel', 'Mono'),
             );
    $this->mode = $mode[$bits[24]][$bits[25]];

    // XXX: I dunno what the mode extension is for bits 26,27

    $this->copyright = $bits[28];
    $this->original = $bits[29];

    $emphasis = array(
        array('none', '50/15ms'),
        array('', 'CCITT j.17'),
             );
    $this->emphasis = $emphasis[$bits[30]][$bits[31]];

    if ($this->bitrate == 0) {
        $s = -1;
    } else {
        $s = ((8*filesize($this->file))/1000) / $this->bitrate;       
    }
    $this->length = sprintf('%02d:%02d',floor($s/60),floor($s-(floor($s/60)*60)));
    $this->lengths = (int)$s;

    if ($this->debug) print($this->debugend);
    } // _readframe()

    /*
     * getGenre - return the name of a genre number
     *
     * if no genre number is specified the genre number from
     * $this->genreno will be used.
     *
     * the genre is returned or false if an error or not found
     * no error message is ever returned
     *
     * @param   integer $genreno Number of the genre
     * @return  mixed   false, if no genre found, else string
     *
     * @access public     
     */
    function getGenre($genreno) {
    if ($this->debug) print($this->debugbeg . "getgenre($genreno)<HR>\n");

    $genres = $this->genres();
    if (isset($genres[$genreno])) {
        $genre = $genres[$genreno];
        if ($this->debug) print($genre . "\n");
    } else {
        $genre = '';
    }

    if ($this->debug) print($this->debugend);
    return $genre;
    } // getGenre($genreno)

    /*
     * getGenreNo - return the number of the genre name
     *
     * the genre number is returned or 0xff (255) if a match is not found
     * you can specify the default genreno to use if one is not found
     * no error message is ever returned
     *
     * @param   string  $genre      Name of the genre
     * @param   integer $default    Genre number in case of genre not found
     *
     * @access public
     */
    function getGenreNo($genre, $default = 0xff) {
    if ($this->debug) print($this->debugbeg . "getgenreno('$genre',$default)<HR>\n");

    $genres = $this->genres();
    $genreno = false;
    if ($genre) {
        foreach ($genres as $no => $name) {
        if (strtolower($genre) == strtolower($name)) {
            if ($this->debug) print("$no:'$name' == '$genre'");
            $genreno = $no;
        }
        }
    }
    if ($genreno === false) $genreno = $default;
    if ($this->debug) print($this->debugend);
    return $genreno;
    } // getGenreNo($genre, $default = 0xff)

    /*
     * genres - reuturns an array of the ID3v1 genres
     *
     * @return array
     *
     * @access public
     */
    function genres() {
    return array(
        0   => 'Blues',
        1   => 'Classic Rock',
        2   => 'Country',
        3   => 'Dance',
        4   => 'Disco',
        5   => 'Funk',
        6   => 'Grunge',
        7   => 'Hip-Hop',
        8   => 'Jazz',
        9   => 'Metal',
        10  => 'New Age',
        11  => 'Oldies',
        12  => 'Other',
        13  => 'Pop',
        14  => 'R&B',
        15  => 'Rap',
        16  => 'Reggae',
        17  => 'Rock',
        18  => 'Techno',
        19  => 'Industrial',
        20  => 'Alternative',
        21  => 'Ska',
        22  => 'Death Metal',
        23  => 'Pranks',
        24  => 'Soundtrack',
        25  => 'Euro-Techno',
        26  => 'Ambient',
        27  => 'Trip-Hop',
        28  => 'Vocal',
        29  => 'Jazz+Funk',
        30  => 'Fusion',
        31  => 'Trance',
        32  => 'Classical',
        33  => 'Instrumental',
        34  => 'Acid',
        35  => 'House',
        36  => 'Game',
        37  => 'Sound Clip',
        38  => 'Gospel',
        39  => 'Noise',
        40  => 'Alternative Rock',
        41  => 'Bass',
        42  => 'Soul',
        43  => 'Punk',
        44  => 'Space',
        45  => 'Meditative',
        46  => 'Instrumental Pop',
        47  => 'Instrumental Rock',
        48  => 'Ethnic',
        49  => 'Gothic',
        50  => 'Darkwave',
        51  => 'Techno-Industrial',
        52  => 'Electronic',
        53  => 'Pop-Folk',
        54  => 'Eurodance',
        55  => 'Dream',
        56  => 'Southern Rock',
        57  => 'Comedy',
        58  => 'Cult',
        59  => 'Gangsta',
        60  => 'Top 40',
        61  => 'Christian Rap',
        62  => 'Pop/Funk',
        63  => 'Jungle',
        64  => 'Native US',
        65  => 'Cabaret',
        66  => 'New Wave',
        67  => 'Psychadelic',
        68  => 'Rave',
        69  => 'Showtunes',
        70  => 'Trailer',
        71  => 'Lo-Fi',
        72  => 'Tribal',
        73  => 'Acid Punk',
        74  => 'Acid Jazz',
        75  => 'Polka',
        76  => 'Retro',
        77  => 'Musical',
        78  => 'Rock & Roll',
        79  => 'Hard Rock',
        80  => 'Folk',
        81  => 'Folk-Rock',
        82  => 'National Folk',
        83  => 'Swing',
        84  => 'Fast Fusion',
        85  => 'Bebob',
        86  => 'Latin',
        87  => 'Revival',
        88  => 'Celtic',
        89  => 'Bluegrass',
        90  => 'Avantgarde',
        91  => 'Gothic Rock',
        92  => 'Progressive Rock',
        93  => 'Psychedelic Rock',
        94  => 'Symphonic Rock',
        95  => 'Slow Rock',
        96  => 'Big Band',
        97  => 'Chorus',
        98  => 'Easy Listening',
        99  => 'Acoustic',
        100 => 'Humour',
        101 => 'Speech',
        102 => 'Chanson',
        103 => 'Opera',
        104 => 'Chamber Music',
        105 => 'Sonata',
        106 => 'Symphony',
        107 => 'Booty Bass',
        108 => 'Primus',
        109 => 'Porn Groove',
        110 => 'Satire',
        111 => 'Slow Jam',
        112 => 'Club',
        113 => 'Tango',
        114 => 'Samba',
        115 => 'Folklore',
        116 => 'Ballad',
        117 => 'Power Ballad',
        118 => 'Rhytmic Soul',
        119 => 'Freestyle',
        120 => 'Duet',
        121 => 'Punk Rock',
        122 => 'Drum Solo',
        123 => 'Acapella',
        124 => 'Euro-House',
        125 => 'Dance Hall',
        126 => 'Goa',
        127 => 'Drum & Bass',
        128 => 'Club-House',
        129 => 'Hardcore',
        130 => 'Terror',
        131 => 'Indie',
        132 => 'BritPop',
        133 => 'Negerpunk',
        134 => 'Polsk Punk',
        135 => 'Beat',
        136 => 'Christian Gangsta Rap',
        137 => 'Heavy Metal',
        138 => 'Black Metal',
        139 => 'Crossover',
        140 => 'Contemporary Christian',
        141 => 'Christian Rock',
        142 => 'Merengue',
        143 => 'Salsa',
        144 => 'Trash Metal',
        145 => 'Anime',
        146 => 'Jpop',
        147 => 'Synthpop'
            );
    } // genres
} // end of id3

?>



примеры:

На сегодняшний день музыкальные магазины online, наподобие Musikload[1], становятся все более распространенными и пользуются бешенной популярностью. В этой статье мы расскажем как можно читать мета-информацию mp3-файла средствами PHP, что поможет вам в создании каталога музыки. Это очень просто, поддержка базы данных не нужна.

Откуда знает MP3-Player, например Winamp информацию об исполнителе или названии композиции, которую он проигрывает? Может быть, он сам каким-то чудным образом узнает название песни и альбома? Нет, здесь нет никакого волшебства! Подобная информация содержится в самих файлах. Музыкальные файлы других форматов таких как WMA или Ogg Vorbis также содержат подобную информацию, но здесь речь пойдет о файлах в формате mp3.

Спецификация mp3 определяет способ хранения музыкальных данных, однако не предусматривает никакой возможности для сохранения метаданных композиции, таких как название и исполнитель. Чтобы обойти это ограничение был разработан стандарт ID3. Согласно этой спецификации, метаданные должны быть помещены в так называемые ID3-теги, которые независимо от используемого стандарта ID3, помещаются в конец или начало файла. ID3-теги версии 1 (ID3v1-Tags) представляют собой простейшую конструкцию, которая дописывается в конец файла. Ее объем не должен превышать 128 байт. Структура тега такова: после строкового значения “TAG» следует информация о названии (30 символов), исполнителе (30 символов), альбоме (30 символов), годе записи (четырехзначное число), комментарий (30 символов), жанр (1 байт). Тег с подобной структурой обозначается как ID3v1.0-Tag. В дополнение к этому существует еще стандарт ID3v1.1-Tag, который встречается значительно чаще, поскольку позволяет сохранять информацию о порядковом номере композиции в альбоме. Вследствие этого был урезан до 28 символов размер комментария. Сразу после комментария следует нуль-байт, а последующий байт содержит информации о номере трэка. На иллюстрации один и два видна структура обоих стандартов.
PEAR придет на помощь!

Для считывания информации из ID3v1 тегов, в библиотеку PEAR уже был включен пакет MP3_Id[3], который поможет Вам без проблем извлекать информацию из тега, или наоборот записывать. Если в файл отсутствует ID3-тег, вы можете его создать. Листинг 1 показывает как можно считывать информацию из тегов. Создается объект класса MP3_ID, считывается файл, а затем метод getTag() извлекает данные, которые помещаются для дальнейшей обработки в отдельные поля объект. Листинг 2 показывает результат действия программы листинга 1. Общий обзор доступных полей вы найдете в документации по пакету на домашней странице PEAR.

Листинг 1:

Код:
<?php
require_once 'MP3/Id.php';

// Создаем объект, читаем файл
$id3 = &new MP3_Id();
$result = $id3->read('../data/Little-Big-Man.mp3');
if (PEAR::isError($result)) {
die($result->getMessage() . "n");
}

// Читаем поля и выводим информацию
echo 'Название: ' . $id3->getTag('name') . "n";
echo 'Исполнитель: ' . $id3->getTag('artists') . "n";
echo 'Альбом: ' . $id3->getTag('album') . "n";
echo 'Год: ' . $id3->getTag('year') . "n";
echo 'Комментарий: ' . $id3->getTag('comment') . "n";
echo 'Жанр: ' . $id3->getTag('genre') . "n";
echo 'Жанр (число): ' . $id3->getTag('genreno') . "n";
echo 'Трэк: ' . $id3->getTag('track') . "n";
?>


Листинг 2:

Название: Little Big Man
Исполнитель: Dirty Mac
Альбом: Demo-Tape
Год: 2001
Комментарий: Песня из альбома Demo-Tape
Жанр: Rock
Жанр (число): 17
Трэк: 5

Листинг 3 показывает как просто можно изменять содержимое ID3-тегов и создавать их. Сначала, как это было показано в Листинге 1, создаем объект класса MP3_ID, считываем файл, а с помощью метода setTag($fieldname, $value) помещаем в тег нужную информацию. Хотите удалить все теги? Тогда посмотрите на листинг 4, где показано как можно сделать это. Для удаления тегов используется метод remove(), а остальное вы уже знаете. Необходимо дополнить, что MP3_Id обладает другими полезными функциями, которые вам позволят перенести содержимое тега из одного файла в другой или сформировать массив, содержащий все музыкальные направления. Для получения дополнительной информации смотрите документацию.

Listing 3:

Код:
<?php
require_once 'MP3/Id.php';

// создаем объект, читаем данные
$id3 = &new MP3_Id();
$result = $id3->read('../data/Little-Big-Man.mp3');
// Ошибка "Tag not found" игнорируется
if (PEAR::isError($result) && $result->getCode() !== PEAR_MP3_ID_TNF) {
die($result->getMessage() . "n");
}

// Определяем информацию
$id3->setTag('name', 'Neuer Titel');
$id3->setTag('artists', 'Andere Band');
$id3->setTag('album', 'Schlagertraum #3');
$id3->setTag('year', 1984);
$id3->setTag('comment', 'Volksmusikal. Hochgenuss');
$id3->setTag('genre', 'Folk');
$id3->setTag('track', 5);

// Записываем информацию в тег
$result = $id3->write();
if (PEAR::isError($result)) {
die($result->getMessage() . "n");
}

echo "Тег успешно записан.! n";
?>


Listing 4:

Код:
<?php
require_once 'MP3/Id.php';

// Создаем объект, читаем файл
$id3 = &new MP3_Id();
$err = $id3->read('../data/Little-Big-Man.mp3');
if (PEAR::isError($err)) {
die($err->getMessage() . "n");
}

// Удаляем тег
$result = $id3->remove();
if (PEAR::isError($result)) {
die($result->getMessage() . "n");
}

echo "Тег успешно стерт! n";
?>


Используем PECL

В конце лета 2004 года появилось расширение PHP ext/id3[7]. Разрабатывается в рамках PECL[6]. В отличие от MP3_ID эта библиотека написана не на PHP, а на C, поэтому она должно работать несколько быстрее. Однако библиотека не входит в стандартный комплект PHP-исходников, к тому же на сегодняшний день отсутствует стабильная версия, хотя функции отвечающие за чтение и запись ID3-тегов считаются стабильными.

Если вы хотите использовать именно это расширение, для установки необходимо воспользоваться либо PEAR-installer, либо откомпилировать php, включив поддержку данного расширения. Если вы используете WINDOWS, существует возможность скачать уже откомпилированную DLL для версии php 5.0 или 5.01 с сайта PHP-Snapshot[9], поместить ее в каталог с расширениями php (например c:phpext), подключить через php.ini. Чтобы воспользоваться расширением, вы должны иметь PHP 4.3 или более позднюю версию, поскольку библиотека использует Streams-API.

Само собой разумеется, библиотека позволяет изменять содержимое ID3-тегов. Для этого вам не нужно ничего, кроме массива, представленного в листинге 6, и функции id3_set_tag(). В качестве первого параметра функция принимает имя изменяемого mp-3 файла, а в качестве второго - массив с необходимыми данными. Третий параметр необязателен и представляет собой константу, указывающую версию ID3-тега. В существующей версии библиотеки функция id3_set_tag() может работать только с тегами версии 1.0 или 1.1. Листинг 7 содержит необходимый php-код. В дополнение к этому, листинг 8 показывает как с помощью функции id3_remove_tag можно удалить существующий ID3-тег.

Ext/id3 содержит еще несколько полезных функций, которые позволяют определить версию ID3-тега (id3_get_version) или манипулируют со списком музыкальных направлений и их id, представленных в виде целого числа типа integer. Надо сказать, что данное число мало подходит для указания музыкального направления.

Listing 5:

Код:
<?php
// имя файла на локальном диске
$tag1 = id3_get_tag('../data/Little-Big-Man.mp3', ID3_V1_1);
print_r($tag1);

// имя файла в виде URL
// Внимание! Или вы подключаетесь к DSL, или ждете ;-)
$tag2 = id3_get_tag('http://dirty-mac.com/sounds/little_big_man.mp3', ID3_V1_1);
print_r($tag2);

// идентификатор ресурса вместо имени файла
$fd = fopen('../data/Little-Big-Man.mp3', 'r');
$tag3 = id3_get_tag($fd, ID3_V1_1);
print_r($tag3);
?>


Listing 6:

Код:
Array
(
[title] => Little Big Man
[artist] => Dirty Mac
[album] => Demo-Tape
[year] => 2001
[comment] => Song vom Demo-Tape
[track] => 5
[genre] => 17
)


Listing 7:

Код:
<?php
$tag = array(
'title' => 'Новое название',
'artist' => 'Другая группа',
'album' => 'Schlagertraum #3',
'year' => 1984,
'genre' => id3_get_genre_id('Rock'),
'comment' => 'Отличная популярная мелодия',
'track' => 5
);

// Записываем тег
$result = id3_set_tag('../data/Little-Big-Man.mp3', $tag, ID3_V1_1 );
if ($result === false) {
echo "Тег не был успешно записан! n";
}

echo "Тег успешно записан! n";


Следующее поколение

Несмотря на то, что с помощь ID3v1-тегов уже можно сохранять важнейшую информацию о содержимом mp3-файла, уже проявляются ограничения версий 1.0 и 1.1:

* из-за фиксированного размера тега ограничен объем сохраняемой информации
* ограничено количество сохраняемых атрибутов

Как мы видим, расширить объем пространства, отведенный под ID3v1 теги нельзя, Существую трудности с сохранением информации о названии композиции, исполнителе, альбоме, комментарии, если размер данных превышает 30 символов. Допустим, вам нужно указать название The Hitchhiker's Guide to the Galaxy, используя стандарт ID3v1, вы можете сохранить лишь The Hitchhiker's Guide to. Та же ситуации наблюдается с указанием музыкального направления. Для этого выделяется только один байт, вследствие этого количество музыкальных направлений не может превышать 256. Наверное, сегодня этого достаточно, но кто знает, сколько в будущем появится еще музыкальных направлений.

Чтобы преодолеть указанные ограничения был введены ID3-теги версии 2[2], или короче ID3v2. ID3v2-теги записываются в начало файла, собственно перед самими аудио данными. Информация организована в отдельные единицы, которые обозначаются как фреймы. ID3v2 - это формат-контейнер, то есть, существует возможность при изменении тега вводить новые фреймы. Из этого следует, что ID3v2 может содержать значительно больше информации, чем ID3v1. Это может быть информация об авторских правах, битрейте, (BMP) или, наконец, полный текст песни или изображения. В дополнение к этому можно по желанию добавлять новые фреймы. Вот важнейшие достоинства данного формата:

* Никаких ограничений на объем сохраняемой информации
* Гибкость и расширяемость
* Возможность сжатия содержимого тегов
* Поддержка Unicode
* Возможность хранить бинарные данные, например изображения и файлы.

Из-за расширенных возможностей ID3v2-теги, несколько труднее поддаются считыванию, чем ID3v1-теги. Хорошая новость состоит в том, что ext/id3 уже позволяет извлекать важнейшую информацию. Если вы исполните код, помещенный в листинг 9, вы получите тот же результат, что и в листинге 10. Проделав это, вы сможете убедиться, что объем выводимых данных значительно шире, чем тот, что показан в листингах 5 и 6.

Каждый фрейм ID3v2-тега обладает уникальным ID. Ext/id3 содержит две функции, которые позволяют узнать содержимое фрейма. Это id3_get_frame_short() и id3_get_frame_long_name(). В качестве параметра они принимают id фрейма и возвращают его описание.

В будущих версиях ext/id3 будет содержать другие полезные функции, которые позволят считывать или записывать фреймы, соответствующие спецификации ID3.

Листинг 8:

Код:
<?php
// удаляет тег
$result = id3_remove_tag('../data/Little-Big-Man.mp3');

if ($result === false) {
echo "Тег не удален.! n";
}

echo "Тег успешно удален! n";
?>


Listing 9:

Код:
<?php
//Читаем тег ID3v2
$tag = id3_get_tag('../data/Little-Big-Man.mp3', ID3_V2_3);
print_r($tag);
?>


Дополнительная информация

Прежде чем вы организуете бизнес, связанный с продажей музыкальных композиций online, мы вам расскажем еще о нескольких полезных возможностях библиотеки MP3_Id. С помощью нее можно не только считывать информацию ID3- тегов, она позволяет получить некоторую интересную информацию о самом mp3-файле. Речь идет о битрейте, длительности звучания и других полезных свойствах. Подобные сведения можно получить при помощи метода study(), а дальше посредством метода getTag(), можно выбирать необходимые данные. Листинг 12 показывает как это работает. Результат работы программы показан в листинге 13. К сожалению, эти возможности недостаточно документированы, т.е. трудно разобраться какой атрибут можно считать при помощи getTag() или изменить посредство setTag(). В этом случае необходимо изучить код модуля MP3/Id.php.

Listing 10:

Код:
Array
(
[copyright] => Dirty Mac
[originalArtist] => Dirty Mac
[composer] => Marcus Goetze
[artist] => Dirty Mac
[title] => Little Big Man
[album] => Demo-Tape
[track] => 5/12
[genre] => (17)Rock
[year] => 2001
)


Listing 11:

Код:
<?php
// Id ID3v2-Frames
$frame = 'TOLY';
$short = id3_get_frame_short_name($frame);
$descr = id3_get_frame_long_name($frame);
echo "Frame: $frame n";
echo "Kurzform: $short n";
echo "Beschreibung: $descr n";
?>


Listing 12:

Код:
<?php
require_once 'MP3/Id.php';

// создаем объект, считываем данные
$id3 = &new MP3_Id();
$result = $id3->read('../data/Little-Big-Man.mp3');
// Ошибкаr "Tag not found" игнорируется
if (PEAR::isError($result) && $result->getCode() !== PEAR_MP3_ID_TNF) {
die($result->getMessage() . "n");
}

$result = $id3->study();
if (PEAR::isError($result)) {
die($result->getMessage() . "n");
}

echo 'MPEG ' . $id3->getTag('mpeg_ver') . ' Layer ' . $id3->getTag('layer') . "n";
echo $id3->getTag('mode') . "n";
echo 'Размер файла: ' . $id3->getTag('filesize') . " Bytes n";
echo 'Bitrate: ' . $id3->getTag('bitrate') . "kB/s n";
echo 'Длительность: ' . $id3->getTag('length') . " min n";
echo 'Samplerate: ' . $id3->getTag('frequency') . "Hz n";
?>


Listing 13:

MPEG 1 Layer 3
Joint Stereo
Размерe: 4089856 Bytes
Bitrate: 128kB/s
Длительность: 04:15 min
Samplerate: 44100Hz
Выводы

В этой статье мы рассмотрели существующие возможности извлечения информации из mp-3 файлов средствами PHP. Обе библиотеки (MP3_Id и id3) легки в использовании и содержать необходимые функции. Одна библиотека написана на PHP, другая на C. Выбор того или иного варианта определяется вашими предпочтениями и возможностями хостинга.
Изображение
:roll:
Alexsandrit
Активный участник
 
Сообщения: 256
Зарегистрирован: 29 сен 2007, 16:47
Домен: http://proekts.vfose.ru/


Вернуться в PHP, HTML, CSS...

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 122