Advertisement
Guest User

analyze sound file with sox/php

a guest
May 23rd, 2015
369
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 10.81 KB | None | 0 0
  1. <?php
  2. /*
  3.         wrapper for sox, optionally requires sox with mp3 support
  4.     by unosonic
  5. */
  6.  
  7. class sox {
  8.         private $sox_cmd = "/usr/bin/sox";
  9.         private $soxi_cmd = "/usr/bin/soxi";
  10.         private $soxi_chan_cmd = "/usr/bin/soxi -c";
  11.         private $soxi_brate_cmd = "/usr/bin/soxi -b";
  12.         private $soxi_brate_avg_cmd = "/usr/bin/soxi -B";
  13.         private $soxi_srate_cmd = "/usr/bin/soxi -r";
  14.         private $soxi_type_cmd = "/usr/bin/soxi -t";
  15.         private $sox_analyze_stats_cmd = "/usr/bin/sox %s -n stats 2>&1";
  16.         private $sox_analyze_stat_cmd = "/usr/bin/sox %s -n stat 2>&1";
  17.  
  18.  
  19.         public $filetype;
  20.         public $channels;
  21.         public $samplerate;
  22.         public $bitrate;
  23.         public $bitrate_avg;
  24.         public $soundfile;
  25.  
  26.         function __construct ($file) {
  27.  
  28.                 if(!is_file($this->sox_cmd)) {
  29.                         throw new Exception('Error: sox not found.');
  30.                 }
  31.  
  32.                 if(!is_file($this->soxi_cmd)) {
  33.                         throw new Exception('Error: soxi not found.');
  34.                 }
  35.  
  36.                 if(isset($file) && is_file($file)) {
  37.  
  38.                         $cmd = $this->soxi_cmd . ' ' . $file;
  39.                         $type_cmd = $this->soxi_type_cmd . ' ' . $file;
  40.                         $chan_cmd = $this->soxi_chan_cmd . ' ' . $file;
  41.                         $srate_cmd = $this->soxi_srate_cmd . ' ' . $file;
  42.                         $brate_avg_cmd = $this->soxi_brate_avg_cmd . ' ' . $file;
  43.                         $brate_cmd = $this->soxi_brate_cmd . ' ' . $file;
  44.  
  45.                         @exec($cmd, $out, $err);
  46.  
  47.                         // file exists, but sox can't open it
  48.                         if (empty($out) && intval($err == 1)) {
  49.                                 throw new Exception('Error: sound file format of ' . $this->soundfile . ' is not recognized.');
  50.                         }
  51.  
  52.                         // file type
  53.                         unset($out);
  54.                         unset($err);
  55.                         @exec($type_cmd, $out, $err);
  56.                         // var_dump($out);
  57.                         $this->filetype = $out[0];
  58.  
  59.                         // # of channels
  60.                         unset($out);
  61.                         unset($err);
  62.                         @exec($chan_cmd, $out, $err);
  63.                         // var_dump($out);
  64.                         $this->channels = $out[0];
  65.  
  66.                         // sample rate
  67.                         unset($out);
  68.                         unset($err);
  69.                         @exec($srate_cmd, $out, $err);
  70.                         //var_dump($out);
  71.                         $this->samplerate = $out[0];
  72.  
  73.                         // bitrate per sample (0 for mp3)
  74.                         unset($out);
  75.                         unset($err);
  76.                         @exec($brate_cmd, $out, $err);
  77.                         //var_dump($out);
  78.                         $this->bitrate = $out[0];
  79.  
  80.                         // average bitrate over all samples
  81.                         unset($out);
  82.                         unset($err);
  83.                         @exec($brate_avg_cmd, $out, $err);
  84.                         //var_dump($out);
  85.                         $this->bitrate_avg = $out[0];
  86.  
  87.                         // remember soundfile
  88.                         $this->soundfile = $file;
  89.  
  90.  
  91.                         // debug
  92.                         // echo $this->soundfile . " is of type " . $this->filetype . ", has " . $this->channels . " channel(s), a sample rate of " . $this->samplerate . "Hz and a bitrate per sample of " . $this->bitrate . " (" . $this->bitrate_avg . "bi
  93. t/s average over all samples)\n";
  94.  
  95.  
  96.                } else {
  97.                        throw new Exception('Error: no soundfile given or file is not readable.');
  98.                }
  99.        }
  100.  
  101.        /* exec the stat[s] cmd of sox, ugly parsing... save values in array
  102.                "/[\s,]+/"  => arbitrary number of space or comma
  103.                "/:/"
  104.        */
  105.        public function analyze() {
  106.                $stat_cmd = sprintf($this->sox_analyze_stat_cmd, $this->soundfile);
  107.                $stats_cmd = sprintf($this->sox_analyze_stats_cmd, $this->soundfile);
  108.                @exec($stat_cmd, $out_stat, $err);
  109.                @exec($stats_cmd, $out_stats, $err);
  110.                $arr = array();
  111.                foreach ($out_stat as $value) {
  112.  
  113.                        // # of samples read
  114.                        if(strpos($value, "Samples read") !== FALSE) {
  115.                                $arr["samples"] = intval(trim(substr(strrchr($value, ":"), 1)));
  116.                        }
  117.                        // length in seconds
  118.                        if(strpos($value, "Length") !== FALSE) {
  119.                                $arr["length"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  120.                        }
  121.                        // The maximum sample value in the audio
  122.                        if(strpos($value, "Maximum amplitude") !== FALSE) {
  123.                                $arr["max_amp"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  124.                        }
  125.                        // The minimum sample value in the audio
  126.                        if(strpos($value, "Minimum amplitude") !== FALSE) {
  127.                                $arr["min_amp"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  128.                        }
  129.                        //  ½min(xk)+½max(xk)
  130.                        if(strpos($value, "Midline amplitude") !== FALSE) {
  131.                                $arr["mid_amp"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  132.                        }
  133.                        // The  average  of the absolute value of each sample in the audio: ¹/nΣ│xk│
  134.                        if(strpos($value, "Mean    norm") !== FALSE) {
  135.                                $arr["mean_norm"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  136.                        }
  137.                        // ¹/nΣxk The average of each sample in the audio, >0 => DC offset
  138.                        if(strpos($value, "Mean    amplitude") !== FALSE) {
  139.                                $arr["mean_amp"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  140.                        }
  141.                        //  √(¹/nΣxk²) The level of a D.C. signal with same power as average audio's power
  142.                        if(strpos($value, "RMS     amplitude") !== FALSE) {
  143.                                $arr["rms_amp"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  144.                        }
  145.                        // max(│xk-xk-1│)
  146.                        if(strpos($value, "Maximum delta") !== FALSE) {
  147.                                $arr["max_delta"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  148.                        }
  149.                        // min(│xk-xk-1│)
  150.                        if(strpos($value, "Minimum delta") !== FALSE) {
  151.                                $arr["min_delta"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  152.                        }
  153.                        // ¹/n-1Σ│xk-xk-1│
  154.                        if(strpos($value, "Mean    delta") !== FALSE) {
  155.                                $arr["mean_delta"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  156.                        }
  157.                        // √(¹/n-1Σ(xk-xk-1)²)
  158.                        if(strpos($value, "RMS     delta") !== FALSE) {
  159.                                $arr["rms_delta"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  160.                        }
  161.                        // rough frequency of audio?
  162.                        if(strpos($value, "Rough   frequency") !== FALSE) {
  163.                                $arr["freq"] = intval(trim(substr(strrchr($value, ":"), 1)));
  164.                        }
  165.                        // value to amplify to 0 dB
  166.                        if(strpos($value, "Volume adjustment") !== FALSE) {
  167.                                $arr["vol_adjust"] = floatval(trim(substr(strrchr($value, ":"), 1)));
  168.                        }
  169.  
  170.                };
  171.  
  172.                // output of stats cmd,
  173.                foreach ($out_stats as $value) {
  174.  
  175.                        if(strpos($value, "DC offset") !== FALSE) {
  176.                                $h = preg_split("/[\s]{2,}/", $value);
  177.                                $arr["dc_offset"] = floatval(trim($h[1]));
  178.                        }
  179.                        if(strpos($value, "Crest factor") !== FALSE) {
  180.                                // split at 2 or more spaces:
  181.                                $h = preg_split("/[\s]{2,}/", $value);
  182.                                $c = isset($h[2]) && isset($h[3]) ? floatval((trim($h[2]) + trim($h[3]))/2) : floatval(trim($h[1]));
  183.                                $arr["crest_factor"] = $c;
  184.                        }
  185.                        if(strpos($value, "Flat factor") !== FALSE) {
  186.                                $h = preg_split("/[\s]{2,}/", $value);
  187.                                $arr["flat_factor"] = floatval(trim($h[1]));
  188.                        }
  189.                        if(strpos($value, "Pk lev dB") !== FALSE) {
  190.                                $h = preg_split("/[\s]{2,}/", $value);
  191.                                $arr["peak_level"] = floatval(trim($h[1]));
  192.                        }
  193.                        if(strpos($value, "Pk count") !== FALSE) {
  194.                                $h = preg_split("/[\s]{2,}/", $value);
  195.                                // check if we have [k]ilos of peaks...
  196.                                if(substr($h[1], -1) == "k") {
  197.                                        $p = intval(rtrim($h[1], "k") * 1000);
  198.                                } else {
  199.                                        $p = intval($h[1]);
  200.                                }
  201.                                $arr["peak_count"] = $p;
  202.                        }
  203.                }
  204.  
  205.                /* check if a file is clipping at 0dB: get max/min ampitude and peak count:
  206.                   if amplitude = +/- 1 and peak count > n => clipping */
  207.  
  208.                if (($arr["max_amp"] == 1 || $arr["min_amp"] == -1) && $arr["peak_count"] > 100) {
  209.                        $arr["clipping"] = TRUE;
  210.                } else {
  211.                        $arr["clipping"] = FALSE;
  212.                }
  213.  
  214.                // check for dc offset, 0.001 reasonable?
  215.                if ($arr["dc_offset"] > 0.001) {
  216.                        $arr["has_dc"] = TRUE;
  217.                } else {
  218.                        $arr["has_dc"] = FALSE;
  219.                }
  220.                return $arr;
  221.        }
  222. }
  223.  
  224. // test it.
  225. $file = $_SERVER['argv'][1];
  226. if(is_file($file)) {
  227.        $sox = new sox($file);
  228.        print_r($sox->analyze());
  229.        // var_dump($sox->analyze());
  230. } else {
  231.        echo "no soundfile given\n";
  232. }
  233.  
  234. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement