]> mj.ucw.cz Git - vs.git/commitdiff
Added transpose mode.
authorMartin Mares <mj@ucw.cz>
Sat, 25 Jan 2003 16:19:40 +0000 (16:19 +0000)
committerMartin Mares <mj@ucw.cz>
Sat, 25 Jan 2003 16:19:40 +0000 (16:19 +0000)
vs.pl

diff --git a/vs.pl b/vs.pl
index 0ac0fb580170a156e6cfe38034b53169df095cb7..ad9be12d5fe9872a555fa3a086acc6c872ac7a02 100755 (executable)
--- a/vs.pl
+++ b/vs.pl
@@ -134,6 +134,81 @@ for(;;) {
        }
 }
 
+### Chords ###
+
+package VS::Chord;
+
+# Internal representation of chords: <base-tone>:<type> (so C="0:", C#="1:", Dmi="2:mi" etc.)
+# but usually they are accompanied by position info after a second colon
+
+our (%t2n, @n2t);
+
+BEGIN {
+%t2n = (
+       "C" => 0,
+       "C#" => 1,
+               "Db" => 1,
+       "D" => 2,
+       "D#" => 3,
+               "Eb" => 3,
+       "E" => 4,
+               "Fb" => 4,
+               "E#" => 5,
+       "F" => 5,
+       "F#" => 6,
+               "Gb" => 6,
+       "G" => 7,
+       "G#" => 8,
+               "Ab" => 8,
+       "A" => 9,
+               "Bb" => 9,
+       "A#" => 10,
+               "Hb" => 10,
+               "B" => 10,
+       "H" => 11,
+               "B#" => 11,
+               "Cb" => 11,
+               "H#" => 0
+);
+@n2t = ( "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "B", "H" );
+}
+
+sub parse_line($) {
+       my $r = shift @_;
+       my @l = ();
+       my $pos = 0;
+       while (my ($spaces,$chord,$rest) = $r =~ /(\s*)(\S+)(.*)/) {
+               $pos += length $spaces;
+               if (my ($tone,$sh,$mod) = ($chord =~ /^([CDEFGABH](#|b|))(.*)$/)) {
+                       my $k = $t2n{$tone};
+                       push @l, "$k:$mod:$pos"
+               } else {
+                       push @l, "0:?$chord:$pos";
+               }
+               $pos += length $chord;
+               $r = $rest;
+       }
+       return \@l;
+}
+
+sub synthesize_line($$) {
+       my ($l,$xpos) = @_;
+       my $pp = 0;
+       my $result = "";
+       for (my $i=0; $i<@$l; $i++) {
+               my ($tone,$mod,$pos) = split(/:/, $l->[$i]);
+               $tone = ($tone + $xpos) % 12;
+               my $chord = $n2t[$tone] . "$mod ";
+               if ($pp < $pos) {
+                       $result .= " " x ($pos - $pp);
+                       $pp = $pos;
+               }
+               $result .= $chord;
+               $pp += length $chord;
+       }
+       return $result;
+}
+
 ### Window Objects ###
 
 package VS::Window;
@@ -181,9 +256,12 @@ sub new($) {
        $w->{"file"} = "";
        $w->{"attrs"} = {};
        $w->{"lines"} = ["", "", "   The Virtual Songbook 0.0\n", "   (c) 2003 Martin Mares <mj\@ucw.cz>"];
-       $w->{"linetype"} = [0,0,0,0];
+       $w->{"chords"} = [0,0,0,0];
        $w->{"n"} = 4;
        $w->{"top"} = 0;
+       $w->{"chords_analysed"} = 0;
+       $w->{"current_xpose"} = 0;
+       $w->{"requested_xpose"} = 0;
        return bless $w;
 }
 
@@ -192,6 +270,8 @@ sub view($$$) {
        if ($w->{"file"} ne $f) {
                $w->{"file"} = $f;
                $w->{"xfile"} = $x;
+               $w->{"current_xpose"} = 0;
+               $w->{"chords_analysed"} = 0;
                $f =~ s@^./@@;
                $x =~ s@^./@@;
                if (open X, $f) {
@@ -204,16 +284,17 @@ sub view($$$) {
                                }
                        }
                        my @lines = ();
-                       my @types = ();
+                       my @chords = ();
                        while (<X>) {
                                chomp;
-                               if (s/^!//) { push @types, 1; } else { push @types, 0; }
+                               if (s/^!//) { push @chords, 1; } else { push @chords, 0; }
                                push @lines, $_;
                        }
                        close X;
                        $w->{"attrs"} = \%attrs;
                        $w->{"lines"} = \@lines;
-                       $w->{"linetypes"} = \@types;
+                       $w->{"chords"} = \@chords;
+                       $w->{"chordtable"} = [];
                        $w->{"top"} = 0;
                        $w->{"n"} = scalar @lines;
                        $w->redraw;
@@ -228,6 +309,24 @@ sub view($$$) {
        }
 }
 
+sub transpose($) {
+       my $w = shift @_;
+       if (!$w->{"chords_analysed"}) {
+               for (my $i=0; $i<$w->{"n"}; $i++) {
+                       if ($w->{"chords"}->[$i]) {
+                               $w->{"chordtable"}->[$i] = VS::Chord::parse_line($w->{"lines"}->[$i]);
+                       }
+               }
+               $w->{"chords_analysed"} = 1;
+       }
+       for (my $i=0; $i<$w->{"n"}; $i++) {
+               if ($w->{"chords"}->[$i]) {
+                       $w->{"lines"}->[$i] = VS::Chord::synthesize_line($w->{"chordtable"}->[$i], $w->{"requested_xpose"});
+               }
+       }
+       $w->{"current_xpose"} = $w->{"requested_xpose"};
+}
+
 sub redraw_line($$) {
        my ($w,$i) = @_;
        my $win = $w->{"win"};
@@ -244,6 +343,7 @@ sub redraw_line($$) {
 
 sub redraw($) {
        my $w = shift @_;
+       $w->transpose if $w->{"current_xpose"} != $w->{"requested_xpose"};
        my $win = $w->{"win"};
        my $top = $w->{"top"};
        my $cnt = $w->{"n"} - $w->{"top"};
@@ -294,6 +394,9 @@ sub key($$) {
        elsif ($key eq KEY_NPAGE) { $w->go($w->{"h"}-1); }
        elsif ($key eq KEY_HOME) { $w->go(-1000000000); }
        elsif ($key eq KEY_END) { $w->go(1000000000); }
+       elsif ($key eq "+" || $key eq "=") { $w->{"requested_xpose"} = ($w->{"requested_xpose"}+1)%12; $status_window->redraw; $w->redraw; }
+       elsif ($key eq "-") { $w->{"requested_xpose"} = ($w->{"requested_xpose"}+11)%12; $status_window->redraw; $w->redraw; }
+       elsif ($key eq "0") { $w->{"requested_xpose"} = 0; $status_window->redraw; $w->redraw; }
        else { $status_window->tell("Unknown key <$key>"); }
 }
 
@@ -463,6 +566,9 @@ sub redraw($) {
        $win->bkgdset($attr_status);
        $win->addstr(0, 0, $w->{"msg"});
        $win->clrtoeol;
+       my $aux = "";
+       $aux = "T=" . $main_window->{"requested_xpose"} if ($main_window->{"requested_xpose"});
+       $win->addstr(0, $w->{"w"}-length $aux, $aux) if $aux ne "";
        $win->refresh;
 }