#!/bin/sh
# the next line restarts using wish \
if [ -n "$DISPLAY" ]; then exec wish "$0" "$@"; \
else echo "No Display! Run ExEf in X Window."; exit 1; fi

# ExEf - the ultimate effect engine
# Copyright (C) 2001 Tom Olexa <olexat@post.cz>

# Auxiliary functions

# Exponential frequency
proc expf {x y} {
    global paramhts$x$y paramf$x$y
    set paramf$x$y [expr round(19.445*exp(0.05776*[set paramhts$x$y]))]
    .$x$y.scales.scalef configure -label "[set paramf$x$y] Hz"
} 

# Exponential time
proc expt {x y n} {
    global paramsix$n$x$y paramt$n$x$y
    set paramt$n$x$y [expr round(exp(0.04332*[set paramsix$n$x$y]))]
    .$x$y.scales.scalet$n configure -label "[set paramt$n$x$y] ms"
}

# Logarithmic frequency
proc logf {freq} {
    expr round(17.31*log($freq) - 51.37)
}

# Logarithmic time
proc logt {tau} {
    expr round(23.08*log($tau))
}

# Button update - distort
proc dupdate {x y n nname kind} {
    .$x$y.buttons.$n configure -text "$nname: $kind"
    flushdis $x $y
}

# Button update - filters
proc fupdate {x y kind} {
    .$x$y.scales.button configure -text "$kind"
}    

# Button update - modulator
proc mupdate {x y par value} {
    .$x$y.scales.$par configure -text "$value"
} 

# Slider limits update - biquad
proc supdate {x y} {
    global paramk$x$y
    if {[set paramk$x$y] == "e"} {
	set wlabel Resonance
	set sfrom 40
	set sto -40
    } else {
	set wlabel {  Stopband}
	set sfrom 0
	set sto -80
    }
    .$x$y.label configure -text "Pass type     Frequency \[halftones\]     \
        Q factor \[dB\]    $wlabel \[dB\]"
    .$x$y.scales.scalep configure -from $sfrom -to $sto	-variable paramp$x$y
}

# Disabling/enabling slider (SpecSub)
proc ableSs {x y} {
    global paramd$x$y
    if [set paramd$x$y] {
	.$x$y.scales.scalet2 configure -state disabled -troughcolor Black
    } else {.$x$y.scales.scalet2 configure -state normal -troughcolor Gray30}
}	

# Disabling/enabling slider (Modulator)
proc ableM {x y} {
    global paramk$x$y
    if {[set paramk$x$y] == "a"} {
	.$x$y.scales.scalep configure -state disabled -troughcolor Black
    } else {.$x$y.scales.scalep configure -state normal -troughcolor Gray30}
}

# Updating VU meter status
proc vupdate {} {
    global paramd100
    if {$paramd100} {
	set onOff Off
	set high 34
	set stat normal
    } else {
	set onOff On
	set high 0
	set stat disabled
	destroy .100
    }
	
    .invu.top.vuon configure -text $onOff
    .outvu.top.vuon configure -text $onOff
    .invu.vubar configure -height $high
    .outvu.vubar configure -height $high
    .invu.top.vuopt configure -state $stat
    .outvu.top.vuopt configure -state $stat
    flushvu
}

# Disabling/enabling VU meter
proc vuable {} {
    global paramd100
    set paramd100 [expr !$paramd100]
    vupdate
}

# VU bar + light
proc barSlide {upDown BarId value} {
    set inpx [expr $value*3+300] 
    $upDown coords $BarId 30 2 $inpx 10
}

proc light {upDown LightId value} {
    if {$value == 0} {
	$upDown itemconfigure $LightId -fill Black
    }
    if {$value == 1} {
	$upDown itemconfigure $LightId -fill Yellow3
    }    
}

# Recording unit updates
proc recording {m f} {
    global paramd108
    switch $m {
	2   {
	    destroy .102
	    destroy .104
	    destroy .108
	    .record.rec configure -state disabled
	    .record.pause configure -state normal
	    .record.stop configure -state normal
    	    .record.top.status configure -text "Recording"
	    .record.top.set configure -state disabled
	    foreach i {1 2 4 5 7} {
		.exefbutton.exef.menu entryconfigure $i -state disabled
	    }
	    set paramd108 1
	}
	3   {
	    if {$paramd108 == 3} {
		.record.top.status configure -text "Recording"
		set paramd108 2
	    } else {
		.record.top.status configure -text "Paused"
		set paramd108 3
	    }	
	}
	0   {
	    .record.rec configure -state normal
	    .record.pause configure -state disabled
	    .record.stop configure -state disabled
	    .record.top.status configure -text "Stopped"
	    .record.top.set configure -state normal
	    .exefbutton.exef configure -state normal
	    foreach i {1 2 4 5 7} {
		.exefbutton.exef.menu entryconfigure $i -state normal
	    }
	    set paramd108 4
	}
    }
    if {$f} {
        flushrec
    }
}	


# File functions

# Pipes initialization
proc initPipes {} {
    global ReceivId TransId
    set t 100
    while {![file exists /var/tmp/.ExEf]} {
	puts "Waiting $t ms for /var/tmp/.ExEf"
	after $t
	set t [expr $t << 1]	
    }
    cd /var/tmp/.ExEf
    
    set t 100
    while {![file exists FFromTcl]} {
	puts "Waiting $t ms for pipes"
	after $t
	set t [expr $t << 1]	
    }
    set ReceivId [open FToTcl r]
    set TransId [open FFromTcl w]
    fconfigure $TransId -buffering line
}

proc initDir {} {
    set t 100
    while {![file exists .ExEf]} {
	puts "Waiting $t ms for ~/.ExEf"
	after $t
	set t [expr $t << 1]	
    }
    cd .ExEf
}

# Changing a directory
proc chDir {x y} {
    global dirName fileName completeName
    set dirTail [.104.boxes.dirs get @$x,$y]
    cd [file join $dirName $dirTail]
    set dirName [pwd]
    set completeName [file join $dirName $fileName]
    loadDir
}    

# Loading a directory
proc loadDir {} {
    global dirName
     
    .104.boxes.dirs delete 0 end
    foreach i [lsort [concat [glob -nocomplain [file join $dirName .*]] \
	[glob -nocomplain [file join $dirName *]]]] {
	    if {[file isdirectory $i]} {
        	.104.boxes.dirs insert end [file tail $i]
	    }    
    }
    
    .104.boxes.files delete 0 end
    foreach i [lsort [concat [glob -nocomplain [file join $dirName .*]] \
	[glob -nocomplain [file join $dirName *]]]] {
	    if {[file isfile $i]} {
        	.104.boxes.files insert end [file tail $i]
	    }    
    }    
} 

# File or Directory?
proc fileOrDir m {
    global completeName dirName fileName
    if {[file isdirectory $completeName]} {
	cd $completeName
	set dirName [pwd]
	loadDir	
    } else {
    	loadSave $m
    }	
}

# Load / Save
proc loadSave {m} {
    global changed continue completeName fileName outChan TransId
    
    switch $m {
	l -
	lchan {
	    if {$changed} {
		setEffect 10 6
		tkwait window .106
		if {!$continue} {
		    return
		}
	    }
	    destroy .104
	    if {$m == "l"} {
		set fileName [file tail $completeName]
		winNotCh
		destroy .100
		destroy .101
		destroy .102
		removeAll
		puts $TransId "Load $completeName"
	    } else {
		winChanged	
		set x $outChan
		removeCol $x
		puts $TransId "Column $x $completeName"
	    }	
	}
	s {
	    destroy .104
	    set fileName [file tail $completeName]
	    winNotCh
	    saveConf
	}
	schan {
	    destroy .104
	    saveChannel
	}
	r {
	global paramn108
	set SaveId [open $completeName w]
	close $SaveId
	set paramn108 $completeName
	recording 2 1
	}
    }        
}   

