2011-10-16

Quite often I find myself over at http://thesession.org checking out old traditional tunes. The site offers the tunes as sheet music and ABC Notation. While I certainly appreciate having ready access to the tunes, I find that, more often than not, I need to copy the ABC notation into a text file, convert the text file into a [lilypond[(http://lilypond.org) file, transpose the lilypond file to the G Major scale, and then finally add some code that will display the tune as banjo tabs. Oh man, did you catch all of that? There has to be an easier way to do this.....

Oh, there is...

For the most part, the process is just a series of text manipulations which can be accomplished in just about any programming language. Since I am currently on a Ruby kick, I figured I would just hammer out a quick script to automate the process of retrieving ABC notation from a given page and converting the results into something more usable.

Enter the Ruby

#!/usr/bin/env ruby

require 'optparse'
require 'open-uri'
require 'rexml/document'
require 'iconv'

def sanitizestring )
  #replace non alpha-numerics with _
  string string.gsub(/[^A-z0-9_]/,'_')
  return string.downcase
end

def errorstring )
  puts "**** ERROR ****"
  puts string
  exit
end

option = {}
OptionParser.new do |opts|
  opts.banner "Usage: sessionconvert [options] [thesession.org_URL]"
  
  opts.on("-b""--banjo""add banjo tabulature"do |v|
    option[:banjo] = v
  end
  
  opts.on("-l""--lilypond""compile with lilypond"do |v|
    option[:lilypond] = v
  end
  
end.parse!

url =  ARGV[0]
# was a url supplied?
unless url
  error "you must supply a thesession.org url"
end

begin
  text open(url).read
rescue
  error "Failed to read #{url}"
end



begin
  #watch out for sneaky 
  ic Iconv.new('UTF-8//IGNORE''UTF-8')
  valid_string ic.iconv(text)
  doc REXML::Document.new valid_string
rescue
  error "Failed to parse #{url}"
end

root doc.root
root.elements["body/div[@id='abc']/div[@class='box']/p"].to_s
abc p.gsub(/<.*>/,'')

#get the title
/T: (?<title>.*)/.matchabc )
title m['title']
#get the key
/K: (?<key>.*)/.matchabc )
key m['key']

#sanitize the title, we will use this a bunch
sanitized_title sanitize(title)
#what will the filenames be?
filename_abc sanitized_title+".abc"

open(filename_abc,'w')
f.write(abc)
f.close

begin
  `abc2ly #{filename_abc}`
rescue
  error "abc2ly is not installed"
end

#what will the lilypond file be?
filename_ly sanitized_title+".ly"

if option[:banjo]
  #what is the key we are transposing from
  t_key key[0].downcase
  banjer_bit "\\transpose  #{t_keyg,
    \\context TabStaff = \"banjer\"{
    \\set TabStaff.stringTunings = #banjo-open-g-tuning
    \\set Staff.instrumentName = #\"Banjo\"
    \\context TabVoice = \"banjer\" { \\tabFullNotation \\stemDown \\voicedefault }
  }"

  text File::read(filename_ly)
  #substitute the banjer stuff
  text text.gsub(/<<.*>>/m"<<\n #{banjer_bit}\n\t>>")
  #make a new lilypond file
  filename_ly sanitized_title+"-banjo.ly"
  #write the new text to file
  open(filename_ly,'w')
  f.write(text)
  f.close
  
end

#did the user request compiling 
begin
  `lilypond #{filename_ly}if option[:lilypond]
rescue
  error "lilypond is not installed"
end

If you have problems copying the code, please see http://hoof.jezra.net/snip/nQ

Usage

Since I don't always want to convert a tune to banjo tabs (some tunes are better on the concertina), a flag (-b) needs to be included with the arguments to specify that the tune should be converted to banjo tabs. Similarly, including the -l flag with compile the final lilypond file into a pdf of sheet music or tabs.

For example: The tune Rakes of Mallow is found at http://www.thesession.org/tunes/display/85 and to convert the tune to banjo tabs and compile to a PDF the following command would be used.

./sessioncovert.rb -bl http://www.thesession.org/tunes/display/85

This is what the final PDF looks like. Damn that's nice!

...and this is me butchering the tune on my banjo. Damn, I need more practice.

Awesome! Now quit reading, and go butcher a tune on the instrument of your choice.

Comments
Name:
not required
Email:
not required (will not be displayed)
Website:
not required (will link your name to your site)
Comment:
required
Please do not post HTML code or bbcode unless you want it to show up as code in your post. (or if you are a blog spammer, in which case, you probably aren't reading this anyway).
Prove you are human by solving a math problem! I'm sorry, but due to an increase of blog spam, I've had to implement a CAPTCHA.
Problem:
6 plus 7
Answer:
required
subscribe
 
2016
2015
2014
2013
2012
2011
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008