先安装sox和音频解码包,ubuntu下安装如下:

sudo apt-get install sox libsox-fmt-all

sox使用文档

Demo如下,下面的代码可以跑通,只是代码未整理:

<?php

namespace App\Services;

/**
* 需要先安装sox: sudo apt install sox libsox-fmt-all
*/
class WaveformService
{
protected $filename;
protected $info;
protected $channels;
protected $samples;
protected $sampleRate;
protected $duration;

public static $linesPerPixel = 4;
public static $samplesPerLine = 512;

public function __construct($filename)
{
$this->filename = $filename;
}

public function getInfo()
{
$out = null;
$ret = null;
exec('sox --i ' . escapeshellarg($this->filename) . ' 2>&1', $out, $ret);
$str = implode('|', $out);
$match = null;
if (preg_match('/Channels?\s*\:\s*(\d+)/ui', $str, $match)) {
$this->channels = intval($match[1]);
}

$match = null;
if (preg_match('/Sample\s*Rate\s*\:\s*(\d+)/ui', $str, $match)) {
$this->sampleRate = intval($match[1]);
}

$match = null;
if (preg_match('/Duration.*[^\d](\d+)\s*samples?/ui', $str, $match)) {
$this->samples = intval($match[1]);
}

if ($this->samples && $this->sampleRate) {
$this->duration = 1.0 * $this->samples / $this->sampleRate;
}

if ($ret !== 0) {
throw new \Exception('Failed to get audio info.' . PHP_EOL . 'Error: ' . implode(PHP_EOL, $out) . PHP_EOL);
}
}

public function getSampleRate()
{
if (!$this->sampleRate) {
$this->getInfo();
}
return $this->sampleRate;
}

public function getChannels()
{
if (!$this->channels) {
$this->getInfo();
}
return $this->channels;
}

public function getSamples()
{
if (!$this->samples) {
$this->getInfo();
}
return $this->samples;
}

public function getDuration()
{
if (!$this->duration) {
$this->getInfo();
}
return $this->duration;
}

/**
* 波形图数据,返回的是arr
* @return [type] [description]
*/
public function getWaveform()
{
$needChannels = $this->getChannels() > 1 ? 2 : 1;
$samplesPerPixel = self::$samplesPerLine * self::$linesPerPixel;
$needRate = 1.0 * 720 * $samplesPerPixel * $this->getSampleRate() / $this->getSamples();

// Command text
$command = 'sox ' . escapeshellarg($this->filename) .
' -c ' . $needChannels .
' -r ' . $needRate . ' -e floating-point -t raw -';

$outputs = [
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];

$pipes = null;
$proc = proc_open($command, $outputs, $pipes);

if (!$proc) {
throw new \Exception('Failed to run sox command, plesae install sox');
}

$lines1 = [];
$lines2 = [];
while ($chunk = fread($pipes[1], 4 * $needChannels * self::$samplesPerLine)) {
$data = unpack('f*', $chunk);
$channel1 = [];
$channel2 = [];
foreach ($data as $index => $sample) {
if ($needChannels === 2 && $index % 2 === 0) {
$channel2 []= (float) number_format($sample, 4);
} else {
$channel1 []= (float) number_format($sample, 4);
}
}
$lines1 []= max($channel1);
if ($needChannels === 2) {
$lines2 []= max($channel2);
}
}

$err = stream_get_contents($pipes[2]);
$ret = proc_close($proc);

if ($ret !== 0) {
throw new \Exception('Failed to run `sox` command. Error:' . PHP_EOL . $err);
}

// 目前只取单声道的
return $lines1;
}
}

使用方法:

$waveform = new WaveformService("音乐路径.mp3");
$waveformDataArr = $waveform->getWaveform();