From df6ffc3da9d202aa1dd5bcfb363e938871681f44 Mon Sep 17 00:00:00 2001 From: Zach DeCook Date: Tue, 13 Feb 2018 15:11:34 -0500 Subject: * Tabs Project: Initial Commit --- .gitmodules | 3 + ccharter | 1 + functions.js | 17 +++ index.css | 219 ++++++++++++++++++++++++++++++++ index.less | 131 +++++++++++++++++++ index.php | 111 ++++++++++++++++ jsonly.js | 110 ++++++++++++++++ page.js | 111 ++++++++++++++++ page.php | 400 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ toc-filter.js | 18 +++ 10 files changed, 1121 insertions(+) create mode 100644 .gitmodules create mode 160000 ccharter create mode 100644 functions.js create mode 100644 index.css create mode 100644 index.less create mode 100755 index.php create mode 100644 jsonly.js create mode 100644 page.js create mode 100644 page.php create mode 100644 toc-filter.js diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1d7efec --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ccharter"] + path = ccharter + url = https://github.com/earboxer/ccharter.git diff --git a/ccharter b/ccharter new file mode 160000 index 0000000..dffd1be --- /dev/null +++ b/ccharter @@ -0,0 +1 @@ +Subproject commit dffd1beac4f5fa588efd324924c9e55a22e7d57d diff --git a/functions.js b/functions.js new file mode 100644 index 0000000..63480a3 --- /dev/null +++ b/functions.js @@ -0,0 +1,17 @@ +function array_flip (trans) { // eslint-disable-line camelcase + // discuss at: http://locutus.io/php/array_flip/ + // original by: Kevin van Zonneveld (http://kvz.io) + // improved by: Pier Paolo Ramon (http://www.mastersoup.com/) + // improved by: Brett Zamir (http://brett-zamir.me) + // example 1: array_flip( {a: 1, b: 1, c: 2} ) + // returns 1: {1: 'b', 2: 'c'} + var key + var tmpArr = {} + for (key in trans) { + if (!trans.hasOwnProperty(key)) { + continue + } + tmpArr[trans[key]] = key + } + return tmpArr +} \ No newline at end of file diff --git a/index.css b/index.css new file mode 100644 index 0000000..61f21d0 --- /dev/null +++ b/index.css @@ -0,0 +1,219 @@ +pre { + font-weight: bold; + font-size: 1em; +} +.tabs, +.chord0, +.chordC { + /*Red Apple*/ + color: #c00000; + font-weight: bold; +} +.chord1, +.chord-11, +.chordDb { + color: #f7102c; + text-shadow: 1px 1px 1px black; +} +.chord2, +.chord-10, +.chordD { + color: #ff6400; +} +.chord3, +.chord-9, +.chordEb { + color: #fcb30f; + text-shadow: 1px 1px 1px black; +} +.chord4, +.chord-8, +.chordE { + color: #c8c800; +} +.chord5, +.chord-7, +.chordF { + color: #d0ff14; + text-shadow: 1px 1px 1px black; +} +.chord6, +.chord-6, +.chordGb { + /*Green Apple*/ + color: #64c000; +} +.chord7, +.chord-5, +.chordG { + /*Lime*/ + color: #00dc00; +} +.chord8, +.chord-4, +.chordAb { + /*Blue Razzberry*/ + color: #0096c8; +} +.chord9, +.chord-3, +.chordA { + /*Blueberry*/ + color: #0000c8; +} +.chord10, +.chord-2, +.chordBb { + color: #9600be; +} +.chord11, +.chord-1, +.chordB { + color: #e7417c; +} +.btn-Z { + margin-top: 1em; + color: white; + background-color: #999; + border-color: #777777; +} +.btn-Z:hover { + color: white; + background-color: #888888; + border-color: #666666; +} +.btn-C { + margin-top: 1em; + color: white; + background-color: #c00000; + border-color: #9e0000; +} +.btn-C:hover { + color: white; + background-color: #af0000; + border-color: #8d0000; +} +.btn-Db { + margin-top: 1em; + color: white; + background-color: #f7102c; + border-color: #d5000a; + text-shadow: 1px 1px 1px black; +} +.btn-Db:hover { + color: white; + background-color: #e6001b; + border-color: #c40000; +} +.btn-D { + margin-top: 1em; + color: white; + background-color: #ff6400; + border-color: #dd4200; +} +.btn-D:hover { + color: white; + background-color: #ee5300; + border-color: #cc3100; +} +.btn-Eb { + margin-top: 1em; + color: white; + background-color: #fcb30f; + border-color: #da9100; + text-shadow: 1px 1px 1px black; +} +.btn-Eb:hover { + color: white; + background-color: #eba200; + border-color: #c98000; +} +.btn-E { + margin-top: 1em; + color: white; + background-color: #c8c800; + border-color: #a6a600; +} +.btn-E:hover { + color: white; + background-color: #b7b700; + border-color: #959500; +} +.btn-F { + margin-top: 1em; + color: white; + background-color: #d0ff14; + border-color: #aedd00; + text-shadow: 1px 1px 1px black; +} +.btn-F:hover { + color: white; + background-color: #bfee03; + border-color: #9dcc00; +} +.btn-Gb { + margin-top: 1em; + color: white; + background-color: #64c000; + border-color: #429e00; +} +.btn-Gb:hover { + color: white; + background-color: #53af00; + border-color: #318d00; +} +.btn-G { + margin-top: 1em; + color: white; + background-color: #00dc00; + border-color: #00ba00; +} +.btn-G:hover { + color: white; + background-color: #00cb00; + border-color: #00a900; +} +.btn-Ab { + margin-top: 1em; + color: white; + background-color: #0096c8; + border-color: #0074a6; +} +.btn-Ab:hover { + color: white; + background-color: #0085b7; + border-color: #006395; +} +.btn-A { + margin-top: 1em; + color: white; + background-color: #0000c8; + border-color: #0000a6; +} +.btn-A:hover { + color: white; + background-color: #0000b7; + border-color: #000095; +} +.btn-Bb { + margin-top: 1em; + color: white; + background-color: #9600be; + border-color: #74009c; +} +.btn-Bb:hover { + color: white; + background-color: #8500ad; + border-color: #63008b; +} +.btn-B { + margin-top: 1em; + color: white; + background-color: #e7417c; + border-color: #c51f5a; +} +.btn-B:hover { + color: white; + background-color: #d6306b; + border-color: #b40e49; +} diff --git a/index.less b/index.less new file mode 100644 index 0000000..2ba475a --- /dev/null +++ b/index.less @@ -0,0 +1,131 @@ +@Red-Apple: rgb(192,0,0); +@Cherry: rgb(255,0,0); +@Strawberry: rgb(247, 16, 44); +@Grapefruit: rgb(231,91,40);//Going into retirement. +@Orange: rgb(255,100,0); +@Banana: rgb(150,150,0);//Going into retirement. +@Mango: rgb(252, 179, 15); +@Lemon: rgb(200,200,0);//This color is not accurately named. +@Pear: rgb(208, 255, 20);//Too bright to see! +@Green-Apple: rgb(100,192,0);//Going into retirement. +@Lime: rgb(0,220,0); +@Blue-Razzberry: rgb(0,150,200); +@Blueberry: rgb(0,0,200); +@Blackberry: rgb(50,0,100);//Going into retirement. +@Grape: rgb(150,0,190); +@Raspberry: rgb(231, 65, 124); + +@ColorC: @Red-Apple; +@ColorDb: @Strawberry; +@ColorD: @Orange; +@ColorEb: @Mango; +@ColorE: @Lemon; +@ColorF: @Pear; +@ColorGb: @Green-Apple; +@ColorG: @Lime; +@ColorAb: @Blue-Razzberry; +@ColorA: @Blueberry; +@ColorBb: @Grape; +@ColorB: @Raspberry; +pre { + font-weight: bold; + font-size: 1em; +} +.chordZ(@color: #BBB){ + color: @color; + & when(hsvvalue(@color) > 95%) and (lightness(@color) > 51%){ + text-shadow: 1px 1px 1px black; + } +} +.tabs, .chord0, .chordC{/*Red Apple*/ + .chordZ(@ColorC); + font-weight: bold; +} +.chord1, .chord-11, .chordDb{ + .chordZ(@ColorDb) +} +.chord2, .chord-10, .chordD{ + .chordZ(@ColorD); +} +.chord3, .chord-9, .chordEb{ + .chordZ(@ColorEb); +} +.chord4, .chord-8, .chordE{ + .chordZ(@ColorE); +} +.chord5, .chord-7, .chordF{ + .chordZ(@ColorF); +} +.chord6, .chord-6, .chordGb{/*Green Apple*/ + .chordZ(@ColorGb); +} +.chord7, .chord-5, .chordG{/*Lime*/ + .chordZ(@ColorG); +} +.chord8, .chord-4, .chordAb{/*Blue Razzberry*/ + .chordZ(@ColorAb); +} +.chord9, .chord-3, .chordA{/*Blueberry*/ + .chordZ(@ColorA); +} +.chord10, .chord-2, .chordBb{ + .chordZ(@ColorBb); +} +.chord11, .chord-1, .chordB{ + .chordZ(@ColorB); +} + +.btn-Z(@color: #999){ + margin-top: 1em; + color: white; + background-color: @color; + border-color: @color - #222; + & when(hsvvalue(@color) > 95%) and (lightness(@color) > 51%){ + text-shadow: 1px 1px 1px black; + } + &:hover{ + color: white; + background-color: @color - #111; + border-color: @color - #333; + } +} +.btn-Z{ + .btn-Z; +}; + +.btn-C{ + .btn-Z(@ColorC); +} +.btn-Db{ + .btn-Z(@ColorDb); +} +.btn-D{ + .btn-Z(@ColorD); +} +.btn-Eb{ + .btn-Z(@ColorEb); +} +.btn-E{ + .btn-Z(@ColorE); +} +.btn-F{ + .btn-Z(@ColorF); +} +.btn-Gb{ + .btn-Z(@ColorGb); +} +.btn-G{ + .btn-Z(@ColorG); +} +.btn-Ab{ + .btn-Z(@ColorAb); +} +.btn-A{ + .btn-Z(@ColorA); +} +.btn-Bb{ + .btn-Z(@ColorBb); +} +.btn-B{ + .btn-Z(@ColorB); +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100755 index 0000000..bc25f51 --- /dev/null +++ b/index.php @@ -0,0 +1,111 @@ + + + + + + + + + + + + Choruses and Hymns + + +

