Skip to content

Instantly share code, notes, and snippets.

@ashishmaurya
Last active August 17, 2020 05:14
Show Gist options
  • Save ashishmaurya/5bcda08e124d1bac296ab8df818d48ba to your computer and use it in GitHub Desktop.
Save ashishmaurya/5bcda08e124d1bac296ab8df818d48ba to your computer and use it in GitHub Desktop.
Generate Waveform from music file with PHP
<?php
//Refer : https://github.com/ashishmaurya/waveform-using-php/blob/master/classAudioFileModified.php
//For full class file
function getVisualizationSVG($output) {
$width = $this->visual_width;
$height = $this->visual_height;
$height_channel = $height / $this->wave_channels;
if ($this->wave_filename <> "" && $this->wave_id == "RIFF" && $this->wave_type == "WAVE" && ($this->wave_channels >= 1 && $this->wave_channels <= 2) && $this->wave_bits % 8 == 0) {
$file = fopen($this->wave_filename, "r");
// read the first 12 bytes (RIFF- & WAVE-chunk)
for ($i = 0; $i < 12; $i++) {
$null = fgetc($file);
}
// Read the next chunk-id, supposed to be "fmt "
$chunk_id_3 = fgetc($file) . fgetc($file) . fgetc($file) . fgetc($file);
if ($chunk_id_3 == "fmt ") {
$chunk_size_3 = $this->longCalc(fgetc($file), fgetc($file), fgetc($file), fgetc($file), 0);
for ($i = 0; $i < $chunk_size_3; $i++) {
$null = fgetc($file);
}
// Read the next chunk-id, supposed to be "data"
$chunk_id_4 = "";
while ($chunk_id_4 <> "data" && !feof($file)) {
$chunk_id_4 = fgetc($file) . fgetc($file) . fgetc($file) . fgetc($file);
if ($chunk_id_4 <> "data") {
$chunk_size_4 = $this->longCalc(fgetc($file), fgetc($file), fgetc($file), fgetc($file), 0);
for ($i = 0; $i < $chunk_size_4; $i++) {
$null = fgetc($file);
}
}
}
if ($chunk_id_4 == "data") {
$chunk_size_4 = $this->longCalc(fgetc($file), fgetc($file), fgetc($file), fgetc($file), 0);
$visualData = array();
$bytes_per_frame = ($this->wave_bits / 8) * ($this->wave_channels);
$bytes_per_channel = ($this->wave_bits / 8);
$frames = $chunk_size_4 / $bytes_per_frame;
$visual_frames = ceil($frames / $width);
$frame_index = 1;
$data_index = 1;
// revised code -- computing bytes per pixel allows quick processing of large (>10MB) wavs by fseek()ing past unused data
$bytes_per_pixel = floor($chunk_size_4 / $width);
$currentindex = 0;
while (!feof($file) && $currentindex < $chunk_size_4) {
$loopindex = 0;
for ($j = 0; $j < $this->wave_channels; $j++) {
$bytes = array();
for ($i = 0; $i < $bytes_per_channel; $i++) {
$bytes[$i] = fgetc($file);
$loopindex++;
}
switch ($bytes_per_channel) {
case 1: $visualData[$j][$data_index] = $this->shortCalc($bytes[0], $bytes[1], 0);
break;
case 2: $f = 128;
if (ord($bytes[1]) & 128)
$f = 0;
$x = chr((ord($bytes[1]) & 127) + $f);
$visualData[$j][$data_index] = floor($this->shortCalc($bytes[0], $x, 0) / 256);
break;
}
if (($j + 1) == $this->wave_channels) {
$data_index++;
}
}
$currentindex+= ( $bytes_per_pixel - $loopindex );
fseek($file, $bytes_per_pixel, SEEK_CUR);
}
// this for-loop draws a graph for every channel
for ($j = 0; $j < 1; $j++) {
$last_x = 1;
$last_y = $height_channel / 2;
// this for-loop draws the graphs itself
$data = array();
for ($i = 1; $i < sizeof($visualData[$j]); $i++) {
$faktor = 128 / ($height_channel / 2);
$val = $visualData[$j][$i] / $faktor;
$data[] = $val;
}
$this->data = $data;
//Genrate Wave SVG file
$f = fopen($output, "w");
$data = $this->data;
$txt = '<svg xmlns="http://www.w3.org/2000/svg" width="' . $this->visual_width . '" height="' . $this->visual_height . '">';
$txt .= "<style>";
$txt .= "line{stroke:#CCC;stroke-width:1.5}";
$txt .= "</style>";
$COUNT_POINT = count($data);
$MAX_NUMBER_OF_POINT = 180;
$SKIP_COUNT = floor($COUNT_POINT / $MAX_NUMBER_OF_POINT);
for ($i = 0; $i < $COUNT_POINT; $i++) {
if ($i % $SKIP_COUNT != ($SKIP_COUNT - 1)) {
continue;
}
$y1_4 = $this->visual_height / 4;
$y1 = $this->visual_height - $y1_4;
$y2 = $data[$i];
$y2_4 = ($this->visual_height - $y2) / 4;
$y2 = $y2 - $y2_4;
$y1_4 = $y1 + 1;
$y2_4 +=$y1_4;
$y2 = number_format((float) $y2, 1, '.', '');
$y2_4 = number_format((float) $y2_4, 1, '.', '');
$y2 = round($y2);
$y2_4 = round($y2_4);
$txt .= '<line x1="' . $i . '" y1="' . $y2 . '" x2="' . $i . '" y2="' . $y2_4 . '"/>';
}
$txt .= '<line x1="' . 0 . '" y1="' . $y1_4 . '" x2="' . $this->visual_width . '" y2="' . $y1_4 . '" style="stroke:#FFF;stroke-width:1;"/>';
$txt.="</svg>";
fwrite($f, $txt);
fclose($f);
}
}
}
fclose($file);
} else {
// AudioSample - AudioFile-Object not initialized!
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment