#!/bin/sh
#-*- mode: Tcl;time-stamp-start:"TimeStamp[ 	]+\\\\?[\"<]+";-*-
# the next line restarts using wish \
exec wish $0 -- $@
# Copyright (C) 2007, 2010 William J. Poser (billposer@alum.mit.edu)
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 3 of the GNU General Public License
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# To read the Gnu General Public License, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# or go to the web page:  http://www.gnu.org/licenses/gpl.txt.

set Version "2.3"
package require math::bigfloat
namespace import ::math::bigfloat::*
package require math::bignum
package require Tk
package require msgcat
proc _ {s} {return [::msgcat::mc $s]};	# Define shorthand for gettext

set TkPresentP 1; #Needed for compatibility. This program requires Tk.
set ShowBalloonHelpP 1
set StorageToTimeP 0
set DebugP 0

set AudioType 3
set CompressionType 0; #No compression
set ReportUnit MB

set InputRelief  raised
set OutputRelief solid

set ColorSpecs(Default,ActiveBackground)	"\#0B36FE"
set ColorSpecs(Default,Background)	"\#EE9572"
set ColorSpecs(ListHeader,Background)	"\#CBD7FF"
set ColorSpecs(ListHeader,Foreground)	black
set ColorSpecs(ListHeader,ActiveBackground)	"\#8f89fe";
set ColorSpecs(ListHeader,ActiveForeground)	black
set ColorSpecs(Menu,ActiveBackground)	"\#fee4a9";
set ColorSpecs(Menu,Background)		"\#ffc192";
set ColorSpecs(Menu,Foreground)		"\#fee4a9";
set ColorSpecs(Menu,Select)		red
set ColorSpecs(Menu,ActiveBackground)	"\#fee4a9";
set ColorSpecs(Menu,ActiveForeground)	"\#c36176";
set ColorSpecs(Menubar,Background)	 	"\#c36176";
set ColorSpecs(Menubar,Foreground)		"\#fee4a9";
set ColorSpecs(Menubar,ActiveBackground)	"\#fee4a9";
set ColorSpecs(Menubar,ActiveForeground)	"\#c36176";
set ColorSpecs(Messages,Foreground) black
set ColorSpecs(Messages,Background) "\#DDFFDD"
set ColorSpecs(SearchEntry,Background)	"\#EEEEFF"
set ColorSpecs(TextDisplay,Background) NavajoWhite
set ColorSpecs(TextDisplay,Foreground) "\#000000"
set ColorSpecs(TableList,Background)	"\#DDDDFF"
set ColorSpecs(TableList,SelectBackground)	"\#FFCFBF"
set ColorSpecs(TableList,SelectForeground)	black

#Constants
set One [fromstr 1.0 12] 
set Sixty [fromstr 60]

set UnitMultipliers(KB)	 [fromstr 1000]
set UnitMultipliers(MB)  [mul $UnitMultipliers(KB) $UnitMultipliers(KB)]
set UnitMultipliers(GB)  [mul $UnitMultipliers(MB) $UnitMultipliers(KB)]
set UnitMultipliers(TB)  [mul $UnitMultipliers(MB) $UnitMultipliers(MB)]
set UnitMultipliers(KiB) [fromstr 1024]
set UnitMultipliers(MiB) [mul $UnitMultipliers(KiB)  $UnitMultipliers(KiB)]
set UnitMultipliers(GiB) [mul $UnitMultipliers(MiB) $UnitMultipliers(KiB)]
set UnitMultipliers(TiB) [mul $UnitMultipliers(GiB)  $UnitMultipliers(KiB)]
set UnitMultipliers(CD)  [mul [fromstr 650] $UnitMultipliers(MiB)]
set UnitMultipliers(DVD) [mul [fromstr 4488] $UnitMultipliers(MiB)]
set UnitMultipliers(CD80)  [mul [fromstr 700] $UnitMultipliers(MiB)]

set UnitDividers(KB)  [div $One $UnitMultipliers(KB)] 
set UnitDividers(MB)  [div $One $UnitMultipliers(MB)] 
set UnitDividers(GB)  [div $One $UnitMultipliers(GB)] 
set UnitDividers(TB)  [div $One $UnitMultipliers(TB)] 
set UnitDividers(KiB) [div $One $UnitMultipliers(KiB)] 
set UnitDividers(MiB) [div $One $UnitMultipliers(MiB)] 
set UnitDividers(GiB) [div $One $UnitMultipliers(GiB)] 
set UnitDividers(TiB) [div $One $UnitMultipliers(TiB)] 
set UnitDividers(CD)  [div $One $UnitMultipliers(CD)]
set UnitDividers(DVD) [div $One $UnitMultipliers(DVD)]
set UnitDividers(CD80)  [div $One $UnitMultipliers(CD80)]

set MP3BitRates {32 40 48 56 64 80 96 112 128 144 160 192 224 256 320}
set VorbisBitRates {45 64 80 96 112 128 160 192 224 256 320 500}
array set FLACRatios {
    0	0.28
    1	0.75
    2	0.26
    3	0.51
}

