#!/home/jmc/bin/perl # #=head1 FILE # ABC.pm # #=head1 NAME # ABC - module for handling music in abc notation. # #=head1 SYNOPSIS # use ABC; # $t = new ABC() # #=head1 DESCRIPTION # #=head1 BUGS # #=head1 SEE ALSO # #=head1 AUTHOR #John Chambers # #=cut #package ABC; use Carp; # A = qw(Exporter DynaLoader); # use strict; my $d = 1; my $o; #use ABC_Token; sub ABC_new { my $x = shift; # my $class = ref($x) || $x; my $self = {}; local($fld, $val); # bless $self; $self->{src} = ''; # List for the tune's abc source. $self->{T} = []; # T: header lines. $self->{tok} = []; # Token list. while (($fld = shift) && ($val = shift)) { print STDERR "ABC_new: fld=\"$fld\" val=\"$val\"\n" if $d>4; $self->{$fld} = $val; } $d = $main::V; return ($o = $self); } sub URL { my $x = shift; if (@_) {$x->{URL} = shift} return $x->{URL}; } $ABC_Key = 'C'; $ABC_Length = '1/8'; $ABC_Meter = '4/4'; # $obj->hdr('T',1,'First Title') # $obj->hdr('T',2,'Second Title') sub ABC_hdr { local($x,$h,$n,$v) = @_; local($r); if (defined($v)) { if (!defined($x->{$h})) { $x->{$h} = []; # Make it into a list. } push @{$x->{$h}}, $v; $r = $v; } else { $r = $x->{$h}[$n]; } if ($h eq 'L') {$ABC_Length = $v} elsif ($h eq 'M') {$ABC_Meter = $v} elsif ($h eq 'K') {$ABC_Key = $v} return $r; } # ABC_bar(obj,bar) sub ABC_bar { local($x,$v) = @_; local($r,$t); $t = {}; $t->{'type'} = 'bar'; $t->{'val'} = $v; push @{$x->{tok}}, $t; return $t; } # ABC_gchord(obj,gchord) sub ABC_gchord { local($x,$v) = @_; local($r,$t); $t = {}; $t->{'type'} = 'gchord'; $t->{'val'} = $v; push @{$x->{tok}}, $t; return $t; } # ABC_note(obj,pitch,length) sub ABC_note { local($x,$p,$l) = @_; local($r,$t); $t = {}; $t->{'type'} = 'note'; $t->{'pitch'} = $p; $t->{'len'} = $l; push @{$x->{tok}}, $t; return $t; } # Parse some abc text, and build a parse tree for it in our ABC object. sub ABC_Parse { local($x) = shift; # ABC object to hold parsed music. local($src,$hdr,$txt); for $src (@_) { print STDERR "Parse: abc=\"$src\"\n" if $d>4; $x->{src} .= $src; # Accumulate the abc source text. } $src = $x->{src}; # Parse the entire source. while ($src) { # Each pass should eat at least 1 char. print STDERR "Parse: src=\"", substr($src,0,20), "\"\n" if $d>4; if ($src =~ s"^\s*\n\s*"") { print STDERR "Parse: Newline.\n" if $d>5; } elsif ($src =~ s"^([A-Z]):(.*?)(\n|[A-Z]:)"$3") { ABC_hdr($x,$1,0,$2); # Add to object's headers. } elsif ($src =~ s"^([\[|:\]]+)"") { # Bar line. ABC_bar($x,$1); } elsif ($src =~ s"^([A-Ga-g][,']*)([\d/]*)"") { # Note ABC_note($x,$1,$2); } elsif ($src =~ s#^"([^"]*)"##) { # Guitar chord. ABC_gchord($x,$1); } else { $src =~ s/^(.)//; print STDERR "Parse: SKIP '$1'\n" if $d>5; } print STDERR "Parse: now \"", substr($src,0,20), "\"\n" if $d>6; } return $x; } 1;