Backend for songs.zachdecook.com
Diffstat (limited to 'page.php')
| -rw-r--r-- | page.php | 400 |
1 files changed, 400 insertions, 0 deletions
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]; +} |