proc LoadMessageCatalog {} {
    global DebugP;

    if {$DebugP} {
	if {[::msgcat::mcload "msgs"] == 0} {
	    puts "No message catalog loaded."
	} else {
	    puts "Message catalog loaded."
	}
    } else {
	::msgcat::mcload [file join [file dirname [info script]] msgs];
    }
}

proc DetermineOS {} {
    if {[string equal $::tcl_platform(platform) windows]} {
	set ::Pars(System) MSWindows;
    } elseif {[string equal $::tcl_platform(platform) unix]} {
	if {[string equal $::tcl_platform(os) Darwin]} {
	    set ::Pars(System) MacOSX;
	} else {
	    set ::Pars(System) Unix;
	}
    }
}


proc DetermineGraphicsSystem {} {
    if {[string match X11*  [winfo server .]]} {
	set ::Pars(AquaP) 0
	set ::Pars(WindowSystem) X11
    } else {
	if {[string match $::Pars(System) MSWindows]} {
	    set ::Pars(AquaP) 0;
	    set ::Pars(WindowSystem) MSWindows;
	}
	if {[string match $::Pars(System) MacOSX]} {
	    set ::Pars(AquaP) 1
	    set ::Pars(WindowSystem) Aqua
	}
    }
}

proc CheckTkEightFivePlusOnX11 {} {
    set VLevelList [split [info patchlevel] "."]
    set Major [lindex $VLevelList 0]
    set Minor [lindex $VLevelList 1]
    if {$::Pars(WindowSystem) eq "X11"} {
	if {$Major > 8} {
	    return 1
	} else {
	    if {($Major == 8) && ($Minor >= 5)} {
		return 1
	    }
	} 
    }
    return 0
}

proc ClearDisplays {} { 
    ClearTime
    ClearStorage
}

proc ClearStorage {} {
   set ::StorageText ""
}

proc ClearTime {} {
    set ::HoursText ""
    set ::MinutesText ""
    set ::SecondsText ""
}

proc ComputeTotalSeconds {} {
    set HourString [string trim $::HoursText]
    if {[string length $HourString] == 0} {set HourString 0}
    if {[string is int $HourString]} {
	set HourString $HourString.
    }
    set LengthHours [fromstr $HourString 6]
    set MinuteString [string trim $::MinutesText]
    if {[string length $MinuteString] == 0} {set MinuteString 0}
    if {[string is int $MinuteString]} {
	set MinuteString $MinuteString.
    }
    set LengthMinutes [fromstr $MinuteString 6]
    set SecondString [string trim $::SecondsText]
    if {[string length $SecondString] == 0} {set SecondString 0}
    if {[string is int $SecondString]} {
	set SecondString $SecondString.
    }
    set LengthSeconds [fromstr $SecondString 6]
    return [add [mul [add [mul $LengthHours $::Sixty] $LengthMinutes] $::Sixty] $LengthSeconds]
}

proc ComputeRaw {TotalSeconds} {
    return [mul $TotalSeconds [BytesPerSecond]]
}

#Argument is a bigint. Returns a bigfloat
proc ComputeInverseRaw {BytesAvailable} {
    return [div $BytesAvailable [BytesPerSecond]]
}

proc BytesPerSecond {} {
    set SamplingRate [$::RateBox get]
    set BytesPerSecond [expr int($::Channels * $::BytesPerSample * $SamplingRate)]
    set BytesPerSecond $BytesPerSecond.
    return  [fromstr $BytesPerSecond 12]
}


#The bitrates below are divided by two to get a rate per channel since
#the form in which they are standardly given is for stereo.
#Argument is a bigint. Returns a bigfloat.
proc ComputeInverseCompressed {BytesAvailable} {
    set ChCnt [fromstr $::Channels]
    switch -- $::CompressionType {
	1 {
	    set InvCompressionRatio [div [fromstr 1.0 12] [fromstr $::FLACRatios($::AudioType) 12]]
	    set UncompressedBytes [mul $BytesAvailable $InvCompressionRatio]
    	    set Seconds [div $UncompressedBytes [BytesPerSecond]]
	}
	2 {
	    set BitRate [div [fromstr [$::MP3RateBox get]] [fromstr 2]]
	    set Seconds [div $BytesAvailable [mul $ChCnt  [mul $BitRate [fromstr 125]]]]
	}
	3 {
	    set BitRate [div [fromstr 292] [fromstr 2]]
	    set Seconds [div $BytesAvailable [mul $ChCnt  [mul $BitRate [fromstr 125]]]]
	}
	4 {
	    set BitRate [div [fromstr [$::VorbisRateBox get]] [fromstr 2]]
	    set Seconds [div $BytesAvailable [mul $ChCnt  [mul $BitRate [fromstr 125]]]]
	}
	default {
	    set Seconds 0.0
	}
    }
    return $Seconds
}

