use Tk;
use Time::HiRes qw (sleep);
use Tk::BrowseEntry;
use subs "save", "l_harm", "r_harm";
$m_win = MainWindow->new;
$m_win->title("Synthesizer");
$m_win -> geometry("+10+10");
$m_win -> fontCreate('normal', -family => 'helvetica', -size => 12);
$m_win -> optionAdd('*font' => 'normal'); 

@nh1=(0,0,0,0,0,0,0,0,0,0);
@nh2=(0,0,0,0,0,0,0,0,0,0);
@cnote=qw/C Db D Eb E F Gb G Ab A Bb B/;
@octave=(0..8);
@ref=(430..445);
@cperfect=qw(Stretched m2_16/15 M2_9/8 m3_6/5 M3_5/4 P4_4/3 TT_Sqrt(2) P5_3/2 m6_8/5 M6_5/3 m7_7/4 M7_15/8 Octave_2);
@perfect=(1,16/15,9/8,6/5,5/4,4/3,sqrt(2),3/2,8/5,5/3,7/4,15/8,2);
$ref=440;
$note=9;
$cnote="A";
$oct=4;

open (FILE,"<wavgen.txt") || die "Could not open parameter file";
@param = <FILE>;
close FILE;
chomp @param;
($freq1,$freq2,$nh1[1],$nh1[2],$nh1[3],$nh1[4],$nh1[5],$nh1[6],$nh1[7],$nh1[8],$nh1[9],$nh2[1],$nh2[2],$nh2[3],$nh2[4],$nh2[5],$nh2[6],$nh2[7],$nh2[8],$nh2[9],$d1,$d2,$ih1,$ih2,$vol,$vol,$chan,$stop)=@param;
$stop=2; #makes sure it starts 'paused'

#add a top banner frame

$note_frame = $m_win->Frame(-relief => "groove",-borderwidth => 2);
$note_frame->pack(-side => 'top', -fill => 'both', -expand => 'x');
$note_ref = $note_frame->BrowseEntry(-label => "LOAD: A4(ref)",-width => 5, -choices => \@ref, -variable => \$ref);
$note_ref -> pack(-side => 'left');
$note_note = $note_frame->BrowseEntry(
	-browse2cmd => sub{($dummy,$note)=@_;},
	-label => "  Note",
	-width => 3,
	-choices => \@cnote,
	-listheight => 12,
	-variable => \$cnote);
$note_note -> pack(-side => 'left');
$note_octave = $note_frame->BrowseEntry(-label => "  Octave", -width => 3, -choices => \@octave, -variable => \$oct);
$note_octave -> pack(-side => 'left');
$note_label = $note_frame->Label(-text => "  Into: ");
$note_label -> pack(-side => 'left');
$note_apply_l =  $note_frame->Button(-text => "L", -command => sub{
			$freq1 = $ref*2**(($note-9)/12)*2**($oct-4);
			$l_f_val->delete(0,'end'); $l_f_val->insert(0,sprintf "%4.1f", "$freq1");
			save;
			});
$note_apply_l -> pack(-side => 'left');
$note_apply_r =  $note_frame->Button(-text => "R", -command => sub{
			$freq2 = $ref*2**(($note-9)/12)*2**($oct-4);
			$r_f_val->delete(0,'end'); $r_f_val->insert(0,sprintf "%4.1f", "$freq2");
			save;
			});
$note_apply_r -> pack(-side => 'left');
$note_perfect = $note_frame->BrowseEntry(
	-browse2cmd => sub{($dummy,$perfect)=@_;
			$freq2 = $freq1*$perfect[$perfect];
			#deal with 'stretch'
			if($perfect==0){
				if($freq1>=440){
				print "greater\n";
					$freq2=$freq1*sqrt(1+$ih2*($freq1/$ref)**2);
				}else{
					$freq2=$freq1*sqrt(1-$ih2*($ref/$freq1)**2);
				print "less\n";
				};
			};
			$r_f_val->delete(0,'end'); $r_f_val->insert(0,sprintf "%4.1f", "$freq2");
			$cperfect="";
			save;
			},
	-label => "  R(L)",
	-width => 3,
	-choices => \@cperfect,
	-listheight => 13,
	-variable => \$cperfect);
