Added "!" trick to give hints to the key detection algorithm. It's all Chris Tomlin's fault.
authorDan Fuhry <dan@enanocms.org>
Sun, 02 Sep 2012 23:48:00 -0400
changeset 5 c36fbf04faac
parent 4 bb3789db954a
child 6 07ceb3e35e25
Added "!" trick to give hints to the key detection algorithm. It's all Chris Tomlin's fault.
Halftone.php
README
--- a/Halftone.php	Tue May 08 01:38:29 2012 -0400
+++ b/Halftone.php	Sun Sep 02 23:48:00 2012 -0400
@@ -87,6 +87,12 @@
 	{
 		// discard bass note
 		list($chord) = explode('/', $chord);
+		// skip chord if it has a "!"
+		if ( $chord{0} == '!' )
+		{
+			continue;
+		}
+		
 		$match = array();
 		preg_match('/((?:[Mm]?7?|2|5|6|add9|sus4|[Mm]aj[79]|dim|aug)?)$/', $chord, $match);
 		if ( !empty($match[1]) )
@@ -223,7 +229,7 @@
 	{
 		$chord = $chord{0} . '&sharp;' . substr($chord, 2);
 	}
-	return $chord;
+	return ltrim($chord, '!');
 }
 
 function transpose_chord($chord, $increment, $accidental = false)
@@ -236,6 +242,12 @@
 		return transpose_chord($upper, $increment, $accidental) . '/' . transpose_chord($lower, $increment, $accidental);
 	}
 	// shave off any wacky things we're doing to the chord (minor, seventh, etc.)
+	$prechord = '';
+	if ( $chord{0} == '!' )
+	{
+		$prechord = '!';
+		$chord = substr($chord, 1);
+	}
 	preg_match('/((?:[Mm]?7?|2|5|6|add9|sus4|[Mm]aj[79]|dim|aug)?)$/', $chord, $match);
 	// find base chord
 	if ( !empty($match[1]) )
@@ -255,7 +267,7 @@
 	if ( !$kname )
 		// again, should never happen
 		return "[TRANSPOSITION FAILED: " . $chord . $match[1] . " + $increment (-&gt;$key)]";
-	$result = $kname . $match[1];
+	$result = $prechord . $kname . $match[1];
 	// echo "$chord{$match[1]} + $increment = $result<br />";
 	return $result;
 }
@@ -362,14 +374,13 @@
 	foreach ( explode("\n", $inner) as $line )
 	{
 		$chordline = false;
-		$chords_regex = '/(\((?:[A-G][#b]?(?:[Mm]?7?|2|5|6|add9|sus4|[Mm]aj[79]|dim|aug)?(?:\/[A-G][#b]?)?)\))/';
+		$chords_regex = '/(\((?:\!?[A-G][#b]?(?:[Mm]?7?|2|5|6|add9|sus4|[Mm]aj[79]|dim|aug)?(?:\/[A-G][#b]?)?)\))/';
 		$line_split = preg_split($chords_regex, $line, -1, PREG_SPLIT_DELIM_CAPTURE);
 		$line_pattern = '';
 		if ( preg_match_all($chords_regex, $line, $chords) )
 		{
 			// this is a line with lyrics + chords
-			// echo out the line, adding spans around chords. here is where we also do transposition
-			// (if requested) and 
+			// echo out the line, adding spans around chords.
 			$line_final = array();
 			$last_was_chord = false;
 			foreach ( $line_split as $entry )
--- a/README	Tue May 08 01:38:29 2012 -0400
+++ b/README	Sun Sep 02 23:48:00 2012 -0400
@@ -5,9 +5,10 @@
 Halftone markup example:
 
 <halftone title="Don't Stop Believing">
-Intro: (E) (B) (C#m) (A) (E) (B) (G#m) (A)
+= Intro =
+(E) (B) (C#m) (A) (E) (B) (G#m) (A)
 
-Verse 1:
+= Verse 1 =
 (E)Just a (B)small town girl
 (C#m)Living in a (A)lonely world,
 (E)She took the (B)midnight train going
@@ -24,4 +25,22 @@
 if you put chords so close to each other. An example would be using
 "(G#m)any(A)where" in the sample verse above - depending on your theme/font
 G#m would be directly adjacent to A (confusing) or A would even overlap. So
-be sure to space out your lyrics accordingly.
+be sure to space out your lyrics accordingly. You can use HTML entities (like
+"&nbsp;" or so) to space things out.
+
+You may also find it beneficial, if the key detection algorithm goofs up, to
+prepend a "!" to the beginning of a chord expression which does not fit into
+the consonant chords for a given key. Consider the following passage, taken
+from a song in the key of A (this is the pre-chorus):
+
+	(E)And together we (B)sing (D)
+	Everyone (B)sing (D)
+
+The key detection actually caused Halftone to think this song was in D. You can
+rewrite this as,
+
+	(E)And together we (!B)sing (D)
+	Everyone (!B)sing (D)
+	
+...which causes the key detection algorithm to ignore that random B, which is
+considered to be dissonant to the key of A.