powered by nequal
Home » Packages » GD_Tab_Guitar » Source

GD_Tab_Guitar / trunk/Guitar.php

Subversion URL: http://svn.openpear.org/GD_Tab_Guitar/trunk/Guitar.php

Recent change

cloned [32] -- 2008-11-01 21:46:44
インストール先のディレクトリに入れておく必要がなかったので修正

<?php
/**
 * GD_Tab_Guitar generates guitar tab scores.
 * This module is inspired by GD::Tab::Guitar (perl module), and it's almost its copy.
 *
 *
 * SYNOPSIS
 *
 * $gtr = new GD_Tab_Guitar();
 * 
 * // print png image
 * print $gtr->chord('D#sus4')->png();
 * 
 * // other tab generate
 * $gtr->generate('G7', array(1,0,0,0,2,3))->png();
 * 
 * // above fret style (1st string to 6th string) is unfamiliar to most guitarists.
 * // you can also specify the reversed and familiar style like this:
 * $gtr->generate('G7', '320001')->png();
 * 
 * // if you want to specify some mute strings, put "x" character.
 * $gtr->generate('D7', 'x00212')->png();
 * 
 * // set color
 * $gtr->setColor(255, 0, 0);
 * 
 * // set background-color and no interlace
 * $gtr->setBgcolor(200, 200, 200);
 * $gtr->setInterlaced(0);
 * 
 * // all tabs image save to file.
 * foreach ($gtr->allChords() as $chord) {
 *     $gtr->chord($chord)->png("$chord.png");
 * }
 *
 *
 * @author     NAKAMURA Satoru <clonedoppelganger@gmail.com>
 * @license    New BSD License
 * @version    0.0.1
 * @see http://search.cpan.org/dist/GD-Tab-Guitar/
 * @see http://search.cpan.org/~tateno/GD-Tab-Ukulele-0.01/
 */
class GD_Tab_Guitar
{
 
    const GD_TINY_FONT = 1;
 
    const GD_SMALL_FONT = 2;
 
    protected static $lines = array(
        array(5,  15, 46, 15),
        array(5,  21, 46, 21),
        array(5,  27, 46, 27),
        array(5,  33, 46, 33),
        array(5,  39, 46, 39),
        array(5,  45, 46, 45),
        array(4,  15, 4,  45),
        array(6,  15, 6,  45),
        array(14, 15, 14, 45),
        array(22, 15, 22, 45),
        array(30, 15, 30, 45),
        array(38, 15, 38, 45),
    );
 