#Argument is a bigfloat
#Returns a list of two integers and a double representing hours, minutes, and seconds.
proc SecondsToHMS {TotalSeconds} {
    #First we extract the integer and fractional parts of the bigfloat
    set IntegerTotalSeconds [floor $TotalSeconds]
    set FractionalTotalSeconds [sub $TotalSeconds $IntegerTotalSeconds]
    #Now we switch to bignums to do integer arithmetic
    set ts [math::bignum::fromstr [tostr $IntegerTotalSeconds]]
    set hr [math::bignum::divqr $ts [math::bignum::fromstr 3600]]
    set Hours [expr int([math::bignum::tostr [lindex $hr 0]])]
    set mr [math::bignum::divqr [lindex $hr 1] [math::bignum::fromstr 60]]
    set Minutes [expr int([math::bignum::tostr [lindex $mr 0]])]
    set IntegerSeconds [math::bignum::tostr [lindex $mr 1]]
    #Convert the fractional part back to a string so we can do ordinary arithmetic on it
    set FractionalSeconds [tostr $FractionalTotalSeconds]
    set Seconds [expr {$IntegerSeconds + $FractionalSeconds}]
    return [list $Hours $Minutes $Seconds]
}


#The bitrates below are divided by two to get a rate per channel since
#the form in which they are standardly given is for stereo.
proc ComputeCompressed {TotalSeconds RawBytes} {
    set ChCnt [fromstr $::Channels]
    switch -- $::CompressionType {
	1 {
	    set CompressionRatio [fromstr $::FLACRatios($::AudioType) 12]
	    set CompressedBytes [mul $RawBytes $CompressionRatio]
	}
	2 {
	    set BitRate [div [fromstr [$::MP3RateBox get]] [fromstr 2]]
	    set CompressedBytes [mul $ChCnt [mul [mul $TotalSeconds $BitRate]  [fromstr 125]]]
	}
	3 {
	    set BitRate [div [fromstr 292] [fromstr 2]]
	    set CompressedBytes [mul $ChCnt [mul [mul $TotalSeconds $BitRate]  [fromstr 125]]]
	}
	4 {
	    set BitRate [div [fromstr [$::VorbisRateBox get]] [fromstr 2]]
	    set CompressedBytes [mul $ChCnt [mul [mul $TotalSeconds $BitRate]  [fromstr 125]]]
	}
	default {
	    set CompressedBytes 0
	}
    }
    return $CompressedBytes
}

proc SelectStorageInput {} {
    $::OutputFrame configure -relief $::InputRelief
    $::TimeFrame configure -relief $::OutputRelief
    set ::StorageToTimeP 1
    grid forget $::CompressionRatioBox
    $::StorageLabel configure -text [_ "Storage Available"]
    tooltip $::Storage [_ "Enter the available storage here."]
    balloonhelp_clear $::HoursEntry
    balloonhelp_clear $::MinutesEntry
    balloonhelp_clear $::SecondsEntry
    $::Storage configure -validate all
    $::HoursEntry configure -validate all
    $::MinutesEntry configure -validate all
    $::SecondsEntry configure -validate all
}

proc SelectTimeInput {} {
    $::OutputFrame configure -relief $::OutputRelief
    $::TimeFrame configure -relief $::InputRelief
    set ::StorageToTimeP 0
    $::StorageLabel configure -text [_ "Storage Required"]
    tooltip $::HoursEntry [_ "Enter the number of hours, which need not be an integer."]
    tooltip $::MinutesEntry \
	[_ "Enter the number of minutes, which need not be an integer.\nIt may exceed 59."]
    tooltip $::SecondsEntry \
	[_ "Enter the number of seconds, which need not be an integer.\nIt may exceed 59."]
    balloonhelp_clear $::Storage
    $::Storage configure -validate none
    $::HoursEntry configure -validate all
    $::MinutesEntry configure -validate all
    $::SecondsEntry configure -validate all
}

proc DisplayResult {args} {
    if {$::StorageToTimeP} {
	DisplayTimeResult
    } else {
	DisplayStorageResult
    }
}

proc DisplayStorageResult {args} {
    set TotalSeconds [ComputeTotalSeconds]
    if {$::CompressionType} {
	set RawResult [ComputeRaw $TotalSeconds]
	set Result [ComputeCompressed $TotalSeconds $RawResult]
    } else {
	grid forget $::CompressionRatioBox
	set Result [ComputeRaw $TotalSeconds]
    }
    if {[iszero $Result]} {
	set ::StorageText ""
	return
    }
    set ScaledResult [tostr [mul $Result $::UnitDividers($::ReportUnit)]]
    scan $ScaledResult "%f" sr
    set ::StorageText [format "%6.2f" $sr]
    if {$::CompressionType} {
	set CompressionRatioStr [tostr [div $Result $RawResult]]
	scan $CompressionRatioStr "%f" CompressionRatio
	set ::CompressionRatioText [format "%02d%%" \
		[expr int(round($CompressionRatio * 100))]]
	grid $::CompressionRatioBox -row 1 -column 0 -padx {0 10} -sticky e -pady {20 0}
    } else {
	set ::CompressionRatioText ""
    }
}