# Getting file name
proc getFileName {m a x y} {
    global dirName completeName 
    set filename [.104.boxes.files get @$x,$y]
    set completeName [file join $dirName $filename]
    if {$a} {
	loadSave $m
    }
}

# Saving conf
proc saveConf {} {
    global completeName
    set SaveId [open $completeName w]
    puts "Saving $completeName config file"

    puts $SaveId "ExEf config"
    global fSamp bufSize
    puts $SaveId "Audio $fSamp $bufSize"
    global outChan outChPrev paramt1101
    puts $SaveId "Switch $outChan $outChPrev $paramt1101"
    global paramt1100 paramt2100 paramd100
    puts $SaveId "VUMeters $paramt1100 $paramt2100 $paramd100"
    global params108 paramn108
    puts $SaveId "SaveWave 0 $params108 $paramn108"
    puts $SaveId "*Effects"
    foreach x {0 1 2 3} {
	global maxy$x name$x
	puts $SaveId "*Column [set name$x]"
	for {set y 0} {$y <= [set maxy$x]} {incr y} {
	    global kind$x$y param$x$y
	    puts $SaveId "[set kind$x$y] [set param$x$y]"
	}
    }
    puts $SaveId "*"
    flush $SaveId
    close $SaveId
}  

# Saving channel
proc saveChannel {} {
    global completeName outChan
    set SaveId [open $completeName w]
    puts "Saving channel $outChan to $completeName file"

    puts $SaveId "ExEf column"
    set x $outChan
    global maxy$x name$x
    puts $SaveId "*Column [set name$x]"
    for {set y 0} {$y <= [set maxy$x]} {incr y} {
        global kind$x$y param$x$y
        puts $SaveId "[set kind$x$y] [set param$x$y]"
    }
    
    puts $SaveId "*"
    flush $SaveId
    close $SaveId
}  


# Window title - file changed
proc winChanged {} {
    global changed fileName
    set changed 1
    wm title . "Extreme Effect - $fileName (changed)"
}    

# Window title - file not changed
proc winNotCh {} {
    global changed fileName   
    set changed 0
    wm title . "Extreme Effect - $fileName"
}    

# Removing a column
proc removeCol {x} {
    global maxy$x
    for {set y 0} {$y <= [set maxy$x]} {incr y} {
	destroy .effects.matrix.$x$y
	destroy .$x$y
    }
    set maxy$x -1
}    	

# Removing all boxes
proc removeAll {} {
    foreach x {0 1 2 3} {
	removeCol $x
    }
}    	

# New matrix
proc NewMatrix {} {
    global TransId changed continue
    if {$changed} {
        setEffect 10 6
        tkwait window .106
        if {!$continue} {
	    return
	}
    }
    removeAll
    puts $TransId "NewMatrix"
    winNotCh
}

# Warning of changes
proc WarnCng {} {
    global continue
    set continue 0
    set x 10
    set y 6

    wm title .$x$y "Warning!"

    label .$x$y.warn -font {Helvetica 18} -text {Warning!} -pady 8
    label .$x$y.cngs -text {Some changes made. Continue?}
    pack .$x$y.warn .$x$y.cngs

    frame .$x$y.buttons
    pack .$x$y.buttons -fill x
    button .$x$y.buttons.yes -text Yes -pady 0 -command "set continue 1; destroy .$x$y"
    button .$x$y.buttons.cancel -text Cancel -pady 0 -command "destroy .$x$y"
    pack .$x$y.buttons.yes .$x$y.buttons.cancel -side left -expand 1 -pady 3
    after 100 grab .$x$y
}    
    
