} switch ($byte) { // get value for 8-bit wav case 1: $data = findValues($bytes[0], $bytes[1]); break; // get value for 16-bit wav // get value for 16-bit wav case 2: if (ord($bytes[1]) & 128) { $temp = 0; } else { $temp = 128; } $temp = chr((ord($bytes[1]) & 127) + $temp); $data = floor(findValues($bytes[0], $temp) / 256); break; } // skip bytes for memory optimization fseek($handle, $ratio, SEEK_CUR); // draw this data point // data values can range between 0 and 255 $x1 = $x2 = number_format($data_point / $data_size * 100, 2); $y1 = number_format($data / 255 * 100, 2); $y2 = 100 - $y1; // don't bother plotting if it is a zero point if ($y1 != $y2) { $svg .= "<line x1=\"{$x1}%\" y1=\"{$y1}%\" x2=\"{$x2}%\" y2=\"{$y2}%\" />"; } } else { // skip this one due to lack of detail
function generateSoundWave($input, $output, $width, $height, $foreground, $background) { /** * PROCESS THE FILE */ // temporary file name $tmpname = substr(md5(time()), 0, 10); $draw_flat = false; // copy from temp upload directory to current copy($input, "{$tmpname}_o.mp3"); // array of wavs that need to be processed $wavs_to_process = array(); /** * convert mp3 to wav using lame decoder * First, resample the original mp3 using as mono (-m m), 16 bit (-b 16), and 8 KHz (--resample 8) * Secondly, convert that resampled mp3 into a wav * We don't necessarily need high quality audio to produce a waveform, doing this process reduces the WAV * to it's simplest form and makes processing significantly faster */ exec("lame {$tmpname}_o.mp3 -m m -S -f -b 16 --resample 8 {$tmpname}.mp3 && lame -S --decode {$tmpname}.mp3 {$tmpname}.wav"); $wavs_to_process[] = "{$tmpname}.wav"; // delete temporary files unlink("{$tmpname}_o.mp3"); unlink("{$tmpname}.mp3"); $img = false; // generate foreground color list($r, $g, $b) = html2rgb($foreground); // process each wav individually for ($wav = 1; $wav <= sizeof($wavs_to_process); $wav++) { $filename = $wavs_to_process[$wav - 1]; /** * Below as posted by "zvoneM" on * http://forums.devshed.com/php-development-5/reading-16-bit-wav-file-318740.html * as findValues() defined above * Translated from Croation to English - July 11, 2011 */ $handle = fopen($filename, "r"); // wav file header retrieval $heading[] = fread($handle, 4); $heading[] = bin2hex(fread($handle, 4)); $heading[] = fread($handle, 4); $heading[] = fread($handle, 4); $heading[] = bin2hex(fread($handle, 4)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = bin2hex(fread($handle, 4)); $heading[] = bin2hex(fread($handle, 4)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = fread($handle, 4); $heading[] = bin2hex(fread($handle, 4)); // wav bitrate $peek = hexdec(substr($heading[10], 0, 2)); $byte = $peek / 8; // checking whether a mono or stereo wav $channel = hexdec(substr($heading[6], 0, 2)); $ratio = $channel == 2 ? 40 : 80; // start putting together the initial canvas // $data_size = (size_of_file - header_bytes_read) / skipped_bytes + 1 $data_size = floor((filesize($filename) - 44) / ($ratio + $byte) + 1); $data_point = 0; // now that we have the data_size for a single channel (they both will be the same) // we can initialize our image canvas if (!$img) { // create original image width based on amount of detail // each waveform to be processed with be $height high, but will be condensed // and resized later (if specified) $img = imagecreatetruecolor($data_size / DETAIL, $height * sizeof($wavs_to_process)); // fill background of image if ($background == "") { // transparent background specified imagesavealpha($img, true); $transparentColor = imagecolorallocatealpha($img, 0, 0, 0, 127); imagefill($img, 0, 0, $transparentColor); } else { list($br, $bg, $bb) = html2rgb($background); imagefilledrectangle($img, 0, 0, (int) ($data_size / DETAIL), $height * sizeof($wavs_to_process), imagecolorallocate($img, $br, $bg, $bb)); } } while (!feof($handle) && $data_point < $data_size) { if ($data_point++ % DETAIL == 0) { $bytes = array(); // get number of bytes depending on bitrate for ($i = 0; $i < $byte; $i++) { $bytes[$i] = fgetc($handle); } switch ($byte) { // get value for 8-bit wav case 1: $data = findValues($bytes[0], $bytes[1]); break; // get value for 16-bit wav // get value for 16-bit wav case 2: if (ord($bytes[1]) & 128) { $temp = 0; } else { $temp = 128; } $temp = chr((ord($bytes[1]) & 127) + $temp); $data = floor(findValues($bytes[0], $temp) / 256); break; } // skip bytes for memory optimization fseek($handle, $ratio, SEEK_CUR); // draw this data point // relative value based on height of image being generated // data values can range between 0 and 255 $v = (int) ($data / 255 * $height); // don't print flat values on the canvas if not necessary if (!($v / $height == 0.5 && !$draw_flat)) { // draw the line on the image using the $v value and centering it vertically on the canvas imageline($img, (int) ($data_point / DETAIL), $height * $wav - $v, (int) ($data_point / DETAIL), $height * $wav - ($height - $v), imagecolorallocate($img, $r, $g, $b)); } } else { // skip this one due to lack of detail fseek($handle, $ratio + $byte, SEEK_CUR); } } fclose($handle); // delete the processed wav file unlink($filename); } // want it resized? $rimg = imagecreatetruecolor($width, $height); // save alpha from original image imagesavealpha($rimg, true); imagealphablending($rimg, false); // copy to resized imagecopyresampled($rimg, $img, 0, 0, 0, 0, $width, $height, imagesx($img), imagesy($img)); imagepng($rimg, $output, 5); imagedestroy($rimg); imagedestroy($img); }
function mp3toWavForm($fname, $width = 500, $height = 50, $foreground = '#E2E2FF', $background = '#000000', $detail = 3) { $fileInfo = new SplFileInfo($fname); $finalFilename = preg_split('/\\./', $fileInfo->getFilename()); $finalFilename = md5($finalFilename[0]) . '.png'; /** * PROCESS THE FILE */ // temporary file name $tmpname = substr(md5(time()), 0, 10); // copy from temp upload directory to current copy($fname, "{$tmpname}_o.mp3"); /** * convert mp3 to wav using lame decoder * First, resample the original mp3 using as mono (-m m), 16 bit (-b 16), and 8 KHz (--resample 8) * Secondly, convert that resampled mp3 into a wav * We don't necessarily need high quality audio to produce a waveform, doing this process reduces the WAV * to it's simplest form and makes processing significantly faster */ exec("lame.exe {$tmpname}_o.mp3 -f -m m -b 16 --resample 8 {$tmpname}.mp3 && lame --decode {$tmpname}.mp3 {$tmpname}.wav"); // delete temporary files @unlink("{$tmpname}_o.mp3"); @unlink("{$tmpname}.mp3"); $filename = "{$tmpname}.wav"; /** * Below as posted by "zvoneM" on * http://forums.devshed.com/php-development-5/reading-16-bit-wav-file-318740.html * as findValues() defined above * Translated from Croation to English - July 11, 2011 */ $handle = fopen($filename, "r"); //dohvacanje zaglavlja wav datoteke $heading[] = fread($handle, 4); $heading[] = bin2hex(fread($handle, 4)); $heading[] = fread($handle, 4); $heading[] = fread($handle, 4); $heading[] = bin2hex(fread($handle, 4)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = bin2hex(fread($handle, 4)); $heading[] = bin2hex(fread($handle, 4)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = bin2hex(fread($handle, 2)); $heading[] = fread($handle, 4); $heading[] = bin2hex(fread($handle, 4)); //bitrate wav datoteke $peek = hexdec(substr($heading[10], 0, 2)); $byte = $peek / 8; //provjera da li se radi o mono ili stereo wavu $channel = hexdec(substr($heading[6], 0, 2)); if ($channel == 2) { $omjer = 40; } else { $omjer = 80; } while (!feof($handle)) { $bytes = array(); //get number of bytes depending on bitrate for ($i = 0; $i < $byte; $i++) { $bytes[$i] = fgetc($handle); } switch ($byte) { //get value for 8-bit wav case 1: $data[] = findValues($bytes[0], $bytes[1]); break; //get value for 16-bit wav //get value for 16-bit wav case 2: if (ord($bytes[1]) & 128) { $temp = 0; } else { $temp = 128; } $temp = chr((ord($bytes[1]) & 127) + $temp); $data[] = floor(findValues($bytes[0], $temp) / 256); break; } //skip bytes for memory optimization fread($handle, $omjer); } // close and cleanup fclose($handle); unlink("{$tmpname}.wav"); /** * Image generation */ // header("Content-Type: image/png"); // how much detail we want. Larger number means less detail // (basically, how many bytes/frames to skip processing) // the lower the number means longer processing time // get user vars from form // create original image width based on amount of detail $img = imagecreatetruecolor(sizeof($data) / $detail, $height); // fill background of image list($r, $g, $b) = html2rgb($background); imagefilledrectangle($img, 0, 0, sizeof($data) / $detail, $height, imagecolorallocate($img, $r, $g, $b)); // generate background color list($r, $g, $b) = html2rgb($foreground); // loop through frames/bytes of wav data as genearted above for ($d = 0; $d < sizeof($data); $d += $detail) { // relative value based on height of image being generated // data values can range between 0 and 255 $v = (int) ($data[$d] / 255 * $height); // draw the line on the image using the $v value and centering it vertically on the canvas imageline($img, $d / $detail, 0 + ($height - $v), $d / $detail, $height - ($height - $v), imagecolorallocate($img, $r, $g, $b)); } //create file $fp = fopen('images/' . $finalFilename, 'w'); fclose($fp); // want it resized? if ($width) { // resample the image to the proportions defined in the form $rimg = imagecreatetruecolor($width, $height); imagecopyresampled($rimg, $img, 0, 0, 0, 0, $width, $height, sizeof($data) / $detail, $height); imagepng($rimg, 'images/' . $finalFilename); imagedestroy($rimg); } else { // print out at it's raw width (size of $data / detail level) imagepng($img, 'images/' . $finalFilename); imagedestroy($img); } return 'images/' . $finalFilename; }
function mp3_waveform($fname, $width, $height, $foreground, $background) { /** * PROCESS THE FILE */ // temporary file name $tmpname = '/tmp/' . substr(md5(time()), 0, 10); // copy from temp upload directory to current copy($fname, "{$tmpname}_o.mp3"); $imagename = preg_replace('%^(.*)\\.[^.]+$%', '\\1-wave', $fname) . '.png'; /** * convert mp3 to wav using lame decoder * First, resample the original mp3 using as mono (-m m), 16 bit (-b 16), and 8 KHz (--resample 8) * Secondly, convert that resampled mp3 into a wav * We don't necessarily need high quality audio to produce a waveform, doing this process reduces the WAV * to it's simplest form and makes processing significantly faster */ //exec("/usr/local/bin/lame {$tmpname}_o.mp3 --quiet -f -m s -b 64 --resample 8 {$tmpname}.mp3 &&" // ." /usr/local/bin/lame --quiet --decode {$tmpname}.mp3 {$tmpname}.wav"); exec("/usr/local/bin/sox --norm {$tmpname}_o.mp3 -r 8k -b 8 -e unsigned -c 2 {$tmpname}.wav"); // delete temporary files @unlink("{$tmpname}_o.mp3"); //@unlink("{$tmpname}.mp3"); $filename = "{$tmpname}.wav"; if (!file_exists($filename)) { print "Error: WAV file not generated. Please verify directory write and execute permissions."; exit; } /** * Below as posted by "zvoneM" on * http://forums.devshed.com/php-development-5/reading-16-bit-wav-file-318740.html * as findValues() defined above * Translated from Croation to English - July 11, 2011 */ $handle = fopen($filename, "r"); // format: see http://web.archive.org/web/19991115123323/http://www.borg.com/~jglatt/tech/wave.htm $heading[0] = fread($handle, 4); // "RIFF" $heading[1] = bin2hex(fread($handle, 4)); // lSize $heading[2] = fread($handle, 4); // "WAVE" $heading[3] = fread($handle, 4); // "fmt " (format chunk) $heading[4] = bin2hex(fread($handle, 4)); // lChunkSize $heading[5] = bin2hex(fread($handle, 2)); // wFormatTag (=1) $heading[6] = bin2hex(fread($handle, 2)); // wChannels (=2 for stereo) $heading[7] = bin2hex(fread($handle, 4)); // dwSamplesPerSec $heading[8] = bin2hex(fread($handle, 4)); // dwAvgBytesPerSec $heading[9] = bin2hex(fread($handle, 2)); // wBlockAlign $heading[10] = bin2hex(fread($handle, 2)); // wBitsPerSample $heading[11] = fread($handle, 4); // "data" $heading[12] = bin2hex(fread($handle, 4)); // lChunkSize //bitrate wav datoteke $peek = hexdec(substr($heading[10], 0, 2)); $byte = $peek / 8; //provjera da li se radi o mono ili stereo wavu $channel = hexdec(substr($heading[6], 0, 2)); $datasize = hexdec(substr($heading[12], 6, 2) . substr($heading[12], 4, 2) . substr($heading[12], 2, 2) . substr($heading[12], 0, 2)); $omjer = floor($datasize / 512 / 4); error_log('data size = ' . $datasize . ' (' . $heading[12] . ') / omjer = ' . $omjer); //if($channel == 2){ // $omjer = 40; //} //else{ // $omjer = 80; //} //error_log('channels: '.$channel); while (!feof($handle)) { for ($ch = 0; $ch < $channel; $ch++) { $bytes = array(); //get number of bytes depending on bitrate for ($i = 0; $i < $byte; $i++) { $bytes[$i] = fgetc($handle); } switch ($byte) { //get value for 8-bit wav case 1: $data[$ch][] = abs(findValues($bytes[0], $bytes[1]) - 128); break; //get value for 16-bit wav //get value for 16-bit wav case 2: if (ord($bytes[1]) & 128) { $temp = 0; } else { $temp = 128; } $temp = chr((ord($bytes[1]) & 127) + $temp); $data[$ch][] = abs(floor(findValues($bytes[0], $temp) / 256) - 128); break; } } //skip bytes for memory optimization fread($handle, $omjer); } // close and cleanup fclose($handle); unlink("{$tmpname}.wav"); /** * Image generation */ // how much detail we want. Larger number means less detail // (basically, how many bytes/frames to skip processing) // the lower the number means longer processing time $size = sizeof($data[0]); $step = min(array(1, 2 * round($size / $width))); //1 // create original image width based on amount of detail $img = imagecreatetruecolor($size / $step, $height); // fill background of image if ($background == "") { imagesavealpha($img, true); $transparentColor = imagecolorallocatealpha($img, 0, 0, 0, 127); imagefill($img, 0, 0, $transparentColor); } else { list($r, $g, $b) = html2rgb($background); imagefilledrectangle($img, 0, 0, $size / $step, $height, imagecolorallocate($img, $r, $g, $b)); } // generate foreground color list($r, $g, $b) = html2rgb($foreground); //error_log('size:'.$size); if ($size < $width) { $thickness = 1; } else { $thickness = $size / ($width * 2); } imagesetthickness($img, $thickness); $mx = 0; for ($d = 0; $d < $size; $d += $step) { if (abs($data[0][$d]) > $mx) { $mx = abs($data[0][$d]); } if (abs($data[1][$d]) > $mx) { $mx = abs($data[1][$d]); } } $mx *= 1.1; // loop through frames/bytes of wav data as genearted above for ($d = 0; $d < $size; $d += $step) { // relative value based on height of image being generated // data values can range between 0 and 255 $c1 = (int) ($data[0][$d] * $height / 2 / $mx); $c2 = (int) ($data[1][$d] * $height / 2 / $mx); //error_log('L='.$data[0][$d].' / R='.$data[1][$d]); // draw the line on the image using the $v value and centering it vertically on the canvas //imageline($img, $d / $step, round($c1), $d / $step, round($height-$c2), imagecolorallocate($img, $r, $g, $b)); imageline($img, $d / $step, $height / 2, $d / $step, $height / 2 - $c1, imagecolorallocate($img, $r, $g, $b)); imageline($img, $d / $step, $height / 2, $d / $step, $height / 2 + $c2, imagecolorallocate($img, $r, $g, $b)); } // want it resized? if ($width) { // resample the image to the proportions defined in the form $rimg = imagecreatetruecolor($width, $height); // save alpha from original image imagesavealpha($rimg, true); imagealphablending($rimg, false); // copy to resized imagecopyresampled($rimg, $img, 0, 0, 0, 0, $width, $height, $size / $step, $height); imagepng($rimg, $imagename); imagedestroy($rimg); } else { // print out at it's raw width (size of $data / detail level) imagepng($img, $imagename); imagedestroy($img); } unset($data); return $imagename; }