proc DisplayTimeResult {args} {
    set txt [string trim $::StorageText]
    if {[string length $txt] == 0} {
	ClearTime
	return
    }
    if {[string is int $txt]} {
	set txt $txt.
    }
    if {![string is double $txt]} {
	ClearTime
	return
    }
    set Bytes [mul [fromstr $txt 12] $::UnitMultipliers($::ReportUnit)]
    if {$::CompressionType} {
	set TotalSeconds [ComputeInverseCompressed $Bytes]
    } else {
	set TotalSeconds [ComputeInverseRaw $Bytes]
    }
    set il [SecondsToHMS $TotalSeconds]
    set Hours [lindex $il 0]
    set Minutes [lindex $il 1]
    set Seconds [lindex $il 2]
    set SecondsText [format "%.2f" $Seconds]
    if {[string equal $SecondsText "60.00"]} {
	set Seconds 0.0
	set Minutes [incr Minutes]
    }
    set MinutesText [format "%d" $Minutes]
    if {[string equal $MinutesText "60"]} {
	set Minutes 0
	set Hours [incr Hours]
    }
    set ::HoursText [format "%d" $Hours]
    set ::MinutesText [format "%d" $Minutes]
    set ::SecondsText [format "%.2f" $Seconds]
}

proc SetChannels {x y z} {
    set Channels [fromstr $::Channels]
}

proc SetResolution {x y z} {
    set BytesPerSample [fromstr $::BytesPerSample]
}

proc SelectCompressionInfo {a b c} {
    pack forget $::AudioTypeFrame
    pack forget $::MP3RateFrame
    pack forget $::VorbisRateFrame
    switch -exact -- $::CompressionType {
	1 {
	    pack $::AudioTypeFrame  -side left -padx {25 5} -pady {6 3} -anchor nw
	}
	2 {
	    pack $::MP3RateFrame    -side left -padx {25 5} -pady {6 3} -anchor nw
	}
	4 {
	    pack $::VorbisRateFrame -side left -padx {25 5} -pady {6 3} -anchor nw
	}
    }
}

#Balloon help stuff.
proc SetupBalloonHelp {} {
    global bhInfo

    option add *Balloonhelp*background \#99BDFB 80
    option add *Balloonhelp*foreground black widgetDefault
    option add *Balloonhelpinfo.wrapLength 3i  widgetDefault
    option add *Balloonhelp.info.justify left widgetDefault
    toplevel .balloonhelp -class Balloonhelp -background black -borderwidth 1 -relief flat
    label .balloonhelp.info -font BalloonHelpFont;
    pack .balloonhelp.info -side left -fill y
    wm overrideredirect .balloonhelp 1
    wm withdraw .balloonhelp
    set bhInfo(active) 1
}

proc ControlBalloonHelp {} {
    balloonhelp_control $::ShowBalloonHelpP
}

proc balloonhelp_control {state} {
     global bhInfo
     if {$state} {
          set bhInfo(active) 1
     } else {
	balloonhelp_cancel
	set bhInfo(active) 0
     }
}

proc balloonhelp_for {win mesg} {
    global bhInfo
    set bhInfo($win) $mesg
    set ::bhOverlapP($win) 1; 
    bind $win <Enter> {+balloonhelp_pending %W}
    bind $win <Leave> {+balloonhelp_cancel}
}

proc balloonhelp_clear {win} {
    global bhInfo
    bind $win <Enter> {}
    bind $win <Leave> {}
}

proc balloonhelpd_for {win mesg} {
    global bhInfo
    set ::bhOverlapP($win) 0;
    set bhInfo($win) $mesg
    bind $win <Enter> {+balloonhelp_show %W}
    bind $win <Leave> {+wm withdraw .balloonhelp}
}

proc balloonhelp_pending {win} {
     global bhInfo
     balloonhelp_cancel
     set bhInfo(pending) [after 1000 [list balloonhelp_show $win]]
}

proc balloonhelp_cancel {} {
    global bhInfo
    if { [info exists bhInfo(pending)]} {
	after cancel $bhInfo(pending)
	unset bhInfo(pending)
    }
    if {$::TkPresentP} {
	wm withdraw .balloonhelp
    }
}

proc balloonhelp_show {win} {
    global bhInfo;
    global bhOverlapP;
    if {$bhOverlapP($win)} {
	set Overlap 25;
    } else {
	set Overlap -10;
    }
    if {[winfo exists $win]} {
	if {$bhInfo(active)} {
	    .balloonhelp.info configure -text $bhInfo($win)
	    #Set abcissa
	    set MaxStringWidth 0;
	    foreach line [split $bhInfo($win) "\n"] {
		set StringWidth [font measure BalloonHelpFont -displayof .balloonhelp.info $line]
		if {$StringWidth > $MaxStringWidth} {
		    set MaxStringWidth $StringWidth;
		}
	    }
	    set ScreenWidth [winfo screenwidth $win]
	    set Width [winfo width $win];
	    set LeftEdge  [winfo rootx $win];
	    set RightEdge [expr $LeftEdge + $Width];
	    if {$ScreenWidth - $RightEdge < $MaxStringWidth} { 
		if {$LeftEdge > $MaxStringWidth} {
		    set x [expr $LeftEdge - $MaxStringWidth + $Overlap];
		} else {
		    if {$ScreenWidth - $MaxStringWidth > 0} {
			set x [expr $RightEdge - $MaxStringWidth];
		    } else {
			set x [expr $ScreenWidth - $MaxStringWidth];
		    }
		}
	    } else {
		set x [expr $RightEdge - $Overlap];
	    }
	    #Set ordinate
	    set Height [winfo height $win];
	    set TopEdge [winfo rooty $win];
	    set y [expr $TopEdge + int(($Height/1.25))];
	    wm geometry .balloonhelp +$x+$y
	    wm deiconify .balloonhelp
	    raise .balloonhelp
	}
    }
    if {[info exist bhInfo(pending)]} {
	unset bhInfo(pending)
    }
}