$note_perfect -> pack(-side => 'left');
$note_fifth_r =  $note_frame->Button(-text => "1.5xR", -command => sub{
			$freq2 *= 1.5; if($freq2>=2*$freq1){$freq2 /=2};
			$r_f_val->delete(0,'end'); $r_f_val->insert(0,sprintf "%4.1f", "$freq2");
			save;
			});
$note_fifth_r -> pack(-side => 'left');


#    $b->insert("end", "opt1");
#    $b->insert("end", "opt2");
#    $b->insert("end", "opt3");

#establish three main frames:

$left_frame = $m_win->Frame(-relief => "groove",-borderwidth => 2);
$left_frame->pack(-side => 'left', -fill => 'both', -expand => 'y');
$control_frame = $m_win->Frame(-relief => "groove",-borderwidth => 2);
$control_frame->pack(-side => 'left', -fill => 'both', -expand => 'y');
$right_frame = $m_win->Frame(-relief => "groove",-borderwidth => 2);
$right_frame->pack(-side => 'left', -fill => 'both', -expand => 'y');
$bg_color = $left_frame -> cget('bg');

#Add Titles

$l_title = $left_frame->Label(-text => 'Left');
$l_title -> pack(-side => 'top');
$c_title = $control_frame->Label(-text => 'Control');
$c_title -> pack(-side => 'top');
$r_title = $right_frame->Label(-text => 'Right');
$r_title -> pack(-side => 'top');

#add control buttons:

$pause_frame = $control_frame->Frame(-relief => "groove",-borderwidth => 2);
$pause_frame -> pack(-side => 'top');
$c_pause =  $pause_frame->Button(-text => "Pause", -width => 10, -command => sub{
	$tmp = $stop;
	if($tmp==0){
		$c_pause -> configure(-text=>"Resume");
		$stop=2;
		save}
	elsif($tmp==2){
		$c_pause -> configure(-text=>"Pause");
		$stop=0;
		save}
	});
$c_pause -> pack(-side => 'left');

$ch_frame = $control_frame->Frame(-relief => "groove",-borderwidth => 2);
$ch_frame -> pack(-side => 'top');
$c_left =  $ch_frame->Button(-text => "left", -width => 10, -command => sub{$chan=0;save});
$c_left -> pack(-side => 'left');
$c_right =  $ch_frame->Button(-text => "right", -width => 10, -command => sub{$chan=1;save});
$c_right -> pack(-side => 'right');
$c_both =  $control_frame->Button(-text => "left+right", -width => 10, -command => sub{$chan=2;save});
$c_both -> pack(-side => 'top');
$c_stereo =  $control_frame->Button(-text => "stereo", -width => 10, -command => sub{$chan=3;save});
$c_stereo -> pack(-side => 'top');
$vol_frame = $control_frame->Frame(-relief => "groove",-borderwidth => 2);
$vol_frame -> pack(-side => 'top');
$vol_down =  $vol_frame->Button(-text => "Down", -width => 10, -command => sub{
					$vol *= 0.9; if($vol<=0){$vol=0};
					save;
					});
$vol_down -> pack(-side => 'left');
$vol_up =  $vol_frame->Button(-text => "Up", -width => 10, -command => sub{
					$vol *= 1.1; if($vol>=10000){$vol=10000};
					save;
					});
$vol_up -> pack(-side => 'right');
$volume = $control_frame->Label(-text => 'Volume');
$volume -> pack(-side => 'top');
$centval = $control_frame->Label(-text => "$cents");
$centval -> pack(-side => 'top');