+ + +

+ +
+

Browse Songs

+ Table of contents +
+ ' + min='0' max='169' + /> + +
+
+ +
+
+ +
+ Experimental: Click on a chord to view guitar tablature +
+
+ +

+

+ +

+
+
+
+ + + +
+
+ + +
+ + +


+All songs are owned by their respective copyright holders. No infringement intended. +
+ + + + + + + + + + + diff --git a/jsonly.js b/jsonly.js new file mode 100644 index 0000000..9e1cf2d --- /dev/null +++ b/jsonly.js @@ -0,0 +1,110 @@ +/** + * @brief jsonly.js contains the functions that are only called in js, + * not translated from server-side code. + */ + +$('#transp').change( do_transpose ); +var lastTransp = parseInt($('#transp').val()); + +function do_transpose() +{ + var transp = parseInt($('#transp').val()); + var neww = transp; + + $(".tabs").each(function(){ + // Since we only store text that is displayed, transpose relative to + // previous transposition. + // Requires the class to be "tabs chordXX"; + var old = parseInt($(this).attr('class').substring(10)); + if ( isNaN(old) ) + { + old = $(this).attr('class').substring(10); + neww = transpadd(old, transp - lastTransp); + } + $(this).text( zj_transpose2( $(this).text(), transp - lastTransp ) ); + $(this).removeClass("chord"+old); + $(this).addClass("chord"+neww); + }); + $(".btn[data-key]").each(function(){ + console.log($(this)); + var oldKey = $(this).attr('data-key'); + var newKey = transpadd(oldKey, transp - lastTransp); + $(this).removeClass('btn-'+oldKey); + $(this).addClass('btn-'+newKey); + $(this).attr('data-key', newKey); + $(this).text( $(this).attr('data-words') + newKey ); + var tt = parseInt($(this).attr('href').match(/transp=(.+)/)[1]); + tt = ( transp - lastTransp + 24 + tt)%12; + var newhref = $(this).attr('href').match(/(.*?&transp=).+/)[1] + tt; + $(this).attr('href', newhref); + }) + lastTransp = transp; +} + +$(".tabs").click(function(e) { + s = window.getSelection(); + var range = s.getRangeAt(0); + var node = s.anchorNode; + while (range.toString().indexOf(' ') != 0 ) { + if (range.startOffset == 0) + break; + range.setStart(node, (range.startOffset - 1)); + } + range.setStart(node, Math.max(0,range.startOffset)); + while (range.toString().lastIndexOf(' ') != range.toString().length - 1 + || range.toString().length <= 1 ) + { + range.setEnd(node, range.endOffset+1); + if ( range.endOffset == node.length) + break; + } + //range.setEnd(Math.min(range.endOffset+1,node.length); + var str = range.toString().trim(); + if( str != "" ) + show_tab(str); +}); + +function show_tab( chord ) +{ + var canvas = $("#chordy")[0]; + var context = canvas.getContext('2d'); + context.clearRect(0, 0, canvas.width, canvas.height); + + getChordFrets(chord); + +/* + var img = ""; + $("#chordarea").append(img); + $(".myimage").error(function(){ + $(this).hide(); + });*/ +} + +function getChordFrets(chord) +{ + $("#messages").html(""); + chord = chord.replace("(", ""); + chord = chord.replace(")", ""); + chord = chord.replace("sus", "s"); + chord = chord.replace("s4", "s"); + chord = chord.replace("s", "sus"); + chord = chord.replace("7sus", "sus7"); + chord = chord.replace("mj7", "maj7"); + var chordd = chord; + chordd = chordd.replace("Db", "C#"); + chordd = chordd.replace("Eb", "D#"); + chordd = chordd.replace("Gb", "F#"); + chordd = chordd.replace("Ab", "G#"); + chordd = chordd.replace("Bb", "A#"); + taco = chorddict[chordd]; + if ( taco ) { + ChordCharter.drawChord("chordy", 30, 25, chord, taco); + } else { + //Cross-origin stuff + /*var url = "http://jguitar.com/chordsearch?chordsearch="+chord+"&labels=none&fretSpan=4"; + $.get(url, function(data, status){ + $("#messages").prepend("something something gotten"); + });*/ + $("#messages").prepend("Couldn't find a chord for '"+ chord +"'"); + } +} \ No newline at end of file diff --git a/page.js b/page.js new file mode 100644 index 0000000..8815b63 --- /dev/null +++ b/page.js @@ -0,0 +1,111 @@ +/** + * @brief page.js tries to improve pageload speeds + * by processing client-side. + * @author Zach DeCook (zjd7calvin) + * @date 12, February 2017 + * requires jQuery + */ + +/** + * @brief zj_transpose2 transposes a line + */ +function zj_transpose2( line, transp ) +{ + var newchords = zj_transparray( transp ); + var newline = ''; + var space = 0; ///@< Spaces that need to be added or removed. + for(var i = 0; i < line.length; i++) + { + var chari = line[i]; + var nchar = line[i+1]; + var upchar = line[i].toUpperCase(); + var cval = upchar.charCodeAt(0); + // A-G + if( cval <= 71 && cval >=65 ) + { + // Exception for Cmaj7 + if( upchar == 'A' && nchar == 'j' ) + { + newline += chari; + } + else if( nchar == 'b' || nchar =='#') + { + i++; //We have read an extra character now. + var newchord = newchords[upchar + nchar]; + if( newchord.length == 1 ) + { + // Need to insert an extra space. + space += 1; + } + newline += newchord; + } + else + { + var newchord = newchords[upchar]; + if( newchord.length == 2 ) + { + // Need to remove an extra space. + space -= 1; + } + newline += newchord; + } + } + else if ( chari == ' ' ) + { + if( space >= 0) + { + for (var j = 0; j <= space; j++) + { + newline += ' '; + } + space = 0; + } + else + { + // Only balance negative spaces if one will be left remaining + if( nchar == ' ' ) + { + i++; + space += 1; + } + newline += ' '; + } + } + else + { + newline += chari; + } + } + return newline; +} + +function zj_transparray( transp ) +{ + var chords = + ["C","C#","D","D#","E","F","F#","G","G#","A","Bb","B" ]; + var newchords = []; + // Create array to map old chords to new ones + for (var i=0; i < 12; i++) + { + newchords[chords[i]] = chords[(i+transp+12)%12]; + } + newchords["Db"] = newchords["C#"]; + newchords["Eb"] = newchords["D#"]; + newchords["Gb"] = newchords["F#"]; + newchords["Ab"] = newchords["G#"]; + newchords["A#"] = newchords["Bb"]; + return newchords; +} + +function transpadd( fromkey, integer ) +{ + var chords = array_flip( [ "C","C#","D","D#","E","F","F#","G","G#","A","A#","B" ]); + chords["Db"] = chords["C#"]; + chords["Eb"] = chords["D#"]; + chords["Gb"] = chords["F#"]; + chords["Ab"] = chords["G#"]; + chords["Bb"] = chords["A#"]; + var ochords = [ "C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B" ]; + + return ochords[(parseInt(chords[fromkey]) + integer + 24)%12]; +} \ No newline at end of file diff --git a/page.php b/page.php new file mode 100644 index 0000000..c77b40e --- /dev/null +++ b/page.php @@ -0,0 +1,400 @@ +'; + $toc .= ''; + return $toc; +} + +function refToNum( $ref ) +{ + $number = 0; + $matches = array(); + if ( preg_match( "/(\w+).?\s*(\d+)?/", $ref, $matches )) + { + if ( isset($matches[1]) ) + { + switch (strtolower($matches[1])) { + case 'gen': $number+=100000;break; + case 'ex': $number +=200000;break; + case 'rev': + $number += 6600000; + break; + + default: + $number += 0; + break; + } + } + } + return $number; +} + +/** + * @brief load a portion of the text file inputfile.txt starting with + * "$number. " + * Where $number is an integer, or "X12", etc. + */ +function load_song( $number, $transp = 0 ) +{ + $handle = fopen("inputfile.txt", "r"); + if( ! $transp ) $transp = 0; + + $current_song = 0; + $something = 0; + $song = ''; + $textlines = '';///@< for suggesting songs + $allsongs = array(); + $suggestedSong = array(); + $songKeys = array(); + + if ($handle) {while (($line = fgets($handle)) !== false) + { + // Fix weird apostrophe errors + $line = stripslashes( + mb_convert_encoding( $line, "HTML-ENTITIES", "UTF-8" ) + ); + + // If we see a number, then that is what song we are on. + $matches = array(); + if ( preg_match("(^(X?\d+)\. )", $line, $matches) ) + { + $allsongs[$matches[1]] = $line; + $current_song = $matches[1]; + if( rand(0,100) < 5 ) + { + $suggestedSong[$current_song]['title'] = $line; + } + } + + if( preg_match( "/\{p?\d*\((.+m?)\)\}/", $line, $matches) ) + { + if ( isset( $suggestedSong[$current_song])) + { + $suggestedSong[$current_song]['key'] = $matches[1]; + } + if ( $current_song === $number ) + { + $songKeys[] = $matches[1]; + $songKey = $matches[1]; + } + } + + if ( $current_song === $number || $number == "all" ) + { + if( chordline($line) ) + { + if ( $transp != 0) + { + $line = z_transpose2( $line, $transp ); + } + $class = ! isset( $songKey ) ? "tabs chord$transp" : "tabs chord" . transpadd( $songKey, $transp ); + $line = str_replace( + array('{','}'), + array('{', "}" ), + $line ); + + $song .= "" . $line . ""; + } + else + { + $song .= $line; + $textlines .= $line; + } + } + }fclose($handle);} + else { + // error opening the file. + } + + return + renderEasyTransp( $transp, $number, $songKeys ) + . "
" . $song . "
\n" + . renderNavButtons( $number ) + . renderSS($suggestedSong, $songKeys, $transp); +} + +function renderEasyTransp( $transp, $num, $songKeys = array() ) +{ + $s = ''; + //up two semitones + $classT = 'btn col-xs-12'; + $nsongKey = 'Z'; + $data = ''; + $words = "Transposed up 2 semitones"; + if (isset ( $songKeys[0] ) ) + { + $classT = 'btn col-xs-6'; + $origKey = $songKeys[0]; + $presentKey = transpadd( $origKey, $transp ); + $data = "data-key='$presentKey' data-words='Current Key: '"; + $s .= "\t" + . "Current Key $presentKey\n"; + $nsongKey = transpadd( $presentKey, 2) ?: 'Z'; + $words = "Transposed up to "; + $data = "data-key='$nsongKey' data-words='$words'"; + $words .= $nsongKey; + } + $tt = $transp + 2; + $msg = + $s .= "\t" + . "$words\n"; + //favorite keys + return $s; +} + +function renderNavButtons( $number ) +{ + $navbuttons = ''; + if ( is_numeric($number) ) + { + $pnumber = $number - 1; + $nnumber = $number + 1; + $navbuttons .= "previous\n"; + $navbuttons .= "next\n"; + } + return $navbuttons; +} + +/** + * @brief Show the suggested songs as buttons with transpositions. + * @param $suggestedSong array of songs '25' => ['title'=> 'Majesty', 'key' => 'Bb' ] + * @param $songKeys Keys that you want to transpose these songs into. + */ +function renderSS( $suggestedSong = array(), $songKeys, $transp ) +{ + $ss = array(); + $bs = array();// "bad" songs. Songs without transpositions. + //shuffle( $suggestedSong ); + foreach ($suggestedSong as $songNum => $songarray) { + if( isset($songarray['key']) ) + { + $ok = trim($songarray['key'], 'm'); + $n = 2; + $bn = 12-($n* count($songKeys)); + $smn = count($songKeys) < 3 ? 3 : 12/count($songKeys); + $smbn = count($songKeys) < 3 ? 12 - count($songKeys) * $smn : 12; + $xsn = count($songKeys) == 1 ? 4 : 12/(count($songKeys) ?: 1); + $xsbn = count($songKeys) == 1? 8 : 12; + //$xtn = 12/count($songKeys); + //$xtbn = 12; + $s = "" + . "$songarray[title] ($songarray[key])\n"; + $classT = "btn col-md-$n col-sm-$smn col-xs-$xsn"; + foreach( $songKeys as $sK ) + { + $tt = difftransp( $sK, $songarray['key']); + if ( is_integer($tt) ); + { + $tt = ($tt + $transp + 12)%12; + $nsongKey = transpadd( $sK, $transp ); + + $s .= "\t" + . "Transposed to $nsongKey\n"; + } + } + $ss[] = $s; + } + else + { + $bs[] = "$songarray[title]\n"; + } + } + shuffle( $ss ); shuffle( $bs ); + return implode($ss) . implode($bs); +} + +/** + * @brief Determine whether or not this line contains chords. + */ +function chordline($line) +{ + $chords = + array( "C","C#","D","D#","E","F","F#","G","G#","A#","B",//"A", + "Db", "Eb", "Gb", "Bb",//"Ab", + "Cm", "Dm", "Fm", "Gm", "Bm", //"Em", "Am", + ); + $ambiguous = array( "Ab", "Em", "Am", "A" ); + $line = str_replace(array('/','7', "\n", '2', '4'), ' ', $line); + $tokens = array_filter(explode(' ', $line)); + + $badtokens = 0; + $ambtokens = 0; + foreach ($tokens as $token) { + if( in_array( substr($token, 0,2), $chords ) ) return TRUE; + else if ( in_array( substr( $token, 0,2), $ambiguous) ) $ambtokens++; + else if( $badtokens > 10 ) return FALSE; + else $badtokens++; + } + return $ambtokens >= $badtokens; +} + +function normalizechords($line, $space=TRUE) +{ + // Get rid of flats + $old = array( "Db", "Eb", "Gb", "Ab", "Bb"); + $new = array( "C#", "D#", "F#", "G#", "A#"); + $line = str_replace($old, $new, $line); + + // Uppercase letters A-G + $lc = array( "a", "b", "c", "d", "e", "f", "g"); + $uc = array( "A", "B", "C", "D", "E", "F", "G"); + $line = str_replace($lc, $uc, $line); + + if ( $space == TRUE ) + { + // Move space for nonsharp chords that didn't end in one + $line = preg_replace("( ([A-G])([^# ]))", "$1 $2", $line); + + // Trailing space at the end of the line + $line = str_replace("\n", " \n", $line ); + } + + return $line; +} + +function z_transpose2( $line, $transp ) +{ + $newchords = z_transparray( $transp ); + $newline = ''; + $space = 0; ///@< Spaces that need to be added or removed. + for($i = 0; $i < strlen($line); $i++) + { + $char = $line[$i]; + $nchar = isset($line[$i+1]) ? $line[$i+1] : ''; + $upchar = strtoupper($line[$i]); + $cval = ord($upchar); + // A-G + if( $cval <= 71 && $cval >=65 ) + { + // Exception for Cmaj7 + if( $upchar == 'A' && $nchar == 'j' ) + { + $newline .= $char; + } + else if( $nchar == 'b' || $nchar =='#') + { + $i++; //We have read an extra character now. + $newchord = $newchords[$upchar . $nchar]; + if( strlen($newchord) == 1 ) + { + // Need to insert an extra space. + $space += 1; + } + $newline .= $newchord; + } + else + { + $newchord = $newchords[$upchar]; + if( strlen($newchord) == 2 ) + { + // Need to remove an extra space. + $space -= 1; + } + $newline .= $newchord; + } + } + else if ( $char == ' ' ) + { + if( $space >= 0) + { + for ($j = 0; $j <= $space; $j++) + { + $newline .= ' '; + } + $space = 0; + } + else + { + // Only balance negative spaces if one will be left remaining + if( $nchar == ' ' ) + { + $i++; + $space += 1; + } + $newline .= ' '; + } + } + else + { + $newline .= $char; + } + } + return $newline; +} + +function z_transparray( $transp ) +{ + $chords = + array( "C","C#","D","D#","E","F","F#","G","G#","A","Bb","B" ); + $newchords = array(); + // Create array to map old chords to new ones + for ($i=0; $i < 12; $i++) + { + $newchords[$chords[$i]] = $chords[($i+$transp+12)%12]; + } + $newchords["Db"] = $newchords["C#"]; + $newchords["Eb"] = $newchords["D#"]; + $newchords["Gb"] = $newchords["F#"]; + $newchords["Ab"] = $newchords["G#"]; + $newchords["A#"] = $newchords["Bb"]; + return $newchords; +} + +function difftransp( $fromkey, $tokey ) +{ + $chords = array_flip(array( "C","C#","D","D#","E","F","F#","G","G#","A","A#","B" )); + $chords["Db"] = $chords["C#"]; + $chords["Eb"] = $chords["D#"]; + $chords["Gb"] = $chords["F#"]; + $chords["Ab"] = $chords["G#"]; + $chords["Bb"] = $chords["A#"]; + $fromkey = trim($fromkey, 'm'); + $tokey = trim($tokey, 'm'); + return $chords[$fromkey] - $chords[$tokey]; +} + +function transpadd( $fromkey, $integer ) +{ + $chords = array_flip(array( "C","C#","D","D#","E","F","F#","G","G#","A","A#","B" )); + $chords["Db"] = $chords["C#"]; + $chords["Eb"] = $chords["D#"]; + $chords["Gb"] = $chords["F#"]; + $chords["Ab"] = $chords["G#"]; + $chords["Bb"] = $chords["A#"]; + $ochords = array( "C","Db","D","Eb","E","F","Gb","G","Ab","A","Bb","B" ); + $fromkey = trim($fromkey, 'm'); + return $ochords[($chords[$fromkey] + $integer)%12]; +} diff --git a/toc-filter.js b/toc-filter.js new file mode 100644 index 0000000..08afa2d --- /dev/null +++ b/toc-filter.js @@ -0,0 +1,18 @@ +$(function(){ + $("#toc-filter").bind("change paste keyup", toc_filter); +}); + +function toc_filter( event ) +{ + var val = $(this).val().toLowerCase(); + $("#toc li").each(function(){ + if($(this).text().toLowerCase().indexOf(val) == -1) + { + $(this).hide(); + } + else + { + $(this).show(); + } + }); +} \ No newline at end of file -- cgit 1.4.1