#!/usr/bin/perl -w -T

#
# $Id: music.pl,v 1.2 2002-09-10 21:47:05-05 bobn Exp bobn $
#
# generate guitar tab of scales 

# use warnings;
use strict;
use Storable qw(nstore store_fd nstore_fd freeze thaw dclone);

use Data::Dumper;
use Getopt::Long;


### changes for taintmode 
use lib qw( . );
$ENV{PATH} = '/usr/bin:/bin:/usr/bin:/usr/local/bin';
#####


use Guitar;
my $m = new Guitar;
use CGI qw(:standard) ;


my $MAXNUM = 5;

select STDERR; $|++;
select STDOUT; $|++;

my $explanation;
init();

my $loc_tim .= localtime();
# warn "$0 at $loc_tim\n";

my @in_keys = $m->notes('c');
unshift @in_keys, '';

my @in_scales = sort $m->do_list_scales;

Delete_all() if  param('reset');


print header(), start_html(-title=>"Bob Niederman's Chord and Scale Charting Script"), start_form();

print q(<h4>Scale/Chord types ending in 'C" are chords - otherwise these are scales</h4>);

for ( 1..$MAXNUM)
{
	my $out_key = radio_group(-name=>"key$_", -value=>\@in_keys, -rows=>1, -default=>0);
	$out_key =~ s!<td>!<td>Choose Key:</td><td>!i;
	$out_key =~ s!</td>!</td>\n!gi;

	# my $out_scale = scrolling_list(-name=>"scale$_", -value=>\@in_scales, -columns=>4, -default=>0);
	my $out_scale = 'Scale/Chord type: ' . popup_menu(-name=>"scale$_", -value=>\@in_scales, -length=>scalar(@in_scales) + 3, -default=>'major,');

	for ($out_key, $out_scale) { s/<TABLE/<TABLE border='1'/i; print; }
}

print checkbox(-name=>'compare'), checkbox(-name=>'numeric'), checkbox(-name=>'leftie');
print join("\n",
				submit(-name=>'Show Scales and Chords'), submit(-name=>'reset')
			);

my %tunings = ret_tunings();
my @tunings = keys %tunings;

print "\n<br>tuning:", popup_menu(-name=>'tuning', -value=>\@tunings, 
					 -labels=>\%tunings, -default=>'standard', -length=>1);
					 
print  submit(-name=>'explain all this'), end_form();

if ( param() )
{
	if ( param('explain all this') )
	{
		print $explanation;
	}
	else
	{
		for ( param() )
		{
			if ( param($_) =~ /([^a-zA-Z#0-9\s,])/ )
			{
				my $msg = "unallowed character '$1' in param($_): @{[param($_)]}";
				print "<h1>$msg<br>\n";
				die "[$loc_tim] $msg in $0\n";
			}
		}

		my @cmd = ( './music.pl' );

		
		for ( 1..$MAXNUM )
		{
			if (  param("key$_") and param("scale$_") ) 
			{
				push @cmd, "-s", param("key$_") ."," . param("scale$_");
			}
		}


		if ( param('leftie') ) { push @cmd, '-l' }

		push(@cmd, '-c') if param('compare');
		push(@cmd, '-n') if param('numeric');
		push(@cmd, '-t', param('tuning')) if param('tuning');

		print '<pre>';
		system(@cmd);
		print '</pre>';
	}
}

# print "<img src='http://bob-n.com/1x1.jpg'>", end_html; # web-bug
print end_html;


sub ret_tunings
{
	my %ret;
	my ($len, @out) = (0, ());
	my %h = %{$m->get_all_tunings()};

	# make hash for menu labels;
	for ( keys %h )
	{
		$ret{$_} = "$_ : @{$h{$_}}";
	}
	return ( %ret); 
}


sub init()
{
$explanation = qq[<br>
This program will generate a picture of how scales or chords are laid out on a 
guitar finger-board.
<br><br>
Choose a key, the type of scale or chord, then click the button labelled 
"Show Scales and/or Chords".
<br><br>
When selecting chords or scales, note that something ending in a capital C is a chord, 
otherwise it's a scale.
<br><br>
The output looks like this if you click on 'e' then click on 'minor,', then click on 
"Show Scales and/or Chords":
<br><br>
<pre>
e minor 
e  -  f# g  -  a  -  b  c  -  d  -  e  -  f# g  -  a  -  b  c  -  d  -  e 
b  c  -  d  -  e  -  f# g  -  a  -  b  c  -  d  -  e  -  f# g  -  a  -  b 
g  -  a  -  b  c  -  d  -  e  -  f# g  -  a  -  b  c  -  d  -  e  -  f# g 
d  -  e  -  f# g  -  a  -  b  c  -  d  -  e  -  f# g  -  a  -  b  c  -  d 
a  -  b  c  -  d  -  e  -  f# g  -  a  -  b  c  -  d  -  e  -  f# g  -  a 
e  -  f# g  -  a  -  b  c  -  d  -  e  -  f# g  -  a  -  b  c  -  d  -  e 
O  1     3     5     7     9        12 13    15    17    19    21       24
</pre>
<br><br>
The top line gives the key and type of scale/chord.  The following lines 
show where the notes of the scale/chord appear on the fingerboard, up until the last line, 
which is a fret marker.  
<br>
Note that, 
as in tablature ('tab') notation, the thinnest string is on top, even though on a standard guitar, 
the thinnest string is on the bottom.  I've always though that this is because when a player 
lookas at the fingerboard of the the guitar with it angled 
outward, the strings do appear in that order.  Sort of.  To invert the string order, see the
<b><tt>leftie</tt></b> option, below.
<br> <br>
<br>
You can choose 2 scales/chords to display at a time.  If you do choose 2, you can also check the 
<b>compare</b> checkbox to see the similarities and differences between the selected scales/chords 
(see below).
<br><br>
Options, menus and buttons:
<br><br>
<b>compare</b> checkbox:
<br>
When 2 key/scale combinations are given, this causes 2 additional patterns to be output.  
one will show the notes that are different between the scales/chords selected.  The other will 
show the notes that are common to both the scales/chords selected.
<br><br>
<b>numeric</b> checkbox:
<br>
This produces output using the number of the note in the selected scale, rather than the name of the note.  
This also modifies the behaviour of the extra charts produced by the compare option.  See the output 
for further explanation.
<br><br>
<b>leftie</b> checkbox:
<br>
This inverts the order of the strings, which by default is thinnest string on top 
(as viwed by player from above).  
If you would rather see the patterns as 
they would look straight on in a mirror, or if you plan to invert the stringing of your guitar 
as some left-handed players do, check this option box.
<br><br>
<b>tuning</b> menu:
<br>
This lets you chart how the chords/scales look for some common alternate tunings.  Default is 
the standard tuning (e a d g b e, thick to thin).
<br><br>
<b>reset</b> button:
<br><br>
Clears all selections to defaults.  Useful if you want to have no second key/scale selected 
for future charts after having already seleted one.

];
}