proc tooltip {widget msg} {
    balloonhelp_for $widget $msg
}

proc ValidateEntry {w s type action} {
    if {[string equal $type focusout] || \
	    ([string equal $type key] && ($action == 1))} {
	if {[string length $s] == 0} {return 0}
	if {![string is double $s]} {
	    if {[string equal $type focusout]} {focus $w}
	    return 0
	}
	if {$s < 0.0} {
	    if {[string equal $type focusout]} {focus $w}
	    return 0;
	}
    }
    return 1;
}

::msgcat::mcset es "Dismiss" "Salir"
::msgcat::mcset es "Tooltips?" "\u00bfTooltips?"
::msgcat::mcset ja "Tooltips?" "\u30C4\u30FC\u30EB\u30C1\u30C3\u30D7?"

#French translation
::msgcat::mcset fr "Bits/Sample" "Bits/\u00c9chantillon"
::msgcat::mcset fr "Channels" "Canaux"
::msgcat::mcset fr "Clear" "Effacer"
::msgcat::mcset fr "Compression" "Compression"
::msgcat::mcset fr "Dismiss" "Sortir"
::msgcat::mcset fr "Compute" "Calculer"
::msgcat::mcset fr "Intrinsic Parameters of Audio" "Param\u00e8tres intrinseques de l'audio"
::msgcat::mcset fr "Sampling Rate" "Fr\u00e9quence d'\u00e9chantillonage"
::msgcat::mcset fr "stereo" "st\u00e9r\u00e9o"
::msgcat::mcset fr "Storage Available" "Capacit\u00e9 disponible"
::msgcat::mcset fr "Storage Required" "Capacit\u00e9 requise"
::msgcat::mcset fr "Tooltips?" "Infobulles?"
::msgcat::mcset fr "Unit" "Unit\u00e9"
::msgcat::mcset fr "Duration of Recording" "Dur\u00e9e des donn\u00e9es audio"
::msgcat::mcset fr "Hours" "Heures"
::msgcat::mcset fr "Minutes" "Minutes"
::msgcat::mcset fr "Seconds" "Secondes"
::msgcat::mcset fr "Audio from the 1980s may have this resolution." \
    "Il se peut que des fichiers audio datant des ann\u00e9es 1980 aient\nce profondeur d'\u00e9chantillonage"
::msgcat::mcset fr "Most current digital audio has this resolution." \
    "La plupart de fichiers audio actuels ont ce profondeur d'\u00e9chantillonage"
::msgcat::mcset fr "Some recent high-end audio has this resolution." \
    "Il se peut que des fichiers audio r\u00e9cents de haute qualit\u00e9 aient\nce profondeur d'\u00e9chantillonage"
::msgcat::mcset fr "Compression factor is estimated." "Taux de compression approxim\u00e9"
::msgcat::mcset fr "Compressed size as a percentage of raw size" "Taux de compression comme pourcentage de taille brut"
::msgcat::mcset fr "None" "Aucune"
::msgcat::mcset fr "Most Sony minidisc recorders" "La pluparts des appareils minidisques Sony"
::msgcat::mcset fr "Enter the number of hours, which need not be an integer." "Faire entrer le nombre d'heures. \u00C7a ne doit pas \u00EAtre un nombre entier."
::msgcat::mcset fr "Enter the number of minutes, which need not be an integer.\nIt may exceed 59." "Faire entrer le nombre de minutes. \u00C7a ne doit pas \u00EAtre un nombre entier. Il est permis qu'il d\u00E9passe 59."
::msgcat::mcset fr "Enter the number of seconds, which need not be an integer.\nIt may exceed 59." "Faire entrer le nombre de minutes. \u00C7a ne doit pas \u00EAtre un nombre entier.\nIl est permis qu'il d\u00e9passe 59."
::msgcat::mcset fr "Enter the available storage here." "Faire entrer le capacit\u00e9 disponible ici."
::msgcat::mcset fr "Contents of 70 minute CD = 650 MB = 620 MiB" "Le contenu d'un CD de 70 minutes = 650 MB = 620 MiB"
::msgcat::mcset fr "Contents of 80 minute CD = 700 MB = 668 MiB" "Le contenu d'un CD de 70 minutes = 700 MB = 668 MiB"
::msgcat::mcset fr "Contents of standard DVD = 4.71GB = 4.49 GiB" "Le contenu d'un  DVD = 4.71GB = 4.49 GiB"

#Load the message catalog here so that if one is present it will over-ride
#the built-in catalogs.
LoadMessageCatalog

DetermineOS
DetermineGraphicsSystem
set TkEightFivePlusOnX11P [CheckTkEightFivePlusOnX11]