$c_start =  $control_frame->Button(-text => "START", -width => 10, -background => "pink", -activebackground => "pink", -command => sub{
					$stop=0;
					save;
					$parentpid=$$;
					unless ($childpid=fork()){
						system("perl wavgen2.pl");
						exit()
						};
					$c_start -> configure(-text => "", -background => "$bg_color", -activebackground => "$bg_color");
					$c_exit -> configure(-background => "pink", -activebackground => "pink");
					});
$c_start -> pack(-side => 'left');


$c_exit =  $control_frame->Button(-text => "EXIT", -width => 10, -command => sub{
					$stop=1;
					save;
					sleep 0.25;
					exit;
					});
$c_exit -> pack(-side => 'right');

#populate left frame:

$l_freq_frame = $left_frame->Frame(-relief => "groove",-borderwidth => 2);
$l_freq_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');
$l_harm_frame = $left_frame->Frame(-relief => "groove",-borderwidth => 2);
$l_harm_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');
$l_damp_frame = $left_frame->Frame(-relief => "groove",-borderwidth => 2);
$l_damp_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');
$l_inhar_frame = $left_frame->Frame(-relief => "groove",-borderwidth => 2);
$l_inhar_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');

#populate right frame:

$r_freq_frame = $right_frame->Frame(-relief => "groove",-borderwidth => 2);
$r_freq_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');
$r_harm_frame = $right_frame->Frame(-relief => "groove",-borderwidth => 2);
$r_harm_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');
$r_damp_frame = $right_frame->Frame(-relief => "groove",-borderwidth => 2);
$r_damp_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');
$r_inhar_frame = $right_frame->Frame(-relief => "groove",-borderwidth => 2);
$r_inhar_frame -> pack(-side => 'top', -fill => 'both', -expand => 'y');

#Left Frequency:

$l_f_lab =  $l_freq_frame->Label(-text => "Frequency");
$l_f_lab -> pack(-side => 'bottom');
$l_f_inc2 =  $l_freq_frame->Button(-text => "<<",
			-repeatdelay => 500,
			-repeatinterval => 100,
			-command => sub{
			$freq1 -= 2; if($freq1<=0){$freq1=0};
			$l_f_val->delete(0,'end'); $l_f_val->insert(0,sprintf "%4.1f", "$freq1");
			save;
			});
$l_f_inc2 -> pack(-side => 'left');
$l_f_inc =  $l_freq_frame->Button(-text => "<", -command => sub{
			$freq1 -= 0.1; if($freq1<=0){$freq1=0};
			$l_f_val->delete(0,'end'); $l_f_val->insert(0,sprintf "%4.1f", "$freq1");
			save;
			});
$l_f_inc -> pack(-side => 'left');
$l_f_val =  $l_freq_frame->Entry(-width => 6);
$l_f_val -> pack(-side => 'left');
$l_f_dec =  $l_freq_frame->Button(-text => ">", -command => sub{
			$freq1 += 0.1; if($freq1<=0){$freq1=0};
			$l_f_val->delete(0,'end'); $l_f_val->insert(0,sprintf "%4.1f", "$freq1");
			save;
			});
$l_f_dec -> pack(-side => 'left');
$l_f_dec2 =  $l_freq_frame->Button(-text => ">>",
			-repeatdelay => 500,
			-repeatinterval => 100,
			-command => sub{
			$freq1 += 2; if($freq1>=10000){$freq1=10000};
			$l_f_val->delete(0,'end'); $l_f_val->insert(0,sprintf "%4.1f", "$freq1");
			save;
			});
$l_f_dec2 -> pack(-side => 'left');

#Right Frequency:

$r_f_lab =  $r_freq_frame->Label(-text => "Frequency");
$r_f_lab -> pack(-side => 'bottom');
$r_f_inc2 =  $r_freq_frame->Button(-text => "<<",
			-repeatdelay => 500,
			-repeatinterval => 100,
			-command => sub{
			$freq2 -= 2; if($freq2<=0){$freq2=0};
			$r_f_val->delete(0,'end'); $r_f_val->insert(0,sprintf "%4.1f", "$freq2");
			save;
			});