    protected static $chordLists = array(
        'C'          => 'x32010',
        'C6'         => 'x32210',
        'C6(9)'      => 'x32233',
        'CM7'        => 'x32000',
        'CM7(9)'     => 'x30000',
        'C7'         => 'x32310',
        'C7(b5)'     => 'x34310',
        'C7(b9)'     => 'x32323',
        'C7(b9,13)'  => 'x21214',
        'C7(9)'      => 'x3233x',
        'C7(9,13)'   => 'x32335',
        'C7(#9)'     => 'x3234x',
        'C7(#11)'    => 'x1213x',
        'C7(b13)'    => 'x1211x',
        'C7(13)'     => 'x1221x',
        'Cm'         => 'x35543',
        'Cm6'        => 'x31213',
        'Cm6(9)'     => 'x3124x',
        'CmM7'       => 'x31003',
        'Cm7'        => 'x31313',
        'Cm7(b5)'    => 'x3434x',
        'Cm7(9)'     => 'x3133x',
        'Cm7(9,11)'  => 'x31331',
        'Cdim'       => 'x3424x',
        'Caug'       => 'x3211x',
        'Caug7'      => 'x323x4',
        'Csus4'      => 'x33011',
        'C7sus4'     => 'x33311',
        'Cadd9'      => 'x32030',
        'C#'         => 'x43121',
        'C#6'        => 'x4332x',
        'C#6(9)'     => 'x43344',
        'C#M7'       => 'x43111',
        'C#M7(9)'    => 'x4354x',
        'C#7'        => 'x4342x',
        'C#7(b5)'    => 'x4542x',
        'C#7(b9)'    => 'x43434',
        'C#7(b9,13)' => 'x43436',
        'C#7(9)'     => 'x4344x',
        'C#7(9,13)'  => 'x43445',
        'C#7(#9)'    => 'x4345x',
        'C#7(#11)'   => 'x4546x',
        'C#7(b13)'   => 'x2322x',
        'C#7(13)'    => 'x2332x',
        'C#m'        => 'x46654',
        'C#m6'       => 'x42324',
        'C#m6(9)'    => 'x4234x',
        'C#mM7'      => 'x4211x',
        'C#m7'       => 'x42100',
        'C#m7(b5)'   => 'x4545x',
        'C#m7(9)'    => 'x4244x',
        'C#m7(9,11)' => 'x42442',
        'C#dim'      => 'x4535x',
        'C#aug'      => 'x4322x',
        'C#aug7'     => 'x2322x',
        'C#sus4'     => 'x46674',
        'C#7sus4'    => 'x44422',
        'C#add9'     => 'x43141',
        'D'          => 'xx0232',
        'D6'         => 'xx0202',
        'D6(9)'      => 'x54455',
        'DM7'        => 'xx0222',
        'DM7(9)'     => 'xx0220',
        'D7'         => 'xx0212',
        'D7(b5)'     => 'xx0112',
        'D7(b9)'     => 'x5454x',
        'D7(b9,13)'  => 'x54547',
        'D7(9)'      => 'xx0210',
        'D7(9,13)'   => 'x54557',
        'D7(#9)'     => 'x5456x',
        'D7(#11)'    => 'xx0112',
        'D7(b13)'    => 'x3433x',
        'D7(13)'     => 'x3443x',
        'Dm'         => 'xx0231',
        'Dm6'        => 'xx0201',
        'Dm6(9)'     => 'x5345x',
        'DmM7'       => 'x5322x',
        'Dm7'        => 'xx0211',
        'Dm7(b5)'    => 'xx0111',
        'Dm7(9)'     => 'x5355x',
        'Dm7(9,11)'  => 'x53553',
        'Ddim'       => 'xx0101',
        'Daug'       => 'xx0332',
        'Daug7'      => 'xx0312',
        'Dsus4'      => 'x55033',
        'D7sus4'     => 'xx0213',
        'Dadd9'      => 'xx0230',
        'Eb'         => 'xx1343',
        'Eb6'        => 'xx1313',
        'Eb6(9)'     => 'x65566',
        'EbM7'       => 'xx1333',
        'EbM7(9)'    => 'xx1331',
        'Eb7'        => 'xx1323',
        'Eb7(b5)'    => 'xx1223',
        'Eb7(b9)'    => 'xx1020',
        'Eb7(b9,13)' => 'x65658',
        'Eb7(9)'     => 'xx1021',
        'Eb7(9,13)'  => 'x65668',
        'Eb7(#9)'    => 'xx1022',
        'Eb7(#11)'   => 'xx1223',
        'Eb7(b13)'   => 'x4544x',
        'Eb7(13)'    => 'x4554x',
        'Ebm'        => 'xx1342',
        'Ebm6'       => 'xx1312',
        'Ebm6(9)'    => 'x6456x',
        'EbmM7'      => 'xx1332',
        'Ebm7'       => 'xx1322',
        'Ebm7(b5)'   => 'xx1222',
        'Ebm7(9)'    => 'x6466x',
        'Ebm7(9,11)' => 'xx1121',
        'Ebdim'      => 'xx1212',
        'Ebaug'      => 'xx1003',
        'Ebaug7'     => 'x2102x',
        'Ebsus4'     => 'xx1344',
        'Eb7sus4'    => 'xx1324',
        'Ebadd9'     => 'xx1341',
        'E'          => '022100',
        'E6'         => '022120',
        'E6(9)'      => 'xx2122',
        'EM7'        => '02110x',
        'EM7(9)'     => '021102',
        'E7'         => '020100',
        'E7(b5)'     => 'xx2334',
        'E7(b9)'     => '020101',
        'E7(b9,13)'  => '020131',
        'E7(9)'      => '020132',
        'E7(9,13)'   => '020122',
        'E7(#9)'     => '020103',
        'E7(#11)'    => '6x675x',
        'E7(b13)'    => '020110',
        'E7(13)'     => '020120',
        'Em'         => '022000',
        'Em6'        => '022020',
        'Em6(9)'     => '022022',
        'EmM7'       => '021000',
        'Em7'        => '020000',
        'Em7(b5)'    => '0x2333',
        'Em7(9)'     => '020002',
        'Em7(9,11)'  => 'xx2232',
        'Edim'       => '012020',
        'Eaug'       => '03211x',
        'Eaug7'      => '032130',
        'Esus4'      => '022200',
        'E7sus4'     => '020200',
        'Eadd9'      => '024100',
        'F'          => '133211',
        'F6'         => '1x323x',
        'F6(9)'      => '100011',
        'FM7'        => 'xx3210',
        'FM7(9)'     => '1x2010',
        'F7'         => '131211',
        'F7(b5)'     => '1x120x',
        'F7(b9)'     => 'xx1212',
        'F7(b9,13)'  => '1x1232',
        'F7(9)'      => '131213',
        'F7(9,13)'   => '1x123x',
        'F7(#9)'     => '131214',
        'F7(#11)'    => '101201',
        'F7(b13)'    => '1x122x',
        'F7(13)'     => '1x123x',
        'Fm'         => '133111',
        'Fm6'        => '133131',
        'Fm6(9)'     => '1xx133',
        'FmM7'       => '13211x',
        'Fm7'        => '131111',
        'Fm7(b5)'    => '1x110x',
        'Fm7(9)'     => '131113',
        'Fm7(9,11)'  => '131313',
        'Fdim'       => '1x0101',
        'Faug'       => 'xx3221',
        'Faug7'      => '1x1221',
        'Fsus4'      => '133311',
        'F7sus4'     => '131311',
        'Fadd9'      => 'xx3213',
        'F#'         => '244322',
        'F#6'        => '2x434x',
        'F#6(9)'     => '2x112x',
        'F#M7'       => 'xx4321',
        'F#M7(9)'    => '2x312x',
        'F#7'        => '242322',
        'F#7(b5)'    => '2x231x',
        'F#7(b9)'    => '212020',
        'F#7(b9,13)' => 'x1204x',
        'F#7(9)'     => '21212x',
        'F#7(9,13)'  => '21213x',
        'F#7(#9)'    => '242325',
        'F#7(#11)'   => '2x231x',
        'F#7(b13)'   => '2x233x',
        'F#7(13)'    => '2x234x',
        'F#m'        => '244222',
        'F#m6'       => '244242',
        'F#m6(9)'    => 'xx1224',
        'F#mM7'      => '24322x',
        'F#m7'       => '242222',
        'F#m7(b5)'   => '2x221x',
        'F#m7(9)'    => '242224',
        'F#m7(9,11)' => '20210x',
        'F#dim'      => '2x121x',
        'F#aug'      => 'xx4332',
        'F#aug7'     => '2x2332',
        'F#sus4'     => '244422',
        'F#7sus4'    => '242422',
        'F#add9'     => 'xx4324',
        'G'          => '320003',
        'G6'         => '320000',
        'G6(9)'      => '3x223x',
        'GM7'        => '320002',
        'GM7(9)'     => '3x423x',
        'G7'         => '320001',
        'G7(b5)'     => '3x342x',
        'G7(b9)'     => 'x2313x',
        'G7(b9,13)'  => '3x3100',
        'G7(9)'      => '353435',
        'G7(9,13)'   => '3x3200',
        'G7(#9)'     => '353436',
        'G7(#11)'    => '3x342x',
        'G7(b13)'    => '3x344x',
        'G7(13)'     => '323000',
        'Gm'         => '355333',
        'Gm6'        => '3x233x',
        'Gm6(9)'     => 'xx2335',
        'GmM7'       => '354333',
        'Gm7'        => '353333',
        'Gm7(b5)'    => '3x332x',
        'Gm7(9)'     => '353335',
        'Gm7(9,11)'  => '3x321x',
        'Gdim'       => '3x232x',
        'Gaug'       => '321003',
        'Gaug7'      => '3x3443',
        'Gsus4'      => '330013',
        'G7sus4'     => '330011',
        'Gadd9'      => '3x0233',
        'G#'         => '431114',
        'G#6'        => '431111',
        'G#6(9)'     => '4x334x',
        'G#M7'       => 'xx6543',
        'G#M7(9)'    => '4x534x',
        'G#7'        => '464544',
        'G#7(b5)'    => '4x453x',
        'G#7(b9)'    => 'x3424x',
        'G#7(b9,13)' => '4x4211',
        'G#7(9)'     => '464546',
        'G#7(9,13)'  => '4x4311',
        'G#7(#9)'    => '464547',
        'G#7(#11)'   => '4x453x',
        'G#7(b13)'   => '4x455x',
        'G#7(13)'    => '434111',
        'G#m'        => '466444',
        'G#m6'       => 'xx1101',
        'G#m6(9)'    => 'xx3446',
        'G#mM7'      => 'xx1103',
        'G#m7'       => '464444',
        'G#m7(b5)'   => 'x20102',
        'G#m7(9)'    => '464446',
        'G#m7(9,11)' => '4x432x',
        'G#dim'      => '4x343x',
        'G#aug'      => 'xx6554',
        'G#aug7'     => '4x4554',
        'G#sus4'     => '466644',
        'G#7sus4'    => '464644',
        'G#add9'     => 'xx6546',
        'A'          => 'x02220',
        'A6'         => 'x02222',
        'A6(9)'      => 'x02202',
        'AM7'        => 'x02120',
        'AM7(9)'     => 'x02100',
        'A7'         => 'x02020',
        'A7(b5)'     => 'x0102x',
        'A7(b9)'     => 'x02323',
        'A7(b9,13)'  => 'x05322',
        'A7(9)'      => 'x02423',
        'A7(9,13)'   => 'x05422',
        'A7(#9)'     => '575658',
        'A7(#11)'    => 'x01023',
        'A7(b13)'    => 'x02021',
        'A7(13)'     => 'x02022',
        'Am'         => 'x02210',
        'Am6'        => 'x02212',
        'Am6(9)'     => 'xx4557',
        'AmM7'       => 'x02110',
        'Am7'        => 'x02010',
        'Am7(b5)'    => 'x01213',
        'Am7(9)'     => 'x02000',
        'Am7(9,11)'  => 'x02433',
        'Adim'       => 'x01212',
        'Aaug'       => 'x03221',
        'Aaug7'      => 'x03021',
        'Asus4'      => 'x02230',
        'A7sus4'     => 'x02030',
        'Aadd9'      => 'x02200',
        'Bb'         => 'x13331',
        'Bb6'        => 'x13333',
        'Bb6(9)'     => 'x10011',
        'BbM7'       => 'x13231',
        'BbM7(9)'    => 'x10211',
        'Bb7'        => 'x13131',
        'Bb7(b5)'    => 'x12131',
        'Bb7(b9)'    => 'x10101',
        'Bb7(b9,13)' => 'x10103',
        'Bb7(9)'     => 'x1011x',
        'Bb7(9,13)'  => 'x10113',
        'Bb7(#9)'    => 'x1012x',
        'Bb7(#11)'   => 'x10130',
        'Bb7(b13)'   => 'x13132',
        'Bb7(13)'    => 'x13133',
        'Bbm'        => 'x13321',
        'Bbm6'       => 'x1302x',
        'Bbm6(9)'    => 'xx5668',
        'BbmM7'      => 'x13221',
        'Bbm7'       => 'x13121',
        'Bbm7(b5)'   => 'x1212x',
        'Bbm7(9)'    => 'x13111',
        'Bbm7(9,11)' => '6x654x',
        'Bbdim'      => 'x12020',
        'Bbaug'      => 'x10443',
        'Bbaug7'     => 'x14132',
        'Bbsus4'     => 'x13341',
        'Bb7sus4'    => 'x13141',
        'Bbadd9'     => 'x13311',
        'B'          => 'x24442',
        'B6'         => 'x24444',
        'B6(9)'      => 'x21122',
        'BM7'        => 'x24342',
        'BM7(9)'     => 'x2132x',
        'B7'         => 'x21202',
        'B7(b5)'     => 'x2324x',
        'B7(b9)'     => 'x2121x',
        'B7(b9,13)'  => 'x21214',
        'B7(9)'      => 'x2122x',
        'B7(9,13)'   => 'x21224',
        'B7(#9)'     => 'x2123x',
        'B7(#11)'    => 'x2324x',
        'B7(b13)'    => 'x24243',
        'B7(13)'     => 'x24244',
        'Bm'         => 'x24432',
        'Bm6'        => 'x2413x',
        'Bm6(9)'     => 'x2012x',
        'BmM7'       => 'x20332',
        'Bm7'        => 'x20202',
        'Bm7(b5)'    => 'x2323x',
        'Bm7(9)'     => 'x2022x',
        'Bm7(9,11)'  => 'x20220',
        'Bdim'       => 'x2313x',
        'Baug'       => 'x2100x',
        'Baug7'      => 'x25243',
        'Bsus4'      => 'x24452',
        'B7sus4'     => 'x22202',
        'Badd9'      => 'x24422',
    );
 