if {$TkEightFivePlusOnX11P} {
    set SmallFontSize 9
    set TitleFontSize 13
    set BalloonHelpFontSize 11
    set EntryFontSize 11
    set LabelFontSize 11
    set RadiobuttonFontSize 11
} else {
    set SmallFontSize 10
    set TitleFontSize 15
    set BalloonHelpFontSize 12
    set EntryFontSize 12
    set LabelFontSize 13
    set RadiobuttonFontSize 12
}

if {[lsearch [font families] helvetica] >= 0} {
    font create EntryFont -size $EntryFontSize -family helvetica
    font create LabelFont -size $LabelFontSize -family helvetica
    font create RadiobuttonFont -size $RadiobuttonFontSize -family helvetica
    font create SmallFont -size $SmallFontSize -family helvetica
    font create TitleFont -size $TitleFontSize -weight bold -family helvetica
    font create BalloonHelpFont -size $BalloonHelpFontSize -weight bold -family helvetica
} else {
    font create EntryFont -size $EntryFontSize
    font create LabelFont -size $LabelFontSize
    font create RadiobuttonFont -size $RadiobuttonFontSize -family helvetica
    font create SmallFont -size $SmallFontSize
    font create TitleFont -size $TitleFontSize -weight bold
    font create BalloonHelpFont -size $BalloonHelpFontSize -weight bold
}

option add *Entry*font EntryFont
option add *Label*font LabelFont
option add *Radiobutton*font RadiobuttonFont

#Create GUI
SetupBalloonHelp
set m [frame .main]
set Title [label $m.tit -text "AudioSpace $Version" -font TitleFont]
set Copyright [label $m.cr -text "\u00A9 2007-2010 Bill Poser (http://billposer.org) GPL 3" \
	   -font SmallFont] 

set InputFrame [frame $m.inp -relief ridge -border 1]
set InputTitle [label $InputFrame.tit -text [_ "Intrinsic Parameters of Audio"] -anchor w]

set ChannelFrame [frame $InputFrame.cha]
label $ChannelFrame.tit -text [_ "Channels"]
radiobutton $ChannelFrame.mono   -text [_ "mono"]    -value 1 -variable Channels
radiobutton $ChannelFrame.stereo -text [_ "stereo"]  -value 2 -variable Channels
radiobutton $ChannelFrame.quad   -text [_ "quad"]    -value 4 -variable Channels
$ChannelFrame.mono invoke
pack $ChannelFrame.tit -side top -anchor w -padx {2 0}
pack $ChannelFrame.mono $ChannelFrame.stereo $ChannelFrame.quad -side top -anchor w

set RateFrame [frame $InputFrame.rat]
label $RateFrame.tit -text [_ "Sampling Rate"]
set RateList {8000 10000 16000 18900 20000 22050 32000 37800 44056 44100 48000 96000}
set RateBox [spinbox $RateFrame.sbx -values $RateList -wrap 1 -width 6 -command DisplayResult]
$RateBox set 44100
pack $RateFrame.tit -side top -anchor n
pack $RateBox -side top

set ResolutionFrame [frame $InputFrame.res]
label $ResolutionFrame.tit -text [_ "Bits/Sample"]
radiobutton $ResolutionFrame.a   -text " 8"  -value 1 -variable BytesPerSample
radiobutton $ResolutionFrame.b   -text "16" -value 2 -variable BytesPerSample
radiobutton $ResolutionFrame.c   -text "24" -value 3 -variable BytesPerSample
$ResolutionFrame.b invoke
pack $ResolutionFrame.tit -side top -anchor c
pack $ResolutionFrame.a $ResolutionFrame.b  $ResolutionFrame.c -side top

tooltip $ResolutionFrame.a [_ "Audio from the 1980s may have this resolution."]
tooltip $ResolutionFrame.b [_ "Most current digital audio has this resolution."]
tooltip $ResolutionFrame.c [_ "Some recent high-end audio has this resolution."]


pack $InputTitle      -side top -expand 1 -fill both -pady {6 6} -padx 3
pack $ChannelFrame    -padx 8 -side left -anchor nw -expand 1 -fill both
pack $RateFrame       -padx 8 -side left -anchor nw -expand 1 -fill both
pack $ResolutionFrame -padx 8 -side left -anchor ne -expand 1 -fill both

set CompressionFrame [frame $m.comp -relief ridge -border 1]
label $CompressionFrame.tit -text [_ "Compression"]
pack $CompressionFrame.tit -anchor w

set CompressionChoiceFrame [frame $CompressionFrame.ctc]
radiobutton $CompressionChoiceFrame.non -variable CompressionType -value 0 -text [_ "None"]
radiobutton $CompressionChoiceFrame.nls -variable CompressionType -value 1 -text [_ "FLAC"]
radiobutton $CompressionChoiceFrame.mp3 -variable CompressionType -value 2 -text [_ "MP3"]
radiobutton $CompressionChoiceFrame.atr -variable CompressionType -value 3 -text [_ "ATRAC"]
radiobutton $CompressionChoiceFrame.ogv -variable CompressionType -value 4 -text [_ "Vorbis"]
set CompressionRatioBox [label $CompressionChoiceFrame.cmr -textvariable CompressionRatioText \
		     -width 4 -relief solid]