$r_f_inc2 -> pack(-side => 'left');
$r_f_inc =  $r_freq_frame->Button(-text => "<", -command => sub{
			$freq2 -= 0.1; if($freq2<=0){$freq2=0};
			$r_f_val->delete(0,'end'); $r_f_val->insert(0,sprintf "%4.1f", "$freq2");
			save;
			});
$r_f_inc -> pack(-side => 'left');
$r_f_val =  $r_freq_frame->Entry(-width => 6);
$r_f_val -> pack(-side => 'left');
$r_f_dec =  $r_freq_frame->Button(-text => ">", -command => sub{
			$freq2 += 0.1; if($freq2<=0){$freq2=0};
			$r_f_val->delete(0,'end'); $r_f_val->insert(0,sprintf "%4.1f", "$freq2");
			save;
			});
$r_f_dec -> pack(-side => 'left');
$r_f_dec2 =  $r_freq_frame->Button(-text => ">>",
			-repeatdelay => 500,
			-repeatinterval => 100,
			-command => sub{
			$freq2 += 2; if($freq2>=10000){$freq2=10000};
			$r_f_val->delete(0,'end'); $r_f_val->insert(0,sprintf "%4.1f", "$freq2");
			save;
			});
$r_f_dec2 -> pack(-side => 'left');

#Left Harmonic:

$l_h_lab =  $l_harm_frame->Label(-text => "Harmonics");
$l_h_lab -> pack(-side => 'bottom');
$l_h_frm =  $l_harm_frame->Frame(-borderwidth => 0 );
$l_h_frm -> pack(-side => 'bottom');
$l_h[1] =  $l_h_frm->Button(-text => "1", -command => sub{l_harm(1);save}) -> pack(-side => 'left');
$l_h[2] =  $l_h_frm->Button(-text => "2", -command => sub{l_harm(2);save}) -> pack(-side => 'left');
$l_h[3] =  $l_h_frm->Button(-text => "3", -command => sub{l_harm(3);save}) -> pack(-side => 'left');
$l_h[4] =  $l_h_frm->Button(-text => "4", -command => sub{l_harm(4);save}) -> pack(-side => 'left');
$l_h[5] =  $l_h_frm->Button(-text => "5", -command => sub{l_harm(5);save}) -> pack(-side => 'left');
$l_h[6] =  $l_h_frm->Button(-text => "6", -command => sub{l_harm(6);save}) -> pack(-side => 'left');
$l_h[7] =  $l_h_frm->Button(-text => "7", -command => sub{l_harm(7);save}) -> pack(-side => 'left');
$l_h[8] =  $l_h_frm->Button(-text => "8", -command => sub{l_harm(8);save}) -> pack(-side => 'left');
$l_h[9] =  $l_h_frm->Button(-text => "9", -command => sub{l_harm(9);save}) -> pack(-side => 'left');

#Right Harmonic:

$r_h_lab =  $r_harm_frame->Label(-text => "Harmonics");
$r_h_lab -> pack(-side => 'bottom');
$r_h_frm =  $r_harm_frame->Frame(-borderwidth => 0 );
$r_h_frm -> pack(-side => 'bottom');
$r_h[1] =  $r_h_frm->Button(-text => "1", -command => sub{r_harm(1);save}) -> pack(-side => 'left');
$r_h[2] =  $r_h_frm->Button(-text => "2", -command => sub{r_harm(2);save}) -> pack(-side => 'left');
$r_h[3] =  $r_h_frm->Button(-text => "3", -command => sub{r_harm(3);save}) -> pack(-side => 'left');
$r_h[4] =  $r_h_frm->Button(-text => "4", -command => sub{r_harm(4);save}) -> pack(-side => 'left');
$r_h[5] =  $r_h_frm->Button(-text => "5", -command => sub{r_harm(5);save}) -> pack(-side => 'left');
$r_h[6] =  $r_h_frm->Button(-text => "6", -command => sub{r_harm(6);save}) -> pack(-side => 'left');
$r_h[7] =  $r_h_frm->Button(-text => "7", -command => sub{r_harm(7);save}) -> pack(-side => 'left');
$r_h[8] =  $r_h_frm->Button(-text => "8", -command => sub{r_harm(8);save}) -> pack(-side => 'left');
$r_h[9] =  $r_h_frm->Button(-text => "9", -command => sub{r_harm(9);save}) -> pack(-side => 'left');