# Load Error
proc LoadError {} {
    global er path
    set x 10
    set y 7

    wm title .$x$y "Load Error"

    label .$x$y.warn -font {Helvetica 18} -text {Load Error!} -pady 8
    switch $er {
	1 {label .$x$y.er -text "Can't read file"}
	2 {label .$x$y.er -text "Config file broken"}
	3 {label .$x$y.er -text "Column config file broken"}
    }
    label .$x$y.fname -text "File: $path"
    pack .$x$y.warn .$x$y.fname .$x$y.er -padx 8

    button .$x$y.button -text Acknowledge -pady 0 -command "destroy .$x$y"
    pack .$x$y.button -pady 3
    after 100 grab .$x$y
}    

  
# Flushing functions
# Flushing pass
proc flushpass {x y} {
    global TransId param$x$y kind$x$y paramk$x$y paramf$x$y paramp$x$y 
    set param$x$y "[set paramk$x$y] [set paramf$x$y] [set paramp$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing biquad
proc flushbiq {x y} {
    global TransId param$x$y kind$x$y paramk$x$y paramf$x$y paramq$x$y paramp$x$y
    set param$x$y "[set paramk$x$y] [set paramf$x$y]\
	[set paramq$x$y] [set paramp$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing distort
proc flushdis {x y} {
    global TransId param$x$y kind$x$y paraml$x$y paramr$x$y paramp$x$y 
    set param$x$y "[set paraml$x$y] [set paramr$x$y] [set paramp$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing modulator
proc flushmod {x y} {
    global TransId param$x$y kind$x$y \
	paramw$x$y paramk$x$y paramd$x$y paramt1$x$y paramp$x$y
    set param$x$y "[set paramk$x$y] [set paramw$x$y] [set paramd$x$y]\
    [set paramt1$x$y] [set paramp$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing delay
proc flushdel {x y} {
    global TransId param$x$y kind$x$y parampre$x$y paramx1$x$y paramx2$x$y \
	paramout$x$y paramr1$x$y paramr2$x$y
    set param$x$y "[set parampre$x$y] [set paramx1$x$y] [set paramx2$x$y]\
	[set paramr1$x$y] [set paramr2$x$y] [set paramout$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing hall
proc flushhall {x y} {
    global TransId param$x$y kind$x$y parampre$x$y paramx1$x$y \
	paramx2$x$y paramx3$x$y	paramout$x$y paramr1$x$y paramr2$x$y paramr3$x$y
    set param$x$y "[set parampre$x$y] [set paramx1$x$y] [set paramx2$x$y] \
	[set paramx3$x$y] [set paramr1$x$y] [set paramr2$x$y] \
	[set paramr3$x$y] [set paramout$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing reverb
proc flushrev {x y} {
    global TransId param$x$y kind$x$y paramord$x$y paramx1$x$y parampre$x$y \
	paramt1$x$y paramx2$x$y	paramr1$x$y paramout$x$y
    set param$x$y "[set paramord$x$y] [set paramx1$x$y] [set parampre$x$y] \
	 [set paramt1$x$y] [set paramx2$x$y] [set paramr1$x$y] [set paramout$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing compressor
proc flushcomp {x y} {
    global TransId param$x$y kind$x$y paramth$x$y paramr$x$y paramt1$x$y paramt2$x$y
    set param$x$y "[set paramth$x$y] [set paramr$x$y]\
	[set paramt1$x$y] [set paramt2$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing singen
proc flushsin {x y} {
    global TransId param$x$y kind$x$y paramf$x$y paramp$x$y 
    set param$x$y "[set paramf$x$y] [set paramp$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing noisegate
proc flushng {x y} {
    global TransId param$x$y kind$x$y paramth$x$y params$x$y paramt1$x$y paramt2$x$y
    set param$x$y "[set paramth$x$y] [set params$x$y] \
	[set paramt1$x$y] [set paramt2$x$y]"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing specsub
proc flushss {x y} {
    global TransId param$x$y kind$x$y paramth$x$y paramt1$x$y paramt2$x$y paramd$x$y
    set tau2 [set paramt2$x$y]
    if [set paramd$x$y] {
	set tau2 -1
    }
    set param$x$y " [set paramth$x$y] [set paramt1$x$y] $tau2"
    puts $TransId "Box $x $y [set kind$x$y] [set param$x$y]"
}

# Flushing copy
proc flushcopy {x y} {
    global TransId kind$x$y
    puts $TransId "Box $x $y [set kind$x$y]"
}

# Flushing audio settings
proc flushaud {} {
    global TransId fSamp bufSize
    puts $TransId "Audio $fSamp $bufSize"
}

# Flushing output switch
proc flushsw {param} {
    global TransId outChan outChdel outChPrev paramt1101
    puts $TransId "Switch $outChan $paramt1101"
    if {$param == "c"} {
        set outChPrev $outChdel
	set outChdel $outChan
    }
}

# Flushing VU meters
proc flushvu {} {
    global TransId paramt1100 paramt2100 paramd100
    puts $TransId "VUMeters $paramt1100 $paramt2100 $paramd100"
}

# Flushing recording setting
proc flushrec {} {
    global TransId paramd108 params108 paramn108
    puts $TransId "SaveWave $paramd108 $params108 $paramn108"
}


# Effect windows
# Gain
proc gain {x y} {
    global kind$x$y TransId
    wm title .$x$y "$x$y Gain"
    label .$x$y.label -width 24 -text {Gain [dB]}
    scale .$x$y.scale -orient vertical -length 100 -from 75 -to -75 \
	-sliderlength 24 -tickinterval 25 -variable param$x$y \
	-command "puts -nonewline $TransId \"Box $x $y [set kind$x$y] \"
	    puts $TransId "
    pack .$x$y.label .$x$y.scale 
} 

# Pass
proc pass {x y} {
    global paramk$x$y
    wm title .$x$y "$x$y Pass"
    label .$x$y.label -width 52 -text {Pass type     Frequency [halftones]    \
        Stopband gain [dB]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    
    menubutton .$x$y.scales.button -direction right -width 8 \
        -menu .$x$y.scales.button.menu
    .$x$y.scales.button configure -pady 1 -relief raised
    pack .$x$y.scales.button -side left -padx 16
    menu .$x$y.scales.button.menu -tearoff 0

    foreach nkind {l h} kindname {Lowpass Highpass} {
	.$x$y.scales.button.menu add radiobutton -label $kindname \
    	    -variable paramk$x$y -value $nkind \
	    -command "fupdate $x $y $kindname; flushpass $x $y"
	if {$nkind == [set paramk$x$y]} {
	    .$x$y.scales.button configure -text "$kindname"}
    }
    scale .$x$y.scales.scalef -orient vertical -length 100 -from 120 -to 0 \
	-sliderlength 24 -tickinterval 20 -variable paramhts$x$y \
	-command "expf $x $y; flushpass $x $y; set dump"
    pack .$x$y.scales.scalef -side left
    scale .$x$y.scales.scalep -orient vertical -length 100 -from 0 -to -80 \
	-sliderlength 24 -tickinterval 20 -variable paramp$x$y \
	-command "flushpass $x $y; set dump"
    pack .$x$y.scales.scalep -side right -padx 16
}

# Biquad
proc biquad {x y} {
    global paramk$x$y
    wm title .$x$y "$x$y Biquad"
    label .$x$y.label -width 62
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    
    menubutton .$x$y.scales.button -direction right -width 8 \
        -menu .$x$y.scales.button.menu
    .$x$y.scales.button configure -pady 1 -relief raised
    pack .$x$y.scales.button -side left -padx 16
    menu .$x$y.scales.button.menu -tearoff 0

    foreach nkind {l h e} kindname {Lowpass Highpass Equalizer} {
	.$x$y.scales.button.menu add radiobutton -label $kindname \
    	    -variable paramk$x$y -value $nkind \
	    -command "fupdate $x $y $kindname; supdate $x $y; flushbiq $x $y"
	if {$nkind == [set paramk$x$y]} {
	    .$x$y.scales.button configure -text "$kindname"}
    }
    scale .$x$y.scales.scalef -orient vertical -length 100 -from 120 -to 0 \
	-sliderlength 24 -tickinterval 20 -variable paramhts$x$y \
	-command "expf $x $y; flushbiq $x $y; set dump"
    pack .$x$y.scales.scalef -side left
    scale .$x$y.scales.scalep -orient vertical -length 100 \
	-sliderlength 24 -tickinterval 20 \
	-command "flushbiq $x $y; set dump"
    pack .$x$y.scales.scalep -side right -padx 16
    scale .$x$y.scales.scaleq -orient vertical -length 100 -from 30 -to -10 \
	-sliderlength 24 -tickinterval 10 -variable paramq$x$y \
	-command "flushbiq $x $y; set dump"
    pack .$x$y.scales.scaleq -side right
    supdate $x $y
}
    
# Distort
proc distort {x y} {    
    global paraml$x$y paramr$x$y
    wm title .$x$y "$x$y Distort"
    label .$x$y.label -width 34 -text {Distortion type           ParaDir [dB]}
    pack .$x$y.label
    frame .$x$y.buttons
    pack .$x$y.buttons -side left -fill y -expand yes
    scale .$x$y.scale -orient vertical -length 100 -from 0 -to -120 \
	-sliderlength 24 -tickinterval 20 -variable paramp$x$y \
	-command "flushdis $x $y; set dump"
    pack .$x$y.scale -side right -padx 10
    
    foreach sides {l r} sidenames {Left Right} {
        menubutton .$x$y.buttons.$sides -direction right \
	    -menu .$x$y.buttons.$sides.menu
	.$x$y.buttons.$sides configure -pady 1 -relief raised
        pack .$x$y.buttons.$sides -expand yes
        menu .$x$y.buttons.$sides.menu -tearoff 0

        set i 0
        foreach nkind {a s l S z t 1 - 0 r L} kindname { 
	    ArcTan Sinus LogSig Saturation OverZero Sawtooth Plus1 Minus1
	    Zero SquareRoot Log} {
	    .$x$y.buttons.$sides.menu add radiobutton -label $kindname \
    	    -variable param$sides$x$y -value $nkind \
	    -command "dupdate $x $y $sides $sidenames $kindname"
	    if {$nkind == [set param$sides$x$y]} {
		.$x$y.buttons.$sides configure -text "$sidenames: $kindname"}
	}
    }
}

# Half
proc half {x y} {
    global kind$x$y TransId
    wm title .$x$y "$x$y Half"
    label .$x$y.label -width 24 -text {ParaDir [dB]}
    scale .$x$y.scale -orient vertical -length 100 -from 20 -to -100 \
        -sliderlength 24 -tickinterval 20 -variable param$x$y \
	-command "puts -nonewline $TransId \"Box $x $y [set kind$x$y] \"
	    puts $TransId "
    pack .$x$y.label .$x$y.scale 
}

# Modulator
proc modulator {x y} {
    global paramk$x$y paramw$x$y paramt1$x$y
    wm title .$x$y "$x$y Modulator"
    label .$x$y.label -width 82 -text {Modulator type     Waveform        Modulation depth [%]      \
	Period [sixteenths]        ParaDir [dB]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    
    menubutton .$x$y.scales.kind -direction right -width 9 \
        -menu .$x$y.scales.kind.menu
    .$x$y.scales.kind configure -pady 1 -relief raised
    pack .$x$y.scales.kind -side left -padx 10
    menu .$x$y.scales.kind.menu -tearoff 0

    foreach nkind {a f p} kindname {Amplitude Frequency Phase} {
	.$x$y.scales.kind.menu add radiobutton -label $kindname \
    	    -variable paramk$x$y -value $nkind \
	    -command "mupdate $x $y kind $kindname; ableM $x $y; flushmod $x $y"
	if {$nkind == [set paramk$x$y]} {
	    .$x$y.scales.kind configure -text "$kindname"}
    }

    menubutton .$x$y.scales.wave -direction right -width 9 \
        -menu .$x$y.scales.wave.menu
    .$x$y.scales.wave configure -pady 1 -relief raised
    pack .$x$y.scales.wave -side left -padx 10
    menu .$x$y.scales.wave.menu -tearoff 0

    foreach nwave {s t} wavename {Sinus Triangle} {
	.$x$y.scales.wave.menu add radiobutton -label $wavename \
    	    -variable paramw$x$y -value $nwave \
	    -command "mupdate $x $y wave $wavename; flushmod $x $y"
	if {$nwave == [set paramw$x$y]} {
	    .$x$y.scales.wave configure -text "$wavename"}
    }

    scale .$x$y.scales.scaled -orient vertical -length 100 -from 100 -to 0 \
	-sliderlength 24 -tickinterval 20 -variable paramd$x$y \
	-command "flushmod $x $y; set dump"
    pack .$x$y.scales.scaled -side left -padx 40
    scale .$x$y.scales.scalet1 -orient vertical -length 100 -from 200 -to 0 \
	-sliderlength 24 -tickinterval 40 -variable paramsix1$x$y \
	-command "expt $x $y 1; flushmod $x $y; set dump"
    pack .$x$y.scales.scalet1 -side left
    scale .$x$y.scales.scalep -orient vertical -length 100 -from 20 -to -40 \
	-sliderlength 24 -tickinterval 20 -variable paramp$x$y \
	-command "flushmod $x $y; set dump"
    pack .$x$y.scales.scalep -side right -padx 10
    ableM $x $y
}

# Delay
proc delay {x y} {
    wm title .$x$y "$x$y Delay"
    label .$x$y.label -width 76 -text {Predelay [m]      X1 [m]          \
	X2 [m]              R1 [dB]             R2 [dB]         Output [dB]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    scale .$x$y.scales.scalepre -orient vertical -length 100 -from 90 -to 0 \
	-sliderlength 24 -tickinterval 20 -variable parampre$x$y \
	-command "flushdel $x $y; set dump"
    scale .$x$y.scales.scalex1 -orient vertical -length 100 -from 90 -to 1 \
	-sliderlength 24 -tickinterval 20 -variable paramx1$x$y \
	-command "flushdel $x $y; set dump"
    scale .$x$y.scales.scalex2 -orient vertical -length 100 -from 90 -to 1 \
	-sliderlength 24 -tickinterval 20 -variable paramx2$x$y \
	-command "flushdel $x $y; set dump"
    scale .$x$y.scales.scaler1 -orient vertical -length 100 -from 0 -to -40 \
	-sliderlength 24 -tickinterval 10 -variable paramr1$x$y \
	-command "flushdel $x $y; set dump"
    scale .$x$y.scales.scaler2 -orient vertical -length 100 -from 0 -to -40 \
	-sliderlength 24 -tickinterval 10 -variable paramr2$x$y \
	-command "flushdel $x $y; set dump"
    scale .$x$y.scales.scaleout -orient vertical -length 100 -from 20 -to -40 \
	-sliderlength 24 -tickinterval 20 -variable paramout$x$y \
	-command "flushdel $x $y; set dump"
    pack .$x$y.scales.scalepre .$x$y.scales.scalex1 .$x$y.scales.scalex2 \
	 .$x$y.scales.scaler1 .$x$y.scales.scaler2 .$x$y.scales.scaleout \
	-side left -expand yes
}

# hall
proc hall {x y} {
    wm title .$x$y "$x$y Hall"
    label .$x$y.label -width 102 -text {Predelay [m]          X [m]              \
	Y [m]               Z [m]            Rx [dB]           \
	Ry [dB]             Rz [dB]         Output [dB]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    scale .$x$y.scales.scalepre -orient vertical -length 100 -from 90 -to 0 \
	-sliderlength 24 -tickinterval 20 -variable parampre$x$y \
	-command "flushhall $x $y; set dump"
    scale .$x$y.scales.scalex1 -orient vertical -length 100 -from 180 -to 1 \
	-sliderlength 24 -tickinterval 30 -variable paramx1$x$y \
	-command "flushhall $x $y; set dump"
    scale .$x$y.scales.scalex2 -orient vertical -length 100 -from 180 -to 1 \
	-sliderlength 24 -tickinterval 30 -variable paramx2$x$y \
	-command "flushhall $x $y; set dump"
    scale .$x$y.scales.scalex3 -orient vertical -length 100 -from 180 -to 1 \
	-sliderlength 24 -tickinterval 30 -variable paramx3$x$y \
	-command "flushhall $x $y; set dump"
    scale .$x$y.scales.scaler1 -orient vertical -length 100 -from -10 -to -40 \
	-sliderlength 24 -tickinterval 10 -variable paramr1$x$y \
	-command "flushhall $x $y; set dump"
    scale .$x$y.scales.scaler2 -orient vertical -length 100 -from -10 -to -40 \
	-sliderlength 24 -tickinterval 10 -variable paramr2$x$y \
	-command "flushhall $x $y; set dump"
    scale .$x$y.scales.scaler3 -orient vertical -length 100 -from -10 -to -40 \
	-sliderlength 24 -tickinterval 10 -variable paramr3$x$y \
	-command "flushhall $x $y; set dump"
    scale .$x$y.scales.scaleout -orient vertical -length 100 -from 20 -to -40 \
	-sliderlength 24 -tickinterval 20 -variable paramout$x$y \
	-command "flushhall $x $y; set dump"
    pack .$x$y.scales.scalepre .$x$y.scales.scalex1 .$x$y.scales.scalex2 \
	.$x$y.scales.scalex3 .$x$y.scales.scaler1 .$x$y.scales.scaler2 \
	.$x$y.scales.scaler3 .$x$y.scales.scaleout -side left -expand yes
}

# reverb
proc reverb {x y} {
    wm title .$x$y "$x$y Reverb"
    label .$x$y.label -width 96 -text {Order       Filter length [m]   \
	Predelay [m]   Decay time [m]   Feedback time [m]   \
	Feedback [dB]    Output [dB]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    scale .$x$y.scales.scaleord -orient vertical -length 100 -from 100 -to 4 \
	-sliderlength 24 -tickinterval 20 -variable paramord$x$y \
	-command "flushrev $x $y; set dump"
    scale .$x$y.scales.scalex1 -orient vertical -length 100 -from 180 -to 1 \
	-sliderlength 24 -tickinterval 30 -variable paramx1$x$y \
	-command "flushrev $x $y; set dump"
    scale .$x$y.scales.scalepre -orient vertical -length 100 -from 90 -to 0 \
	-sliderlength 24 -tickinterval 20 -variable parampre$x$y \
	-command "flushrev $x $y; set dump"
    scale .$x$y.scales.scalet1 -orient vertical -length 100 -from 180 -to 1 \
	-sliderlength 24 -tickinterval 30 -variable paramt1$x$y \
	-command "flushrev $x $y; set dump"
    scale .$x$y.scales.scalex2 -orient vertical -length 100 -from 180 -to 1 \
	-sliderlength 24 -tickinterval 30 -variable paramx2$x$y \
	-command "flushrev $x $y; set dump"
    scale .$x$y.scales.scaler1 -orient vertical -length 100 -from 0 -to -40 \
	-sliderlength 24 -tickinterval 10 -variable paramr1$x$y \
	-command "flushrev $x $y; set dump"
    scale .$x$y.scales.scaleout -orient vertical -length 100 -from 20 -to -40 \
	-sliderlength 24 -tickinterval 10 -variable paramout$x$y \
	-command "flushrev $x $y; set dump"
    pack .$x$y.scales.scaleord -side left
    pack .$x$y.scales.scalex1 .$x$y.scales.scalepre .$x$y.scales.scalet1 \
	.$x$y.scales.scalex2 .$x$y.scales.scaler1 -side left -expand yes
    pack  .$x$y.scales.scaleout \
	-side left -padx 8
}

# Compressor
proc compressor {x y} {
    wm title .$x$y "$x$y Compressor"
    label .$x$y.label -width 62 -text {Threshold [dB]   Compression [dB / 10 dB]   \
	Attack [ms]   Decay [ms]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    
    scale .$x$y.scales.scalel -orient vertical -length 100 -from 0 -to -80 \
	-sliderlength 24 -tickinterval 20 -variable paramth$x$y \
	-command "flushcomp $x $y; set dump"
    pack .$x$y.scales.scalel -side left -padx 10
    scale .$x$y.scales.scales -orient vertical -length 100 -from 10 -to 0 \
	-sliderlength 24 -tickinterval 2 -variable paramr$x$y \
	-command "flushcomp $x $y; set dump"
    pack .$x$y.scales.scales -side left -padx 50
    scale .$x$y.scales.scalet1 -orient vertical -length 100 -from 50 -to 1 \
	-sliderlength 24 -tickinterval 10 -variable paramt1$x$y \
	-command "flushcomp $x $y; set dump"
    pack .$x$y.scales.scalet1 -side left -padx 10
    scale .$x$y.scales.scalet2 -orient vertical -length 100 -from 200 -to 1 \
	-sliderlength 24 -tickinterval 40 -variable paramt2$x$y \
	-command "flushcomp $x $y; set dump"
    pack .$x$y.scales.scalet2 -side left -padx 10
}

# Quant
proc quant {x y} {
    global kind$x$y TransId
    wm title .$x$y "$x$y Quantizer"
    label .$x$y.label -width 24 -text {SNR worsening [dB]}
    scale .$x$y.scale -orient vertical -length 100 -from 80 -to 1 \
        -sliderlength 24 -tickinterval 20 -variable param$x$y \
	-command "puts -nonewline $TransId \"Box $x $y [set kind$x$y] \"
	    puts $TransId "
    pack .$x$y.label .$x$y.scale 
}

# Noise Gate
proc noisegate {x y} {
    wm title .$x$y "$x$y Noise Gate"
    label .$x$y.label -width 58 -text {Threshold [dB]   Power saturation [dB]   \
	Attack [ms]   Decay [ms]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    
    scale .$x$y.scales.scalel -orient vertical -length 100 -from -20 -to -100 \
	-sliderlength 24 -tickinterval 20 -variable paramth$x$y \
	-command "flushng $x $y; set dump"
    pack .$x$y.scales.scalel -side left
    scale .$x$y.scales.scales -orient vertical -length 100 -from 20 -to 1 \
	-sliderlength 24 -tickinterval 5 -variable params$x$y \
	-command "flushng $x $y; set dump"
    pack .$x$y.scales.scales -side left -padx 40
    scale .$x$y.scales.scalet1 -orient vertical -length 100 -from 50 -to 1 \
	-sliderlength 24 -tickinterval 10 -variable paramt1$x$y \
	-command "flushng $x $y; set dump"
    pack .$x$y.scales.scalet1 -side left -padx 10
    scale .$x$y.scales.scalet2 -orient vertical -length 100 -from 200 -to 1 \
	-sliderlength 24 -tickinterval 40 -variable paramt2$x$y \
	-command "flushng $x $y; set dump"
    pack .$x$y.scales.scalet2 -side left -padx 10
}

# SpecSub
proc specsub {x y} {
    wm title .$x$y "$x$y Spectral Subtraction"
    label .$x$y.label -width 64 -text {Threshold [dB]   Noise estimation time [16ths]  \
	Estimation end [16ths]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    
    scale .$x$y.scales.scaleth -orient vertical -length 100 -from -10 -to -90 \
	-sliderlength 24 -tickinterval 20 -variable paramth$x$y \
	-command "flushss $x $y; set dump"
    pack .$x$y.scales.scaleth -side left -padx 24	
    scale .$x$y.scales.scalet1 -orient vertical -length 100 -from 200 -to 40 \
	-sliderlength 24 -tickinterval 40 -variable paramsix1$x$y \
	-command "expt $x $y 1; flushss $x $y; set dump"
    place .$x$y.scales.scalet1 -relx .3
    scale .$x$y.scales.scalet2 -orient vertical -length 100 -from 200 -to 0 \
	-sliderlength 24 -tickinterval 40 -variable paramsix2$x$y \
	-command "expt $x $y 2; flushss $x $y; set dump"
    place .$x$y.scales.scalet2 -relx .65
    ableSs $x $y
    checkbutton .$x$y.scales.disable -text Infinite -relief raised \
	-variable paramd$x$y -command "ableSs $x $y; flushss $x $y"
    pack .$x$y.scales.disable -side right -padx 16
}

# Sine Wave Generator
proc singen {x y} {
    wm title .$x$y "$x$y Sine Wave Generator"
    label .$x$y.label -width 36 -text {Frequency [halftones]      ParaDir [dB]}
    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
    scale .$x$y.scales.scalef -orient vertical -length 100 -from 120 -to 0 \
	-sliderlength 24 -tickinterval 20 -variable paramhts$x$y \
	-command "expf $x $y; flushsin $x $y; set dump"
    pack .$x$y.scales.scalef -side left
    scale .$x$y.scales.scalep -orient vertical -length 100 -from 20 -to -100 \
	-sliderlength 24 -tickinterval 20 -variable paramp$x$y \
	-command "flushsin $x $y; set dump"
    pack .$x$y.scales.scalep -side right -padx 10
}

# White Noise
proc wnoise {x y} {
    global kind$x$y TransId
    wm title .$x$y "$x$y White Noise"
    label .$x$y.label -width 24 -text {ParaDir [dB]}
    scale .$x$y.scale -orient vertical -length 100 -from 20 -to -100 \
	-sliderlength 24 -tickinterval 20 -variable param$x$y \
	-command "puts -nonewline $TransId \"Box $x $y [set kind$x$y] \"
	    puts $TransId "
    pack .$x$y.label .$x$y.scale 
}


# Output switch - settings
proc outSwitch {} {
    set x 10
    set y 1
    wm title .$x$y "Output Switch"
    label .$x$y.label -width 24 -text {Switching time [16ths]}

    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
        
    scale .$x$y.scales.scalet1 -orient vertical -length 100 -from 200 -to 0 \
	-sliderlength 24 -tickinterval 40 -variable paramsix1$x$y \
	-command "expt $x $y 1; flushsw t; set dump"
    pack .$x$y.scales.scalet1 -side left -padx 16
}

# VU meters - settings
proc vuSet {} {
    set x 10
    set y 0
    wm title .$x$y "VU meters"
    label .$x$y.label -width 44 -text {Power estimation time [16ths]  \
	Refresh [fragments]}

    frame .$x$y.scales
    pack .$x$y.label .$x$y.scales -fill x
        
    scale .$x$y.scales.scalet1 -orient vertical -length 100 -from 200 -to 0 \
	-sliderlength 24 -tickinterval 40 -variable paramsix1$x$y \
	-command "expt $x $y 1; flushvu; set dump"
    pack .$x$y.scales.scalet1 -side left -padx 32
    scale .$x$y.scales.scalet2 -orient vertical -length 100 -from 200 -to 1 \
	-sliderlength 24 -tickinterval 40 -variable paramt2$x$y \
	-command "flushvu; set dump"
    pack .$x$y.scales.scalet2 -side right -padx 16
}

# Audio settings
proc audioSet {} {
    set x 10
    set y 2
    wm title .$x$y "Audio Settings"

    label .$x$y.label -width 48 -text {Sampling frequency [Hz]    \
	Fragment length [samples]}

    frame .$x$y.buttons
    pack .$x$y.label .$x$y.buttons -fill x

    frame .$x$y.buttons.freq
    pack .$x$y.buttons.freq -side left -fill y
    
    frame .$x$y.buttons.len1
    frame .$x$y.buttons.len2
    
    pack .$x$y.buttons.len1 .$x$y.buttons.len2 -side left -pady 4 -fill y
    
    foreach i {44100 48000} {
        radiobutton .$x$y.buttons.freq.$i -text $i -relief raised \
	    -variable fSamp -value $i \
	    -command "flushaud"
	pack .$x$y.buttons.freq.$i -padx 48 -expand yes
    }

    foreach i {6 7 8} {
        radiobutton .$x$y.buttons.len1.$i -text [expr 1<<$i-1] -relief raised \
	    -variable bufSize -value $i \
	    -command "flushaud"
	pack .$x$y.buttons.len1.$i -padx 32
    }
    
    foreach i {9 10 11} {
        radiobutton .$x$y.buttons.len2.$i -text [expr 1<<$i-1] -relief raised \
	    -variable bufSize -value $i \
	    -command "flushaud"
	pack .$x$y.buttons.len2.$i
    }
    
}

# About box
proc aboutBox {} {
    set x 10
    set y 3
    wm title .$x$y "About ExEf"
    
    label .$x$y.logo -image image1a
    label .$x$y.label -font {Helvetica 18} -text {Extreme Effect}
    label .$x$y.by -text {by Tom Olexa 2001} -pady 16
    label .$x$y.help -text {with help from Vaclav Hanzl} -padx 16
    pack .$x$y.logo .$x$y.label .$x$y.by .$x$y.help
}    

# Recording setting
proc recSet {} {
    set x 10
    set y 8
    wm title .$x$y "Recording setting"

    label .$x$y.label -width 24 -text {Fragments to save at once}
    pack .$x$y.label

    frame .$x$y.buttons1
    frame .$x$y.buttons2
    
    pack .$x$y.buttons1 .$x$y.buttons2 -side left -pady 4
    
    foreach i {3 4 5} {
        radiobutton .$x$y.buttons1.$i -text [expr 1<<$i] -relief raised \
	    -variable params108 -value $i
	pack .$x$y.buttons1.$i -padx 28
    }
    
    foreach i {6 7 8} {
        radiobutton .$x$y.buttons2.$i -text [expr 1<<$i] -relief raised \
	    -variable params108 -value $i
	pack .$x$y.buttons2.$i
    }

}

# File selection dialog
proc fileSel {m} {
    global dirName fileName completeName
    set completeName [file join $dirName $fileName]
    set x 10
    set y 4

    destroy .104

    toplevel .$x$y 
    wm resizable .$x$y 0 0
    
    switch $m {
	l {wm title .$x$y "Load Configuration"}
	s {wm title .$x$y "Save Configuration"}
	lchan {wm title .$x$y "Load Active Channel"}
	schan {wm title .$x$y "Save Active Channel"}
	r {wm title .$x$y "Save Audio"}
    }
    
    label .$x$y.fileLabel -text "Filename:"
    entry .$x$y.fileName -width 48 -textvariable completeName
    label .$x$y.dirsFilesLabel -text "Dirs:                                      Files:" \
	-anchor w
    frame .$x$y.boxes
    pack .$x$y.fileLabel .$x$y.fileName .$x$y.dirsFilesLabel .$x$y.boxes \
	-expand 1 -fill x
    bind .$x$y.fileName <Return> "fileOrDir $m"
    bind .$x$y.fileName <KP_Enter> "fileOrDir $m"

    listbox .$x$y.boxes.dirs -width 20 -height 10 \
	-yscrollcommand ".$x$y.boxes.dscroll set"
    scrollbar .$x$y.boxes.dscroll -command ".$x$y.boxes.dirs yview"
    bind .$x$y.boxes.dirs <Double-1> "chDir %x %y"

    listbox .$x$y.boxes.files -width 20 -height 10 \
	-yscrollcommand ".$x$y.boxes.fscroll set"
    scrollbar .$x$y.boxes.fscroll -command ".$x$y.boxes.files yview"
    bind .$x$y.boxes.files <Double-1> "getFileName $m 1 %x %y"
    bind .$x$y.boxes.files <Button-1> "getFileName $m 0 %x %y"    
    pack .$x$y.boxes.dirs .$x$y.boxes.dscroll -side left -fill y
    pack .$x$y.boxes.fscroll .$x$y.boxes.files -side right -fill y
    
    loadDir
} 
   
# VU meters
proc vuMeter {upDown vulabel} {
    global kind100 paramd100
    set kind100 vu

    frame $upDown -relief raised -borderwidth 3
    pack $upDown -fill x

    frame $upDown.top
    pack $upDown.top -fill x

    label $upDown.top.vulabel -text "$vulabel VU meter"
    pack $upDown.top.vulabel -side left -expand 1

    button $upDown.top.vuon -width 3 -text "Off" -font {Helvetica 10} -pady 0 \
	-command "vuable"

    pack $upDown.top.vuon -side right -expand 1

    button $upDown.top.vuopt -text "Settings" -font {Helvetica 10} -pady 0 \
	-command "setEffect 10 0"
    pack $upDown.top.vuopt -side right -expand 1 -pady 3

    canvas $upDown.vubar -width 400 -height 34
    pack $upDown.vubar -side bottom -expand 1

    $upDown.vubar create line 30 15 30 18 300 18 300 15 -width 1 -fill grey70

    for {set i 0} {$i < 10} {incr i} {
	set x [expr $i*30+30]
        set db [expr $i*10-90]
	$upDown.vubar create line ${x} 16 ${x} 18 -width 1 -fill grey70
        $upDown.vubar create text $x 28 -text $db -font {Helvetica 8} \
	    -fill grey70
    }

    $upDown.vubar create text 315 28 -text dB -font {Helvetica 8} \
	-fill grey70
    $upDown.vubar create text 355 20 -text Over -font {Helvetica 8} \
	-fill grey70
}

# Output switch - foot
proc footSwitch {} {
    global outChan outChPrev
    set outChan $outChPrev
    flushsw c
}

# Output switch - manual
proc manSwitch {i} {
    puts $i    
    global outChan
    set outChan $i
    flushsw c
}

# Setting an effect
proc setEffect {x y} {
    global kind$x$y
    set kind [set kind$x$y]
    if {[winfo exists .$x$y] == 0} {
	toplevel .$x$y 
	wm resizable .$x$y 0 0
        switch $kind {
	    g {gain $x $y}
	    p {pass $x $y}
	    b {biquad $x $y}
	    d {distort $x $y}
	    h {half $x $y}
	    m {modulator $x $y}	    
	    D {delay $x $y}
	    H {hall $x $y}
	    R {reverb $x $y}
	    C {compressor $x $y}
	    q {quant $x $y}
	    n {noisegate $x $y}
	    S {specsub $x $y}
	    s {singen $x $y}
	    w {wnoise $x $y}

	    switch {outSwitch}
	    vu {vuSet}
	    audio {audioSet}
	    about {
		aboutBox
		return
	    }
	    savewave {recSet}
	    warning {
		WarnCng
		return
	    }
	    error {
		LoadError
		return
	    }	
	}
	winChanged
    } else {
	wm withdraw .$x$y
	wm deiconify .$x$y
    }	
}

# InsertButton
proc instButton {} {
    foreach x {0 1 2 3} {
        button .effects.matrix.$x -font {Helvetica 8} -text "Insert a Box" \
	    -command "insertBox $x 0"
	place .effects.matrix.$x -relx [expr 0.25*$x] -y 0 \
	    -relwidth .25 -height 18
    }
}        

# Checking a column
proc checkCol {x} {
    global maxy$x
    if {[set maxy$x] == 9} {
	for {set i 0} {$i <= 9} {incr i} {
	    .effects.matrix.$x$i.buttons.kind.menu entryconfigure 17 \
		-state disabled
	    .effects.matrix.$x$i.buttons.kind.menu entryconfigure 18 \
		-state disabled	
	}
    }
    if {[set maxy$x] == 8} {
	for {set i 0} {$i <= 8} {incr i} {
	    .effects.matrix.$x$i.buttons.kind.menu entryconfigure 17 \
		-state normal
	    .effects.matrix.$x$i.buttons.kind.menu entryconfigure 18 \
		-state normal	
	}
    }
}    	        

# Inserting a box
proc insertBox {x y} { 
    global TransId maxy$x
    set i [set maxy$x]
    incr i
    global kind$x$i param$x$i
    for {set i [set maxy$x]} {$i >= $y} {incr i -1} {
        global kind$x$i param$x$i
        set ii [expr $i+1]
        set param$x$ii [set param$x$i]
        set kind$x$ii [set kind$x$i]
        createBox .effects.matrix.$x$ii $x $ii [set kind$x$ii]
        destroy .$x$i
        destroy .effects.matrix.$x$i
    }
    incr maxy$x
    puts $TransId "InsertBox $x $y"
    winChanged
}    
     
# Removing a box
proc removeBox {name x y} {
    global TransId maxy$x
    global kind$x$y param$x$y
    for {set i $y} {$i < [set maxy$x]} {incr i} {
	set ii [expr $i+1]
	global kind$x$ii param$x$ii
	destroy .$x$i
	set param$x$i [set param$x$ii]
	set kind$x$i [set kind$x$ii]
	destroy .effects.matrix.$x$i
	createBox .effects.matrix.$x$i $x $i [set kind$x$i]
    }
    destroy .$x$i
    destroy .effects.matrix.$x$i
    incr maxy$x -1
    checkCol $x
    puts $TransId "RemoveBox $x $y"
    winChanged
}    

# Changing a box
proc changeBox {name x y} {
    global TransId kind$x$y changed fileName
    destroy .$x$y
    destroy $name
    puts $TransId "ChangeBox $x $y [set kind$x$y]"
    winChanged
}


# Creating a box
proc createBox {name x y kind} {
    global param$x$y paraml$x$y paramr$x$y paramp$x$y paramhts$x$y \
	paramf$x$y paramk$x$y paramsix1$x$y paramsix2$x$y \
	paramt1$x$y paramt2$x$y paramth$x$y paramd$x$y paramq$x$y \
	parampre$x$y paramout$x$y paramx1$x$y paramx2$x$y paramx3$x$y \
	paramr1$x$y paramr2$x$y paramr3$x$y params$x$y paramw$x$y \
	paramord$x$y
	
    frame $name -relief sunken -borderwidth 2
    place $name -relx [expr 0.25*$x] -y [expr 40*$y] \
        -relwidth .25 -height 40
    frame $name.buttons
    pack $name.buttons -side left -expand yes
    
    menubutton $name.buttons.kind -font {Helvetica 8} -text "Kind" \
	-direction right -menu $name.buttons.kind.menu
    $name.buttons.kind configure -pady 1 -relief raised
    pack $name.buttons.kind 
    menu $name.buttons.kind.menu -tearoff 0

    foreach nkind {g p b d h m D H R C q n S s w c} kindname { 
	Gain Pass Biquad Distort Half Modulator Delay Hall Reverb Compressor \
	Quantizer "Noise Gate" "Spectral Subtraction" "Sine Wave" "White Noise" \
	"Copy to next column"} {
    $name.buttons.kind.menu add radiobutton -label $kindname \
        -variable kind$x$y -value $nkind \
	-command "changeBox $name $x $y"
    }
    if {$x == 3} {
	$name.buttons.kind.menu entryconfigure 15 -state disabled
    }
    
    $name.buttons.kind.menu add separator    
    $name.buttons.kind.menu add command -label "Insert a box before" \
	-command "insertBox $x $y"
    $name.buttons.kind.menu add command -label "Insert a box after" \
	-command "insertBox $x [expr $y+1]"
    $name.buttons.kind.menu add command -label "Remove the box" \
	-command "removeBox $name $x $y"
    	
    if {$kind != "c"} {
    button $name.buttons.settings -font {Helvetica 8} -text "Settings" \
	-command "setEffect $x $y"
    $name.buttons.settings configure -pady 0
    pack $name.buttons.settings
    }

    canvas $name.pict -width 32 -height 32 -borderwidth 2 -relief raised
    pack $name.pict -side right

    switch $kind {
	g {$name.pict create poly 11 10 27 18 11 26 \
	    -outline green2 -fill green4}
	p {$name.pict create line 5 10 14 10 30 30 \
	    -fill green
	    scan [set param$x$y] "%s %d %d" paramk$x$y freq paramp$x$y
	    set paramhts$x$y [logf $freq]
	    set paramf$x$y $freq
	}
	b {$name.pict create line 5 18 10 18 14 10 16 20 20 30 34 30 \
	    -fill green
	    scan [set param$x$y] "%s %d %d %d" paramk$x$y freq paramq$x$y paramp$x$y
	    set paramhts$x$y [logf $freq]
	    set paramf$x$y $freq
	    }
	d {$name.pict create line 5 30 13 30 25 6 34 6 \
	    -fill green
	    scan [set param$x$y] "%s %s %d" paraml$x$y paramr$x$y paramp$x$y
	}
	h {$name.pict create poly 8 10 30 10 19 28 \
	    -outline green2 -fill green4}
	m {$name.pict create line 7 10 10 5 15 15 20 5 25 15 30 5 33 10 \
	    -fill green -smooth yes
	    scan [set param$x$y] "%s %s %d %d %d" paramk$x$y paramw$x$y paramd$x$y tau paramp$x$y
	    set paramsix1$x$y [logt $tau]
	    set paramt1$x$y $tau
	}
	D {$name.pict create line 5 5 10 28 15 10 20 24 25 13 30 22 35 15 \
	    -fill green
	    scan [set param$x$y] "%d %d %d %d %d %d" parampre$x$y paramx1$x$y \
		paramx2$x$y paramr1$x$y paramr2$x$y paramout$x$y
	}
	H {$name.pict create line 5 5 10 28 14 10 17 24 19 13 21 22 23 15 \
	    25 20 27 17 29 19 31 17 33 19 34 18 \
	    -fill green
	    scan [set param$x$y] "%d %d %d %d %d %d %d %d" parampre$x$y \
		paramx1$x$y paramx2$x$y paramx3$x$y paramr1$x$y \
		paramr2$x$y paramr3$x$y paramout$x$y
	}
	R {$name.pict create line 5 5 9 28 12 13 17 20 19 11 21 22 23 15 \
	    25 17 27 15 35 15 \
	    -fill green
	    scan [set param$x$y] "%d %d %d %d %d %d %d" paramord$x$y \
		paramx1$x$y parampre$x$y paramt1$x$y paramx2$x$y \
		paramr1$x$y paramout$x$y
	}
	C {$name.pict create line 5 30 25 10 34 10 \
	    -fill green
	    scan [set param$x$y] "%d %d %d %d" paramth$x$y paramr$x$y paramt1$x$y \
		paramt2$x$y
	}    
	q {$name.pict create line 5 28 14 28 14 18 24 18 24 8 33 8 \
	    -fill green}
	n {$name.pict create line 3 3 15 10 15 28 3 32 -fill green
	    $name.pict create line 34 3 22 10 22 28 34 32 -fill green
	    scan [set param$x$y] "%d %d %d %d" paramth$x$y params$x$y \
		paramt1$x$y paramt2$x$y
	}
	S {$name.pict create line 5 30 10 30 12 5 14 30 24 30 26 5 \
	    28 30 33 30 -fill green
	    scan [set param$x$y] "%d %d %d" paramth$x$y tau1 tau2
	    set paramsix1$x$y [logt $tau1]
	    if {$tau2 > 0} { 
	        set paramsix2$x$y [logt $tau2]
		set paramd$x$y 0
	    } else {
		set paramd$x$y 1
	    }
	    set paramt1$x$y $tau1
	    set paramt2$x$y $tau2
	}	    
	s {$name.pict create line 5 18 12 8 \
	    26 28 33 18 -fill green -smooth yes
	    scan [set param$x$y] "%d %d" freq paramp$x$y
	    set paramhts$x$y [logf $freq]
	    set paramf$x$y $freq
        }
	w {$name.pict create line 5 18 9 7 13 30 17 10 \
	    21 20 25 13 29 27 33 15 -fill green -smooth yes}    

	c {$name.pict create line 5 30 20 1 30 20 \
	    -fill green -smooth yes
	    $name.pict create line 25 18 30 20 32 15 \
	    -fill green
	}
    }
}


# Init global vars
puts "\nExEf - the ultimate effect engine"
puts "ExEf GUI - Copyright (C) 2001 Tom Olexa"
set lastInOver 0
set lastOutOver 0
set paramd100 1
foreach i {0 1 2 3} {
    set maxy$i -1
}
set fSamp 44100
set bufSize 11
set paramt1100 1
set paramt2100 100
set paramt1101 1
set outChan 0
set outChPrev 0
set outChdel 0
set changed 0
set continue 0

tk_setPalette background Black activeBackground Yellow3 activeForeground Black \
    foreground Green troughColor Gray30 disabledForeground Green4 \
    selectColor Green
wm protocol . WM_DELETE_WINDOW {
    if {$changed} {
        setEffect 10 6
	tkwait window .106
    } else {
	destroy .
    }
    if {$continue} {
        destroy .
    }
}
wm title . "Extreme Effect"
wm resizable . 0 0

# Main button
set kind102 audio
set kind103 about
set kind104 loadsave
set kind106 warning
set kind107 error
set kind108 savewave
image create photo image1a -file /usr/share/ExEf/ExEflogo.gif

frame .exefbutton -relief raised -borderwidth 3
pack .exefbutton -fill x

menubutton .exefbutton.exef -image image1a -activebackground Yellow4 \
    -direction right -menu .exefbutton.exef.menu
pack .exefbutton.exef -pady 4  

menu .exefbutton.exef.menu -tearoff 0

.exefbutton.exef.menu add command -label "New Matrix" \
    -command "NewMatrix"
.exefbutton.exef.menu add command -label "Load Configuration" \
    -command "fileSel l"
.exefbutton.exef.menu add command -label "Save Configuration" \
    -command "fileSel s"
.exefbutton.exef.menu add separator
.exefbutton.exef.menu add command -label "Load Active Channel" \
    -command "fileSel lchan"
.exefbutton.exef.menu add command -label "Save Active Channel" \
    -command "fileSel schan"
.exefbutton.exef.menu add separator          
.exefbutton.exef.menu add command -label "Audio settings" \
    -command "setEffect 10 2"
.exefbutton.exef.menu add separator 
.exefbutton.exef.menu add command -label "About" \
    -command "setEffect 10 3"
    
# Input VU meter
set upDown .invu
vuMeter $upDown Input
set topBarId [.invu.vubar create rectangle 30 2 30 10 -width 1 \
    -fill green4 -outline green2]
set topLightId [.invu.vubar create rectangle 340 2 370 10 -width 1 \
    -outline green2]

# Effect matrix
frame .effects -borderwidth 3 -relief raised
pack .effects -fill x
label .effects.label -text "Effect Matrix"
pack .effects.label
frame .effects.names
pack .effects.names -fill x
foreach i {0 1 2 3} {
    entry .effects.names.$i -width 10 -justify center \
    -textvariable name$i -font {Helvetica 10}
    pack .effects.names.$i -side left -expand 1
    bind .effects.names.$i <Return> "focus ."
    bind .effects.names.$i <KP_Enter> "focus ."
}
frame .effects.matrix -height 400
pack .effects.matrix -fill x
instButton

# Output switch
frame .switch -borderwidth 3 -relief raised
pack .switch -fill x

frame .switch.top
pack .switch.top -fill x

label .switch.top.label -text "Output switch"
pack .switch.top.label -side left -expand 1

set kind101 switch
button .switch.top.opt -text "Settings" -font {Helvetica 10} \
    -pady 0 -command "setEffect 10 1"
pack .switch.top.opt -side right -expand 1 -pady 3

foreach i {0 1 2 3} {
    radiobutton .switch.channel$i -text "Channel $i" -relief raised -value $i \
	-font {Helvetica 10} -variable outChan \
	-command "flushsw c"
    pack .switch.channel$i -side left -expand 1
}
bind all <space> {footSwitch}
bind all <KeyPress-grave> {manSwitch 0}
bind all <KeyPress-0> {manSwitch 0}
bind all <KeyPress-1> {manSwitch 1}
bind all <KeyPress-2> {manSwitch 2}
bind all <KeyPress-3> {manSwitch 3}
bind all <KP_Insert> {manSwitch 0}
bind all <KP_End> {manSwitch 1}
bind all <KP_Down> {manSwitch 2}
bind all <KP_Next> {manSwitch 3}

# Output VU meter
set upDown .outvu
vuMeter $upDown Output
set bottomBarId [.outvu.vubar create rectangle 30 2 30 10 -width 1 \
 -fill green4 -outline green2]
set bottomLightId [.outvu.vubar create rectangle 340 2 370 10 -width 1 \
    -outline green2]

# Recording unit
frame .record -borderwidth 3 -relief raised
pack .record -fill x

frame .record.top
pack .record.top -fill x

label .record.top.label -text "Recording Unit"
pack .record.top.label -side left -expand 1

label .record.top.status -text "Stopped" -font {Helvetica 10} -width 9
pack .record.top.status -side left -expand 1

label .record.top.fname -text "untitled.wav" -textvariable paramn108 \
    -font {Helvetica 10} -width 12 -anchor e
pack .record.top.fname -side left -expand 1

button .record.top.set -text "Settings" -font {Helvetica 10} -pady 0 \
    -command "setEffect 10 8"
pack .record.top.set -side left -expand 1 -pady 3

button .record.rec -text "Record" -font {Helvetica 10} -pady 0 \
    -foreground yellow -command "fileSel r"
pack .record.rec -side left -expand 1 -fill x -padx 2

button .record.pause -text "Pause" -font {Helvetica 10} -pady 0 \
    -command "recording 3 1" -state disabled
pack .record.pause -side left -expand 1 -fill x

button .record.stop -text "Stop" -font {Helvetica 10} -pady 0 \
    -command "recording 0 1" -state disabled
pack .record.stop -side right -expand 1 -fill x -padx 2


# Start realtime module
if {$argc} {
    exec ExEfDSP -i $argv &
    set fileName $argv
} else {
    exec ExEfDSP -i &
    set fileName .ExEfrc
}        

# Opening pipes
initPipes 

cd
initDir
set dirName [pwd]

# Receiving and evaluating commands 
fileevent $ReceivId readable {
    gets $ReceivId inp
    if {[eof $ReceivId] == 1} {
	exit
    }	
    scan $inp "%s" cmd
    switch $cmd {
	Input {
	    scan $inp "%s %d %d" cmd val1 val2
	    set upDown .invu.vubar
	    barSlide $upDown $topBarId $val1
	    if {$val2 != $lastInOver} {
		light $upDown $topLightId $val2
		set lastInOver $val2
	    }
	}
	Output {
	    scan $inp "%s %d %d" cmd val1 val2
	    set upDown .outvu.vubar
	    barSlide $upDown $bottomBarId $val1
	    if {$val2 != $lastOutOver} {
		light $upDown $bottomLightId $val2
		set lastOutOver $val2
    	    }
	}
	Box {
	    scan $inp "%s %d %d %s" cmd x y kind
	    set param$x$y [lrange $inp 4 end]
    	    set kind$x$y $kind
	    if {$y > [set maxy$x]} {
		set maxy$x $y
	    }
	    createBox .effects.matrix.$x$y $x $y $kind
	    checkCol $x
	}
	Audio {
	    scan $inp "%s %d %d" cmd fSamp bufSize
	}
	Switch {
	    scan $inp "%s %d %d %d" cmd outChan outChPrev paramt1101
	    set outChdel $outChan
	    set paramsix1101 [logt $paramt1101]
	}
	VUMeters {
	    scan $inp "%s %d %d %d" cmd paramt1100 paramt2100 paramd100
	    set paramsix1100 [logt $paramt1100]
	    vupdate
	}
	Column {
	    set name "untitled"
	    scan $inp "%s %d %s" cmd x name
	    set name$x $name
	}
	LoadError {
	    scan $inp "%s %d %s" cmd er path
	    setEffect 10 7
	}
	SaveWave {
	    set paramn108 untitled.wav
	    scan $inp "%s %d %d %s" cmd paramd108 params108 paramn108
	    incr paramd108
	    set completeName $paramn108
	    recording $paramd108 0
	}
    }    
} 