Backend for songs.zachdecook.com
Diffstat (limited to 'page.php')
-rw-r--r--page.php400
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];
+}