grid $CompressionChoiceFrame.non -row 0 -column 0 -padx 8 -sticky w
grid $CompressionChoiceFrame.nls -row 0 -column 1 -padx 8 -sticky w
grid $CompressionChoiceFrame.mp3 -row 0 -column 2 -padx 8 -sticky w
grid $CompressionChoiceFrame.atr -row 1 -column 1 -padx 8 -sticky w -pady {0 42}
grid $CompressionChoiceFrame.ogv -row 1 -column 2 -padx 8 -sticky w -pady {0 42}

tooltip $CompressionChoiceFrame.nls [_ "Compression factor is estimated."]
tooltip $CompressionChoiceFrame.atr [_ "Most Sony minidisc recorders"]
tooltip $CompressionRatioBox [_ "Compressed size as a percentage of raw size"]

set AudioTypeFrame [frame $CompressionFrame.atf]
radiobutton $AudioTypeFrame.cm -variable AudioType -value 0 -text [_ "Classical Music"]
radiobutton $AudioTypeFrame.fm -variable AudioType -value 1 -text [_ "Fast Music"]
radiobutton $AudioTypeFrame.ss -variable AudioType -value 2 -text [_ "Slow Speech"]
radiobutton $AudioTypeFrame.cs -variable AudioType -value 3 -text [_ "Continuous Speech"]
pack $AudioTypeFrame.cs $AudioTypeFrame.ss  $AudioTypeFrame.cm  $AudioTypeFrame.fm \
    -padx 4 -side top -pady 0 -anchor w

set MP3RateFrame [frame $CompressionFrame.mpr]
label $MP3RateFrame.tit -text [_ "KBits per Second"]
set MP3RateBox [spinbox $MP3RateFrame.sbx -values $MP3BitRates -wrap 1 -width 3 \
		    -command DisplayResult]
pack $MP3RateFrame.tit -side top -anchor c
pack $MP3RateBox -side top -anchor c
$MP3RateBox set 128

set VorbisRateFrame [frame $CompressionFrame.vor]
label $VorbisRateFrame.tit -text [_ "KBits per Second"]
set VorbisRateBox [spinbox $VorbisRateFrame.sbx -values $VorbisBitRates -wrap 1 -width 3 \
		      -command DisplayResult]
pack $VorbisRateFrame.tit -side top -anchor c
pack $VorbisRateBox -side top -anchor c

pack $CompressionChoiceFrame -side left -pady 8 -anchor n

set TimeFrame [frame $m.tf -relief ridge -border 1]
set TimeTitle [label $TimeFrame.tit -text [_ "Duration of Recording"]]
set TimeEntryFrame [frame $TimeFrame.tef]
set HoursEntry [entry $TimeEntryFrame.hrs -width 8 -textvariable HoursText \
		    -validatecommand {ValidateEntry %W %P %V %d}]
set MinutesEntry [entry $TimeEntryFrame.mins -width 8 -textvariable MinutesText \
		    -validatecommand {ValidateEntry %W %P %V %d}]
set SecondsEntry [entry $TimeEntryFrame.secs -width 8 -textvariable SecondsText \
		    -validatecommand {ValidateEntry %W %P %V %d}]
set HoursLabel [label $TimeEntryFrame.hrslab  -text [_ "Hours"]]
set MinutesLabel [label $TimeEntryFrame.minslab -text [_ "Minutes"]]
set SecondsLabel [label $TimeEntryFrame.secslab -text [_ "Seconds"]]
set LabelRow 2
set ValueRow 1
grid $HoursEntry      -row $ValueRow -column 1	-padx 2 -pady 3 -sticky we
grid $MinutesEntry    -row $ValueRow -column 2	-padx 2 -pady 3 -sticky we
grid $SecondsEntry    -row $ValueRow -column 3	-padx 2 -pady 3 -sticky we
grid $HoursLabel      -row $LabelRow -column 1	-padx 2 -pady 3 -sticky we
grid $MinutesLabel    -row $LabelRow -column 2	-padx 2 -pady 3 -sticky we
grid $SecondsLabel    -row $LabelRow -column 3	-padx 2 -pady 3 -sticky we

bind $HoursEntry   <Return> DisplayResult
bind $MinutesEntry <Return> DisplayResult
bind $SecondsEntry <Return> DisplayResult

bind $HoursEntry   <FocusIn> +SelectTimeInput
bind $MinutesEntry <FocusIn> +SelectTimeInput
bind $SecondsEntry <FocusIn> +SelectTimeInput

pack $TimeTitle       -side top -expand 1 -fill none -anchor w -pady {2 0}
pack $TimeEntryFrame  -side top -expand 1 -fill none -anchor w -padx {35 2} -pady {8 1}

set OutputFrame [frame $m.sto -relief ridge -border 1]
set StorageLabel [label $OutputFrame.tit -text [_ "Storage Required"]]
set ResultFrame [frame $OutputFrame.sto]
set Storage [entry $ResultFrame.usr -textvariable StorageText -width 15 \
		 -validatecommand {ValidateEntry %W %P %V %d}]
pack $OutputFrame.tit -side top -anchor w -expand 1 -fill none
pack $Storage -side top -expand 1 -fill none

