Thursday, January 14, 2010

Putting it together

Just to get more dramatic results, here's script to check if an ABC tune can be played on a one-row button accordion in G. It's pretty easy to put together given what we've got so far:
use v6;

BEGIN { push @*INC, "lib" }
use ABC;

my @matches = $*IN.slurp.comb(m/ <ABC::tune> /, :match);

my %dg_notes = {
'g' => 1,
'a' => 1,
'b' => 1,
'c' => 1,
'd' => 1,
'e' => 1,
'^f' => 1
}

for @matches {
my %header = header_hash(.<ABC::tune><header>);
say %header<T> ~ ":";

my @notes = gather for .<ABC::tune><music><line_of_music> -> $line
{
for $line<bar> -> $bar
{
for $bar<element>
{
when .<broken_rhythm> { take .<broken_rhythm><note>[0]; take .<broken_rhythm><note>[1]; }
when .<note> { take .<note>; }
}
}
}

my %key_signature = key_signature(%header<K>);

my @trouble = @notes.map({apply_key_signature(%key_signature, .<pitch>)}).grep({!%dg_notes.exists(lc($_))});
say @trouble.perl;
}


Basically, we set up @matches with all the tunes in the file, and %dg_notes with all the notes that can be played (though it's actually just the key of G for now). Then for each tune, we loop through and collect all the notes, factored into the appropriate key signature. Then we just grep against the notes that are allowed to make a list of the notes not present on a G accordion. Here are the results on my sample file:


Cuckold Come Out o' the Amrey:
["^c", "^c", "^c", "^c", "^c", "^c", "^c", "^c", "=f", "^c", "^c", "^c", "^c"]
Elsie Marley:
["=F", "=f"]
Peacock Followed the Hen. JWDM.07:
[]


So in this case, "Cuckold" has a bunch of c-sharps and an f-natural, "Elsie Marley" has a couple of f-naturals, and "Peacock" is solidly playable on a G accordion.

While this approach has been fun, I think it's time to dig in use Perl 6 grammar actions to build a smarter data structure for ABC tunes. Should be exciting...

2 comments: