%PDF- %PDF-
Direktori : /data/www_bck/varak.net_bck/ampache.varak.net/lib/class/ |
Current File : //data/www_bck/varak.net_bck/ampache.varak.net/lib/class/waveform.class.php |
<?php /* vim:set softtabstop=4 shiftwidth=4 expandtab: */ /** * * LICENSE: GNU General Public License, version 2 (GPLv2) * Copyright 2001 - 2014 Ampache.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License v2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /** * Waveform code generation license: * * * Copyright (c) 2011, Andrew Freiday * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * * https://github.com/afreiday/php-waveform-png * */ class Waveform { public $id; /** * Constructor */ private function __construct() { // Static return false; } // Constructor public static function get($song_id) { $song = new Song($song_id); $waveform = null; if ($song->id) { $song->format(); $waveform = $song->waveform; if (!$waveform) { $catalog = Catalog::create_from_id($song->catalog); if ($catalog->get_type() == 'local') { $transcode_to = 'wav'; $transcode_cfg = AmpConfig::get('transcode'); $valid_types = $song->get_stream_types(); if ($song->type != $transcode_to) { $basedir = AmpConfig::get('tmp_dir_path'); if ($basedir) { if ($transcode_cfg != 'never' && in_array('transcode', $valid_types)) { $tmpfile = tempnam($basedir, $transcode_to); $tfp = fopen($tmpfile, 'wb'); if (!is_resource($tfp)) { debug_event('waveform', "Failed to open " . $tmpfile, 3); return null; } $transcoder = Stream::start_transcode($song, $transcode_to); $fp = $transcoder['handle']; if (!is_resource($fp)) { debug_event('waveform', "Failed to open " . $song->file . " for waveform.", 3); return null; } do { $buf = fread($fp, 2048); fwrite($tfp, $buf); } while (!feof($fp)); fclose($fp); fclose($tfp); $waveform = self::create_waveform($tmpfile); //$waveform = self::create_waveform("C:\\tmp\\test.wav"); @unlink($tmpfile); } else { debug_event('waveform', 'transcode setting to wav required for waveform.', '3'); } } else { debug_event('waveform', 'tmp_dir_path setting required for waveform.', '3'); } } // Already wav file, no transcode required else { $waveform = self::create_waveform($song->file); } } if ($waveform) { self::save_to_db($song_id, $waveform); } } } return $waveform; } protected static function findValues($byte1, $byte2) { $byte1 = hexdec(bin2hex($byte1)); $byte2 = hexdec(bin2hex($byte2)); return ($byte1 + ($byte2*256)); } /** * Great function slightly modified as posted by Minux at * http://forums.clantemplates.com/showthread.php?t=133805 */ protected static function html2rgb($input) { $input=($input[0]=="#")?substr($input, 1,6):substr($input, 0,6); return array( hexdec(substr($input, 0, 2)), hexdec(substr($input, 2, 2)), hexdec(substr($input, 4, 2)) ); } protected static function create_waveform($filename) { $detail = 5; $width = 400; $height = 32; $foreground = AmpConfig::get('waveform_color') ?: '#FF0000'; $background = ''; $draw_flat = true; // generate foreground color list($r, $g, $b) = self::html2rgb($foreground); $handle = fopen($filename, "r"); // wav file header retrieval $heading = array(); $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; // 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); // 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) = self::html2rgb($background); imagefilledrectangle($img, 0, 0, (int) ($data_size / $detail), $height, 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 = self::findValues($bytes[0], $bytes[1]); break; // 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(self::findValues($bytes[0], $temp) / 256); break; default: $data = 0; 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, // x1 (int) ($data_point / $detail), // y1: height of the image minus $v as a percentage of the height for the wave amplitude $height - $v, // x2 (int) ($data_point / $detail), // y2: same as y1, but from the bottom of the image $height - ($height - $v), imagecolorallocate($img, $r, $g, $b) ); } else { // skip this one due to lack of detail fseek($handle, $ratio + $byte, SEEK_CUR); } } // close and cleanup fclose($handle); ob_start(); // 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, imagesx($img), imagesy($img)); imagepng($rimg); imagedestroy($rimg); } else { imagepng($img); } imagedestroy($img); $imgdata = ob_get_contents(); ob_clean (); return $imgdata; } protected static function save_to_db($song_id, $waveform) { $sql = "UPDATE `song_data` SET `waveform` = ? WHERE `song_id` = ?"; return Dba::write($sql, array($waveform, $song_id)); } } // Waveform class