Backend for songs.zachdecook.com
* Tabs Project: Initial Commit
| -rw-r--r-- | .gitmodules | 3 | ||||
| m--------- | ccharter | 0 | ||||
| -rw-r--r-- | functions.js | 17 | ||||
| -rw-r--r-- | index.css | 219 | ||||
| -rw-r--r-- | index.less | 131 | ||||
| -rwxr-xr-x | index.php | 111 | ||||
| -rw-r--r-- | jsonly.js | 110 | ||||
| -rw-r--r-- | page.js | 111 | ||||
| -rw-r--r-- | page.php | 400 | ||||
| -rw-r--r-- | toc-filter.js | 18 |
10 files changed, 1120 insertions, 0 deletions
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 +Subproject dffd1beac4f5fa588efd324924c9e55a22e7d57 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 @@ +<!-- +index.php contains the main html used for creating the page. +--> +<!DOCTYPE html> +<html> + <head> + <!-- Latest compiled and minified CSS --> + <!--<link rel="stylesheet" href="../shared/bootstrap-3.3.6/css/bootstrap.min.css" + integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" + crossorigin="anonymous"> --> + <link rel="stylesheet" + href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> + + <link rel="stylesheet" href="index.css" > + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta name="viewport" content="width=device-width, initial-scale=.65"> + <title>Choruses and Hymns</title> + </head> + + <p><body> + +<!-- Light yellow box around page contents --> +<div class="col-lg-offset-2 col-lg-8 col-md-offset-1 col-md-10 col-sm-12 col-xs-12 bg-success"> + + <div class = "col-xs-6 col-xs-offset-0 "> + <h3>Browse Songs</h3> + <a href="?song=0">Table of contents</a> + <form> + <input name='song' type='number' value='<?php echo isset($_GET['song']) ? $_GET['song'] : '' ?>' + min='0' max='169' + /> + <input type="submit" value="Jump to song" /> + </form> + </div> + + <div class = "col-xs-6 col-xs-offset-0 "> + <div id="chordarea"> + <canvas id='chordy' width="100" height="100"/> + </div> + <i>Experimental: Click on a chord to view guitar tablature</i> + <div id="messages"></div> + </div> + + <div class = "col-sm-0 col-md-2 col-lg-2"><p></p></div> + <div class = "col-lg-12 col-md-12 col-sm-12 col-xs-12"><p></p></div> + + <br></br> +</div> +<div class = "text-center col-lg-offset-2 col-lg-8 col-md-offset-1 col-md-10 col-sm-12 col-xs-12 bg-info "> + <form> + <?php $transp = isset( $_GET['transp']) ? (int)$_GET['transp'] : 0 ?> + <select name="transp" id="transp" + value = "<?php echo $transp;?>" + > + <?php + for ($i=-6; $i < 12; $i++) { + if (($transp + 24)%12 == $i) $selected = 'selected'; + else $selected = ''; + //$dir = ($i >= 0 ? "up" : "down" ); + $dir = "transpose"; + echo "<option value='$i' $selected>$dir $i semitones</option>"; + } + ?> + </select> + <noscript> + <button>Transpose</button> + <?php + //$val1 = ($_GET['transp'] - 1 + 12)%12; + $val2 = ($transp + 2)%12; + //$val3 = ($_GET['transp'] + 3)%12; + //echo "<input type='submit' value='$val1' name='transp'>"; + echo "<input type='submit' value='$val2' name='transp'>"; + //echo "<input type='submit' value='$val3' name='transp'>"; + ?> + </noscript> + </form> +</div> + + +<div class="col-lg-offset-2 col-lg-8 col-md-offset-1 col-md-10 col-sm-12 col-xs-12 bg-info"> + +<?php +include 'page.php'; + + $song_number = isset( $_GET['song'] ) ? $_GET['song'] : ''; + if( ! $song_number ) + { + echo toc(); + } + else + { + echo load_song( $song_number, ($transp + 24)%12 ); + } + +?> +<br/><br><br> +All songs are owned by their respective copyright holders. No infringement intended. +</div> + +<!-- <script type="text/javascript" src="../scripts/jqm.js"></script> --> +<script src="https://code.jquery.com/jquery-1.12.4.min.js" +integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" +crossorigin="anonymous"></script> +<script src="toc-filter.js"></script> +<script type="text/javascript" src="functions.js"></script> +<script type="text/javascript" src="page.js"></script> +<script type="text/javascript" src="jsonly.js"></script> +<script type="text/javascript" src="ccharter/scripts/ccharter.js"></script> +<script type="text/javascript" src="data/chords.js"></script> + </body> +</html> 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 = "<img class='myimage' src='chordimages/" + chord + ".png'/>"; + $("#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 @@ -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 @@ +<?php +/** + * @author: Zach DeCook + * Facilitates loading of tablature and transposition. + * Copyright (C) 2017 Zach DeCook + */ + +/** + * @brief Go through the file inputfile.txt and return each song with a link to it. + */ +function toc(){ + $toc = ''; + $toc .= '<form><input type="text" id="toc-filter" placeholder="Filter by song title"/></form>'; + $toc .= '<ul id="toc">'; + $handle = fopen("inputfile.txt", "r"); + if ( $handle ){while (($line = fgets($handle)) !== false) + { + // Fix weird apostrophe errors + $line = stripslashes( + mb_convert_encoding( $line, "HTML-ENTITIES", "UTF-8" ) + ); + $matches = array(); + if( preg_match("(^(X?\d+)\. )", $line, $matches)) + { + $toc .= "<li><a href=?song=$matches[1]>" . $line . "</a>"; + } + if( preg_match("/^{Verse: ?(.*)}/i", $line, $matches)) $toc .= " ($matches[1])"; + if( preg_match("(^{p\d+(\(\S\S?\S?\))?})", $line)) $toc .= " (Reviewed)"; + if( preg_match( "/\{p?\d*\((.+m?)\)\}/", $line, $matches) ) $toc .= " ($matches[1])"; + + }fclose($handle);} + else + { + //Error + } + $toc .= '</ul>'; + 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('</b>{', "}<b class='$class'>" ), + $line ); + + $song .= "<b class='$class'>" . $line . "</b>"; + } + else + { + $song .= $line; + $textlines .= $line; + } + } + }fclose($handle);} + else { + // error opening the file. + } + + return + renderEasyTransp( $transp, $number, $songKeys ) + . "<pre>" . $song . "</pre>\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<a href='?song=$num&transp=$transp' class='$classT btn-$presentKey' $data>" + . "Current Key $presentKey</a>\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<a href='?song=$num&transp=$tt' class='$classT btn-$nsongKey' $data>" + . "$words</a>\n"; + //favorite keys + return $s; +} + +function renderNavButtons( $number ) +{ + $navbuttons = ''; + if ( is_numeric($number) ) + { + $pnumber = $number - 1; + $nnumber = $number + 1; + $navbuttons .= "<a href='?song=$pnumber' class='btn btn-Z col-xs-6'>previous</a>\n"; + $navbuttons .= "<a href='?song=$nnumber' class='btn btn-Z col-xs-6'>next</a>\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 = "<a href='?song=$songNum' class='btn btn-$ok col-md-$bn col-sm-$smbn col-xs-$xsbn'>" + . "$songarray[title] ($songarray[key])</a>\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<a href='?song=$songNum&transp=$tt' class='$classT btn-$nsongKey' data-key='$nsongKey' " + . "data-words='Transposed to '>" + . "Transposed to $nsongKey</a>\n"; + } + } + $ss[] = $s; + } + else + { + $bs[] = "<a href='?song=$songNum' class='btn btn-Z col-xs-12'>$songarray[title]</a>\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 |