While trying to brush up on my jazz improvisation, i had the great idea of making a program that would quiz me on my major scale modes! (similar to a game a friend and i would play) Improvements are encouraged greatly. Originally i planned to get it to quiz on Major and Melodic minor modes, but the program proved more complicated than i thought. Take a look:
#!/usr/bin/perl
use strict;
use Benchmark;
my @modes = qw(Ionian Dorian Phrygian Lydian Mixolydian Aeolian Locria
+n);
my @notes = qw(C D E F G A B);
my @prefs = qw(# b # b # b b # b # b #);
my @accidentals = ("#", "b", " ");
my @scales;
$scales[0] = [qw(0 2 4 5 7 9 11)];
$scales[1] = [qw(1 3 5 6 8 10 0)];
$scales[2] = [qw(2 4 6 7 9 11 1)];
$scales[3] = [qw(3 5 7 8 10 0 2)];
$scales[4] = [qw(4 6 8 9 11 1 3)];
$scales[5] = [qw(5 7 9 10 0 2 4)];
$scales[6] = [qw(6 8 10 11 1 3 5)];
$scales[7] = [qw(7 9 11 0 2 4 6)];
$scales[8] = [qw(8 10 0 1 3 5 7)];
$scales[9] = [qw(9 11 1 2 4 6 8)];
$scales[10] = [qw(10 0 2 3 5 7 9)];
$scales[11] = [qw(11 1 3 4 6 8 10)];
#how many notes ahead are each mode
my %modevalues = qw(Ionian 0 Dorian 2 Phrygian 4 Lydian 5 Mixolydian 7
+ Aeolian 9 Locrian 11);
#get random scale (note and mode)
my $mode = int(rand($#modes+1));
my $accidental = int(rand($#accidentals+1));
my $note = int(rand($#notes+1));
#find out correct number scale from random scale
my $numb = let2numb($notes[$note] . $accidentals[$accidental]); #conve
+rt music note to corresponding number
my $scale = $numb - $modevalues{$modes[$mode]}; #find
+out which original scale the mode came from
$scale += 12 if ($scale < 0); #corre
+ct negative offset
my @reference = @{$scales[$scale]}; #get t
+he correct original scale
my @take = splice(@reference,0,$mode); #conve
+rt the original scale to the right mode
@reference = (@reference, @take); #put t
+he correct scale all together
#print out what scale we want
print $notes[$note], $accidentals[$accidental], " ", $modes[$mode], ":
+\n";
#get response, convert to number music scale, and time it
my $t0 = new Benchmark;
my $cool = <STDIN>;
my $t1 = new Benchmark;
my ($measure) = timestr(timediff($t1, $t0)) =~ /^\s?(\d+ wallclock sec
+s).*/;
my @response = split(/\s/, $cool);
foreach (@response) {
$_ = let2numb($_);
}
#get correct scale in letter form
my $correct;
foreach (@reference) {
$correct .= numb2let($_,$prefs[$scale])." ";
}
#check if correct then exit
if (join(' ', @reference) eq join(' ', @response)) {
print "You're Right! $measure\n";
} else {
print "Sorry $measure\nThe correct scale was: $correct\n";
}
exit;
#function to convert a regular form music note into an number
sub let2numb() {
my ($let, $acc) = split(//, lc(shift @_));
my %cnotes = ("c", "0", "d", "2", "e", "4", "f", "5", "g", "7", "a
+", "9", "b", "11");
my $change;
if ($acc eq "b") {
$change = -1;
} elsif ($acc eq "#") {
$change = 1;
} else {
$change = 0;
}
my $return = $cnotes{$let} + $change;
if ($return > 11) {
$return -= 12;
} elsif ($return < 0) {
$return += 12;
}
return $return;
}
#function to convert number form of a music scale note into basic lett
+er scale, takes sharp or flat preference.
sub numb2let() {
my $number = shift;
my $pref = shift;
my @cnotes = qw(C h D h E F h G h A h B);
if ($cnotes[$number] eq "h") {
return ($pref eq "#") ? $cnotes[$number-1].$pref : $cnotes[$nu
+mber+1].$pref;
} else {
return $cnotes[$number];
}
}