#Left Damping:

$l_d_lab =  $l_damp_frame->Label(-text => "Damping ");
$l_d_lab -> pack(-side => 'bottom');
$l_d_frm =  $l_damp_frame->Frame(-borderwidth => 0 );
$l_d_frm -> pack(-side => 'bottom');
$l_d_inc =  $l_d_frm->Button(-text => "<", -command => sub{
			$d1 -= 0.05; if($d1<=0){$d1=0};
			$l_d_val->delete(0,'end'); $l_d_val->insert(0,sprintf "%4.2f", "$d1");
			save;
			});
$l_d_inc -> pack(-side => 'left');
$l_d_val =  $l_d_frm->Entry(-width => 6);
$l_d_val -> pack(-side => 'left');
$l_d_dec =  $l_d_frm->Button(-text => ">", -command => sub{
			$d1 += 0.05; if($d1>=1){$d1=1};
			$l_d_val->delete(0,'end'); $l_d_val->insert(0,sprintf "%4.2f", "$d1");
			save;
			});
$l_d_dec -> pack(-side => 'left');

#Right Damping:

$r_d_lab =  $r_damp_frame->Label(-text => "Damping ");
$r_d_lab -> pack(-side => 'bottom');
$r_d_frm =  $r_damp_frame->Frame(-borderwidth => 0 );
$r_d_frm -> pack(-side => 'bottom');
$r_d_inc =  $r_d_frm->Button(-text => "<", -command => sub{
			$d2 -= 0.05; if($d2<=0){$d2=0};
			$r_d_val->delete(0,'end'); $r_d_val->insert(0,sprintf "%4.2f", "$d2");
			save;
			});
$r_d_inc -> pack(-side => 'left');
$r_d_val =  $r_d_frm->Entry(-width => 6);
$r_d_val -> pack(-side => 'left');
$r_d_dec =  $r_d_frm->Button(-text => ">", -command => sub{
			$d2 += 0.05; if($d2>=1){$d2=1};
			$r_d_val->delete(0,'end'); $r_d_val->insert(0,sprintf "%4.2f", "$d2");
			save;
			});
$r_d_dec -> pack(-side => 'left');

#Left Inharmonicity:

$l_i_lab =  $l_inhar_frame->Label(-text => "Inharmonicity ");
$l_i_lab -> pack(-side => 'bottom');
$l_i_frm =  $l_inhar_frame->Frame(-borderwidth => 0 );
$l_i_frm -> pack(-side => 'bottom');
$l_i_inc =  $l_i_frm->Button(-text => "<", -command => sub{
			$ih1 -= 0.0001; if($ih1<=0){$ih1=0};
			$l_i_val->delete(0,'end'); $l_i_val->insert(0,sprintf "%5.4f", "$ih1");
			save;
			});
$l_i_inc -> pack(-side => 'left');
$l_i_val =  $l_i_frm->Entry(-width => 6);
$l_i_val -> pack(-side => 'left');
$l_i_dec =  $l_i_frm->Button(-text => ">", -command => sub{
			$ih1 += 0.0001; if($ih1>=0.05){$ih1=0.05};
			$l_i_val->delete(0,'end'); $l_i_val->insert(0,sprintf "%5.4f", "$ih1");
			save;
			});