bind $Storage <Return>   DisplayResult
bind $Storage <FocusIn> +SelectStorageInput

set UnitFrame [frame $OutputFrame.uni]
label $UnitFrame.tit -text [_ "Unit"]
radiobutton $UnitFrame.kb  -text "KB"  -value KB  -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.kib -text "KiB" -value KiB -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.mb  -text "MB"  -value MB  -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.mib -text "MiB" -value MiB -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.gb  -text "GB"  -value GB  -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.gib -text "GiB" -value GiB -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.tb  -text "TB"  -value TB  -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.tib -text "TiB" -value TiB -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.cd  -text "CD70"  -value CD  -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.cde  -text "CD80"  -value CD80  -variable ReportUnit  -font SmallFont
radiobutton $UnitFrame.dvd -text "DVD" -value DVD -variable ReportUnit  -font SmallFont
grid $UnitFrame.tit -row 0 -column 0 -columnspan 5 -sticky ew
grid $UnitFrame.kb  -row 1 -column 0 -sticky w
grid $UnitFrame.kib -row 2 -column 0 -sticky w
grid $UnitFrame.mb  -row 1 -column 1 -sticky w
grid $UnitFrame.mib -row 2 -column 1 -sticky w
grid $UnitFrame.gb  -row 1 -column 2 -sticky w
grid $UnitFrame.gib -row 2 -column 2 -sticky w
grid $UnitFrame.tb  -row 1 -column 3 -sticky w
grid $UnitFrame.tib -row 2 -column 3 -sticky w

grid $UnitFrame.cd  -row 1 -column 4 -sticky w
grid $UnitFrame.cde  -row 2 -column 4 -sticky w
grid $UnitFrame.dvd -row 1 -column 5 -sticky w

tooltip $UnitFrame.kib [_ "Kibibytes = 2\u00B9\u2070 bytes = 1.024 KB"]
tooltip $UnitFrame.mib [_ "Mebibytes = 2\u00B2\u2070 bytes = 1024 KiB = 1.049 MB"]
tooltip $UnitFrame.gib [_ "Gibibytes = 2\u00B3\u2070 bytes = 1024 MiB = 1.073 GB"]
tooltip $UnitFrame.tib [_ "Tebibytes = 2\u2074\u2070 bytes = 1024 GiB = 1.100 TB"]

tooltip $UnitFrame.kb [_ "Kilobytes = 10\u00B3 bytes"]
tooltip $UnitFrame.mb [_ "Megabytes = 10\u2076 bytes = 10\u00B3 KB"]
tooltip $UnitFrame.gb [_ "Gigabytes = 10\u2079 bytes = 10\u00B3 MB"]
tooltip $UnitFrame.tb [_ "Terabytes = 10\u00B9\u00B2 bytes = 10\u00B3 GB"]

tooltip $UnitFrame.cd  [_ "Contents of 70 minute CD = 650 MB = 620 MiB"]
tooltip $UnitFrame.cde  [_ "Contents of 80 minute CD = 700 MB = 668 MiB"]
tooltip $UnitFrame.dvd [_ "Contents of standard DVD = 4.71GB = 4.49 GiB"]

pack $ResultFrame -side left  -padx {8 8} -anchor nw -expand 1 -fill both
pack $UnitFrame   -side right -padx {8 8} -anchor ne  -expand 1 -fill both -pady {0 20}

set Controls [frame $m.ctr -relief flat -border 1]
button $Controls.do  -text [_ "Compute"] -command DisplayResult
button $Controls.dis -text [_ "Dismiss"] -command {exit 0}
button $Controls.clr -text [_ "Clear"]   -command ClearDisplays
checkbutton $Controls.bh  -text [_ "Tooltips?"] -command ControlBalloonHelp \
    -variable ShowBalloonHelpP
pack $Controls.dis -side left  -padx {30 10}
pack $Controls.bh  -side left   -padx {18 18}
pack $Controls.clr -side left   -padx {18 18}
pack $Controls.do  -side right -padx {10 30}

pack $Title            -side top -pady {8 0} -padx 6 -expand 0 -fill none
pack $Copyright        -side top -pady {0 6} -padx 6 -expand 0 -fill none
pack $InputFrame       -side top -pady {4 4} -padx 6 -expand 1 -fill both
pack $CompressionFrame -side top -pady {4 4} -padx 6 -expand 1 -fill both
pack $TimeFrame        -side top -pady {4 4} -padx 6 -expand 1 -fill both -anchor w
pack $OutputFrame      -side top -pady {4 4} -padx 6 -expand 1 -fill both -ipady 4
pack $Controls         -side top -pady {4 8} -padx 6 -expand 1 -fill both
pack $m

#trace add variable Channels write SetChannels
trace add variable Channels write  DisplayResult
#trace add variable BytesPerSample write SetResolution
trace add variable BytesPerSample write DisplayResult
trace add variable CompressionType write SelectCompressionInfo
trace add variable CompressionType write DisplayResult
trace add variable AudioType write DisplayResult
trace add variable ReportUnit write DisplayResult

SelectTimeInput
focus $HoursEntry