    protected static $synonyms = array(
        'C#' => 'Db',
        'Eb' => 'D#',
        'F#' => 'Gb',
        'G#' => 'Ab',
        'Bb' => 'A#',
    );
 
    protected static $synonymsRe = '/^([CFG]#|[EB]b)/';
 
    private static $initialized = false;
 
    private $bgcolor;
 
    private $color;
 
    private $interlaced;
 
    private $im;
 
    public function __construct()
    {
        if (!self::$initialized) {
            self::init();
        }
        $this->bgcolor    = array(255, 255, 255);
        $this->color      = array(0, 0, 0);
        $this->interlaced = true;
    }
 
    public function setBgcolor($r, $g, $b)
    {
        $this->bgcolor = array($r, $g, $b);
    }
 
    public function setColor($r, $g, $b)
    {
        $this->color = array($r, $g, $b);
    }
 
    public function setInterlaced($interlaced)
    {
        $this->interlaced = $interlaced;
    }
 
    public function chord($chord)
    {
        return $this->generate($chord, $this->getFrets($chord));
    }
 
    public function getFrets($chord)
    {
        if (!isset(self::$chordLists[$chord])) {
            throw new Exception("undefined chord $chord");
        }
        return str_split(self::$chordLists[$chord]);
    }
 
    public function generate($chord, $frets = null)
    {
        if ($frets !== null) {
            $frets = is_array($frets) ? array_reverse($frets) : array_reverse(str_split($frets));
        }
 
        $this->im = imagecreate(52, 56);
        $bgcolor = imagecolorallocate($this->im, $this->bgcolor[0], $this->bgcolor[1], $this->bgcolor[2]);
        $color = imagecolorallocate($this->im, $this->color[0], $this->color[1], $this->color[2]);
 
        if ($this->interlaced) {
            imagecolortransparent($this->im, $bgcolor);
            imageinterlace($this->im, true);
        }
 
        $this->drawLine($color);
 
        $fretMax = max(preg_grep('/^\d+$/', $frets));
 
        if ($fretMax > 5) {
            imagefilledrectangle($this->im, 4, 15, 6, 45, $bgcolor);
            $fretNum = $fretMax - 5;
 
            foreach ($frets as &$fret) {
                if (strtolower($fret) !== 'x') {
                    $fret -= $fretNum;
                }
            }
 
            for ($n = 0; $n <= 4; $n++) {
                imagestring($this->im, self::GD_TINY_FONT, 9 * $n + 4, 47, $fretNum + 1, $color);
                $fretNum++;
            }
        }
 
        $i = 0;
        foreach ($frets as &$fret) {
            if (strtolower($fret) === 'x') {
                imageline($this->im, 0, 14 + 6 * $i, 2, 16 + 6 * $i, $color);
                imageline($this->im, 2, 14 + 6 * $i, 0, 16 + 6 * $i, $color);
            } elseif ($fret > 0) {
                imagefilledrectangle($this->im,
                    9  + 8 * ($fret - 1),
                    14 + 6 * $i,
                    11 + 8 * ($fret - 1),
                    16 + 6 * $i, $color
                );
            }
            $i++;
        }
 
        imagestring($this->im, self::GD_SMALL_FONT, 4, 0, $chord, $color);
 
        return $this;
    }
 
