Halftone.php
changeset 4 bb3789db954a
parent 3 c3150cee8dd9
child 5 c36fbf04faac
equal deleted inserted replaced
3:c3150cee8dd9 4:bb3789db954a
    77 function detect_key($chord_list)
    77 function detect_key($chord_list)
    78 {
    78 {
    79 	$majors = array();
    79 	$majors = array();
    80 	$minors = array();
    80 	$minors = array();
    81 	$sharp_or_flat = ACC_SHARP;
    81 	$sharp_or_flat = ACC_SHARP;
       
    82 	// sus4 chords are also a great indicator since they are almost always
       
    83 	// used exclusively on the fifth
       
    84 	$have_sus4 = false;
    82 	// index which chords are used in the song
    85 	// index which chords are used in the song
    83 	foreach ( $chord_list as $chord )
    86 	foreach ( $chord_list as $chord )
    84 	{
    87 	{
    85 		// discard bass note
    88 		// discard bass note
    86 		list($chord) = explode('/', $chord);
    89 		list($chord) = explode('/', $chord);
    87 		$match = array();
    90 		$match = array();
    88 		preg_match('/((?:m?7?|2|add9|sus4|[Mm]aj[79])?)$/', $chord, $match);
    91 		preg_match('/((?:[Mm]?7?|2|5|6|add9|sus4|[Mm]aj[79]|dim|aug)?)$/', $chord, $match);
    89 		if ( !empty($match[1]) )
    92 		if ( !empty($match[1]) )
       
    93 		{
    90 			$chord = str_replace_once($match[1], '', $chord);
    94 			$chord = str_replace_once($match[1], '', $chord);
       
    95 			if ( $match[1] === 'sus4' )
       
    96 				$have_sus4 = $chord;
       
    97 		}
    91 		$sharp_or_flat = get_sharp($chord) == $chord ? ACC_SHARP : ACC_FLAT;
    98 		$sharp_or_flat = get_sharp($chord) == $chord ? ACC_SHARP : ACC_FLAT;
    92 		$chord = get_sharp($chord);
    99 		$chord = get_sharp($chord);
    93 		if ( $match[1] == 'm' || $match[1] == 'm7' )
   100 		if ( $match[1] == 'm' || $match[1] == 'm7' )
    94 		{
   101 		{
    95 			// minor chord
   102 			// minor chord
   103 			if ( !isset($majors[$chord]) )
   110 			if ( !isset($majors[$chord]) )
   104 				$majors[$chord] = 0;
   111 				$majors[$chord] = 0;
   105 			$majors[$chord]++;
   112 			$majors[$chord]++;
   106 		}
   113 		}
   107 	}
   114 	}
       
   115 	/*
       
   116 	// remove very low scorers
       
   117 	foreach ( $majors as $key => $count )
       
   118 	{
       
   119 		if ( $count < 1 )
       
   120 			unset($majors[$key]);
       
   121 	}
       
   122 	*/
   108 	// now we go through each of the detected major chords, calculate its consonants, and determine how many of its consonants are present in the song.
   123 	// now we go through each of the detected major chords, calculate its consonants, and determine how many of its consonants are present in the song.
   109 	$scores = array();
   124 	$scores = array();
   110 	foreach ( $majors as $key => $count )
   125 	foreach ( $majors as $key => $count )
   111 	{
   126 	{
   112 		$scores[$key] = 0;
   127 		$scores[$key] = 0;
   113 		$consonants = get_consonants(name_to_key($key));
   128 		$consonants = get_consonants(name_to_key($key));
   114 		if ( isset($majors[key_to_name($consonants['fourth'])]) )
   129 		if ( isset($majors[key_to_name($consonants['fourth'])]) )
   115 			$scores[$key] += 2;
   130 			$scores[$key] += 2;
   116 		if ( isset($majors[key_to_name($consonants['fifth'])]) )
   131 		if ( isset($majors[key_to_name($consonants['fifth'])]) )
   117 			$scores[$key] += 2;
   132 			$scores[$key] += $have_sus4 === key_to_name($consonants['fifth']) ? 4 : 2;
   118 		if ( isset($majors[key_to_name($consonants['minors'][0])]) )
   133 		if ( isset($majors[key_to_name($consonants['minors'][0])]) )
   119 			$scores[$key] += 1;
   134 			$scores[$key] += 1;
   120 		if ( isset($majors[key_to_name($consonants['minors'][1])]) )
   135 		if ( isset($majors[key_to_name($consonants['minors'][1])]) )
   121 			$scores[$key] += 2;
   136 			$scores[$key] += 2;
   122 		if ( isset($majors[key_to_name($consonants['minors'][2])]) )
   137 		if ( isset($majors[key_to_name($consonants['minors'][2])]) )
   219 	{
   234 	{
   220 		list($upper, $lower) = explode('/', $chord);
   235 		list($upper, $lower) = explode('/', $chord);
   221 		return transpose_chord($upper, $increment, $accidental) . '/' . transpose_chord($lower, $increment, $accidental);
   236 		return transpose_chord($upper, $increment, $accidental) . '/' . transpose_chord($lower, $increment, $accidental);
   222 	}
   237 	}
   223 	// shave off any wacky things we're doing to the chord (minor, seventh, etc.)
   238 	// shave off any wacky things we're doing to the chord (minor, seventh, etc.)
   224 	preg_match('/((?:m?7?|2|add9|sus4|[Mm]aj[79])?)$/', $chord, $match);
   239 	preg_match('/((?:[Mm]?7?|2|5|6|add9|sus4|[Mm]aj[79]|dim|aug)?)$/', $chord, $match);
   225 	// find base chord
   240 	// find base chord
   226 	if ( !empty($match[1]) )
   241 	if ( !empty($match[1]) )
   227 		$chord = str_replace($match[1], '', $chord);
   242 		$chord = str_replace($match[1], '', $chord);
   228 	// what's our accidental? allow it to be specified, and autodetect if it isn't
   243 	// what's our accidental? allow it to be specified, and autodetect if it isn't
   229 	if ( !$accidental )
   244 	if ( !$accidental )
   266 				}
   281 				}
   267 				span.halftone-chord {
   282 				span.halftone-chord {
   268 					position: absolute;
   283 					position: absolute;
   269 					top: 0pt;
   284 					top: 0pt;
   270 					color: rgb(27, 104, 184);
   285 					color: rgb(27, 104, 184);
       
   286 				}
       
   287 				span.halftone-line.labeled span.halftone-chord {
       
   288 					position: static;
   271 				}
   289 				}
   272 				span.halftone-chord.sequential {
   290 				span.halftone-chord.sequential {
   273 					padding-left: 20pt;
   291 					padding-left: 20pt;
   274 				}
   292 				}
   275 				div.halftone-key-select {
   293 				div.halftone-key-select {
   342 	$transpose = isset($_GET['transpose']) ? intval($_GET['transpose']) : $transpose;
   360 	$transpose = isset($_GET['transpose']) ? intval($_GET['transpose']) : $transpose;
   343 	$transpose_accidental = $inkey ? $accidentals[$inkey] : false;
   361 	$transpose_accidental = $inkey ? $accidentals[$inkey] : false;
   344 	foreach ( explode("\n", $inner) as $line )
   362 	foreach ( explode("\n", $inner) as $line )
   345 	{
   363 	{
   346 		$chordline = false;
   364 		$chordline = false;
   347 		$chords_regex = '/(\((?:[A-G][#b]?(?:m?7?|2|add9|sus4|[Mm]aj[79])?(?:\/[A-G][#b]?)?)\))/';
   365 		$chords_regex = '/(\((?:[A-G][#b]?(?:[Mm]?7?|2|5|6|add9|sus4|[Mm]aj[79]|dim|aug)?(?:\/[A-G][#b]?)?)\))/';
   348 		$line_split = preg_split($chords_regex, $line, -1, PREG_SPLIT_DELIM_CAPTURE);
   366 		$line_split = preg_split($chords_regex, $line, -1, PREG_SPLIT_DELIM_CAPTURE);
       
   367 		$line_pattern = '';
   349 		if ( preg_match_all($chords_regex, $line, $chords) )
   368 		if ( preg_match_all($chords_regex, $line, $chords) )
   350 		{
   369 		{
   351 			// this is a line with lyrics + chords
   370 			// this is a line with lyrics + chords
   352 			// echo out the line, adding spans around chords. here is where we also do transposition
   371 			// echo out the line, adding spans around chords. here is where we also do transposition
   353 			// (if requested) and 
   372 			// (if requested) and 
   368 					else
   387 					else
   369 					{
   388 					{
   370 						$line_final[] = '<span class="halftone-chord">' . prettify_accidentals($chord_list[] = transpose_chord(trim($entry, '()'), $transpose, $transpose_accidental)) . '</span>';
   389 						$line_final[] = '<span class="halftone-chord">' . prettify_accidentals($chord_list[] = transpose_chord(trim($entry, '()'), $transpose, $transpose_accidental)) . '</span>';
   371 					}
   390 					}
   372 					$last_was_chord = true;
   391 					$last_was_chord = true;
       
   392 					$line_pattern .= 'c';
   373 				}
   393 				}
   374 				else
   394 				else
   375 				{
   395 				{
   376 					if ( trim($entry) != "" )
   396 					if ( trim($entry) != "" )
   377 					{
   397 					{
   378 						$last_was_chord = false;
   398 						$last_was_chord = false;
   379 						$line_final[] = $entry;
   399 						$line_final[] = $entry;
       
   400 						$line_pattern .= 'w';
   380 					}
   401 					}
   381 				}
   402 				}
   382 			}
   403 			}
   383 			$song .= '<span class="halftone-line">' . implode("", $line_final) . "</span>\n";
   404 			$class_append = preg_match('/^w?c+$/', $line_pattern) ? ' labeled' : '';
       
   405 			$song .= '<span class="halftone-line' . $class_append . '">' . implode("", $line_final) . "</span>\n";
   384 		}
   406 		}
   385 		else if ( preg_match('/^=\s*(.+?)\s*=$/', $line, $match) )
   407 		else if ( preg_match('/^=\s*(.+?)\s*=$/', $line, $match) )
   386 		{
   408 		{
   387 			$song .= "</div>\n<div class=\"section\">\n== {$match[1]} ==\n\n";
   409 			$song .= "</div>\n<div class=\"section\">\n== {$match[1]} ==\n\n";
   388 		} 
   410 		}