I often struggled to keep chords for songs I played in a handy place. For a couple of years I have been maintaining chords in a Google Doc. Given the forgetful person that I'm, storing all the chords in one place has come as a blessing. Having all the chords in one place has helped me to be more organized about my music. It has helped me collaborate better with other musicians.
However, using Google Docs for organizing chords has not since scaled as I added more and more songs. Besides, I was maintaining all the chords in one file. Maybe having individual files would have helped the cause but it was nowhere close to what for example UltimateGuitar provides.
I have since migrated all the chords from the google doc onto my personal website where I write song chords in plain text format (in org-mode files) and using Hugo's magic shortcodes to detect chords and present them in a way such that it is easy to follow.
This has worked wonders for me and this post is meant to give a high
level idea of how you can use Hugo
shortcodes, to organize and
present chords for your songs!
Hugo Short Code for Chords
I defined a new short code called chords
to define the section
of a post where song chords are found. What this shortcodee does is
that it recognizes all the chords in its content using the
following regular expression:
[A-G][b#]?((b|maj|add|m|sus|dim|aug)*[0-9]*)*[^\\w]
Marking Chords in Markdown
I defined a new <chords>
tag (note that this is not a HTML tag) as a way to
indicate that all the content following this tag should be rendered as
chords. This is ugly but it works for my usecase. Chords marker makes Liquid
templating language use a <pre>
with a CSS class for all the content that
follows. As you will see in the following section, it's critical that you
use monospace font for rendering this =<pre>=formatted text in order to maintain
the mapping of where chords change according to lyrics.
<chords>
I got my first real six-string, Bought it at the five-and-dime
The next step is to write chords for the songs. I first place chords
just above the lyrics where the chords change and then annotate (and
differentiate) chords (from lyrics) by placing them in square
brackets. Square brackets encountered after <chords>
tag tell
Liquid templating language that these are chords and should have a
special css style assigned to it.
<chords>
[D A]
I got my first real six-string, Bought it at the five-and-dime
Song sections (such as chorus, verse, prechorus) in the song use
<ctag></ctag>
tag.
[D A]
Jimmy quit, Joey got married, I shoulda known we'd never get far
<ctag>Chorus</ctag>
[Bm A D G]
Oh, when I look back now, That summer seemed to last forever
Liquid Templating to Render Chords
I then have following code in my layout file that renders chords.
Note: In order to not confuse Liquid Templating used for this post, I
have left spaces between {
, }
and %
characters.
{ % if page.categories contains "chords" % }
{ % assign var content_split = content | split:"<chords>" % }
{ { content_split[0] } }
<pre class='highlight'>{ { content_split[1] |
replace: "[", "<span class='chords'>" |
replace: "]", "</span>" |
replace: "<chords>", "<pre class='highlight'>" |
replace: "<ctag>", "<span class='ctag'>" |
replace: "</ctag>", "</span>" } }</pre>
{ % else % }
{ { content } }
{ % endif % }
JS Tricks
I also have added a few Javascript tricks to implement some interesting
functions such as Transpose
and Auto-scroll
which I first found on
UltimateGuitar. These functions come very handy! For those who are interested
here's how the JS code for each look like. Just place these in the appropriate
location (right before the { { content_split[0] } }
line) in the above
template.
Auto-scroll
window.scroll_state = 0;
function autoscroll() {
if (window.scroll_state == 0) {
scroll = setInterval(function() { window.scrollBy(0, 1);
console.log('start');}, 100);
window.scroll_state = 1;
} else {
window.scroll_state = 0;
clearInterval(scroll);
console.log('stop');
}
}
<button onclick="autoscroll();">Autoscroll</button>
Transpose
function transpose(direction) {
var ele = document.getElementsByClassName('chords');
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
// C,C#, D,D#, E, F,F#, G,G#, A,A#, B
for(var i=0;i<ele.length;i++) {
var text = ele[i].textContent;
if (direction == 1) {
text = text.replace(/C/g, "##");
text = text.replace(/D/g, "####");
text = text.replace(/E/g, "######");
text = text.replace(/F/g, "#######");
text = text.replace(/G/g, "#########");
text = text.replace(/A/g, "###########");
text = text.replace(/B/g, "#");
} else {
text = text.replace(/C/g, "############");
text = text.replace(/D/g, "##");
text = text.replace(/E/g, "####");
text = text.replace(/F/g, "#####");
text = text.replace(/G/g, "#######");
text = text.replace(/A/g, "#########");
text = text.replace(/B/g, "###########");
}
text = text.replace(/#############/g, "C");
text = text.replace(/############/g, "B");
text = text.replace(/###########/g, "AA");
text = text.replace(/##########/g, "A");
text = text.replace(/#########/g, "GG");
text = text.replace(/########/g, "G");
text = text.replace(/#######/g, "FF");
text = text.replace(/######/g, "F");
text = text.replace(/#####/g, "E");
text = text.replace(/####/g, "DD");
text = text.replace(/###/g, "D");
text = text.replace(/##/g, "CC");
text = text.replace(/#/g, "C");
text = text.replace(/AA/g, "A#");
text = text.replace(/GG/g, "G#");
text = text.replace(/FF/g, "F#");
text = text.replace(/DD/g, "D#");
text = text.replace(/CC/g, "C#");
ele[i].textContent = text;
}
}
<button onclick="transpose(1);">+1</button>
<button onclick="transpose(0);">-1</button>
Have fun adding chords to your blog!