$l_i_dec -> pack(-side => 'left');

#Right Inharmonicity:

$r_i_lab =  $r_inhar_frame->Label(-text => "Inharmonicity ");
$r_i_lab -> pack(-side => 'bottom');
$r_i_frm =  $r_inhar_frame->Frame(-borderwidth => 0 );
$r_i_frm -> pack(-side => 'bottom');
$r_i_inc =  $r_i_frm->Button(-text => "<", -command => sub{
			$ih2 -= 0.0001; if($ih2<=0){$ih2=0};
			$r_i_val->delete(0,'end'); $r_i_val->insert(0,sprintf "%5.4f", "$ih2");
			save;
			});
$r_i_inc -> pack(-side => 'left');
$r_i_val =  $r_i_frm->Entry(-width => 6);
$r_i_val -> pack(-side => 'left');
$r_i_dec =  $r_i_frm->Button(-text => ">", -command => sub{
			$ih2 += 0.0001; if($ih2>=0.05){$ih2=0.05};
			$r_i_val->delete(0,'end'); $r_i_val->insert(0,sprintf "%5.4f", "$ih2");
			save;
			});
$r_i_dec -> pack(-side => 'left');

#preload values to graphical interface:

$l_f_val->insert(0,sprintf "%4.1f", "$freq1");
$r_f_val->insert(0,sprintf "%4.1f", "$freq2");
for($nh=1;$nh<=9;$nh++){
if($nh1[$nh]){$l_h[$nh] -> configure(-background => "yellow", -activebackground => "yellow")}else{$l_h[$nh] -> configure(-background => "$bg_color", -activebackground => "$bg_color")};
if($nh2[$nh]){$r_h[$nh] -> configure(-background => "yellow", -activebackground => "yellow")}else{$r_h[$nh] -> configure(-background => "$bg_color", -activebackground => "$bg_color")};
};
$l_d_val->insert(0,sprintf "%4.2f", "$d1");
$r_d_val->insert(0,sprintf "%4.2f", "$d2");
$l_i_val->insert(0,sprintf "%5.4f", "$ih1");
$r_i_val->insert(0,sprintf "%5.4f", "$ih2");
save;

MainLoop;

sub save {
	$fhigh=$freq2;
	$flow=$freq1;
	if($fhigh<=$flow){$fhigh=$freq1;$flow=$freq2};
	$tmp=log($fhigh/$flow)/log(2)+10;
	$cents=1200*($tmp-int($tmp));
	$centval->configure(-text => sprintf "diff: %5.1f cents", "$cents");
	@output=($freq1,$freq2,$nh1[1],$nh1[2],$nh1[3],$nh1[4],$nh1[5],$nh1[6],$nh1[7],$nh1[8],$nh1[9],$nh2[1],$nh2[2],$nh2[3],$nh2[4],$nh2[5],$nh2[6],$nh2[7],$nh2[8],$nh2[9],$d1,$d2,$ih1,$ih2,$vol,$vol,$chan,$stop);
	$outputline=join("\n",@output);
	open(FILE,">wavgen.txt");
	print FILE "$outputline";
	close FILE;
};

sub l_harm {
	($nh)=@_;
	$nh1[$nh] = -$nh1[$nh]+1;
	if($nh1[$nh]){
	$l_h[$nh] -> configure(-background => "yellow", -activebackground => "yellow")
	}else{
	$l_h[$nh] -> configure(-background => "$bg_color", -activebackground => "$bg_color")};
};
sub r_harm {
	($nh)=@_;
	$nh2[$nh] = -$nh2[$nh]+1;
	if($nh2[$nh]){
	$r_h[$nh] -> configure(-background => "yellow", -activebackground => "yellow")
	}else{
	$r_h[$nh] -> configure(-background => "$bg_color", -activebackground => "$bg_color")};
};