    public function png($path = null)
    {
        return $this->output('png', $path);
    }
 
    public function jpeg($path = null)
    {
        return $this->output('jpeg', $path);
    }
 
    public function gif($path = null)
    {
        return $this->output('gif', $path);
    }
 
    public function allChords()
    {
        return array_keys(self::$chordLists);
    }
 
    protected function output($type, $path = null)
    {
        switch ($type) {
        case 'png':
            $func = 'imagepng';
            break;
        case 'jpeg':
            $func = 'imagejpeg';
            break;
        case 'gif':
            $func = 'imagegif';
            break;
        default:
            $func = 'imagepng';
        }
        if ($path === null) {
            ob_start();
            call_user_func($func, $this->im);
            $contents = ob_get_clean();
            imagedestroy($this->im);
            return $contents;
        } else {
            call_user_func($func, $this->im, $path);
            imagedestroy($this->im);
        }
    }
 
    protected function drawLine($color)
    {
        foreach (self::$lines as $line) {
            imageline($this->im, $line[0], $line[1], $line[2], $line[3], $color);
        }
    }
 
    protected static function init()
    {
        foreach (self::$chordLists as $chord => $frets) {
            if (preg_match(self::$synonymsRe, $chord, $matches)) {
                $matche = $matches[1];
                $sameChord = preg_replace('/^' . $matche . '/', self::$synonyms[$matche], $chord);
                self::$chordLists[$sameChord] = $frets;
            }
        }
        self::$initialized = true;
    }
 
}