#!/usr/bin/wish -f ## ## SCRIPT: tkPlayChords_withSox.tk ## ## PURPOSE: This Tk GUI script allows the user to play guitar chords --- ## by clicking on buttons that are in (at least) 12 columns ## corresponding to 12 notes in an octave scale --- with the ## possibility of adding more columns/octaves. ## ## (Eventually, the intent is to add the ability to play chords ## that sound like they come from other instruments --- ## piano, harpsichord, harp, chimes, etc. --- by simply ## changing a radiobutton setting on the GUI.) ## ## The buttons in each column allow the user to play ## - major ## - minor ## - major-seventh ## - augmented-fifth ## chords. ## Additional chords may be added by adding buttons to each ## stack/column, where each stack/column corresponds to a ## note of the musical scale. ## For example, a minor-seventh chord could be added by adding ## one button in each stack/column. ## ##+####### ## METHOD: ## The chords are played with the 'play' command (that comes ## with the 'sox' audio command system) with commands like ## ## play -n synth pl G2 pl B2 pl D3 pl G3 pl D4 pl G4 \ ## delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1 ## ## which plays 6 notes over multiple octaves in a ## G major chord --- with a guitar-like sound. ## ##+################## ## CHORDS FILE OPTION: ## ## This utility includes an option to 'play' a text file ## conaining a sequence of chord names (and length of ## time to sustain each chord) --- including rest indicators ## (and length of time to sustain each rest). ## ## Example format: ## ## ## Format of each record: chord-time chord-name ## ## ## ## 'R' indicates a rest. A rest generates a pause ## ## for the specified time. ## ## ## ## Empty lines and lines starting with '#' are skipped. ## ## ## 3.0 Cmaj ## 3.0 Cmaj ## 3.0 Fmaj ## 3.0 Gmaj ## 3.0 Cmaj ## 3.0 Cmaj ## 1.5 Gmaj ## 1.5 R ## 1.5 Fmaj ## 1.5 R ## 3.0 Cmaj ## 3.0 Cmaj ## #################### ## NOTES IN CHORDS: ## (12 chords, C to B) ## ## Chord Major Minor 7th Aug(+) ## ------ ------ ------ ---- ------ ## ## C C,E,G C,Eb,G Bb C,E,G# ## ## Db/C# Db,F,Ab Db,E,Ab B Db,F,A ## ## D D,F#,A D,F,A C D,F#,Bb ## ## Eb/D# Eb,G,Bb Eb,Gb,Bb Db Eb,G,B ## ## E E,G#,B E,G,B D E,G#,C ## ## F F,A,C F,Ab,C Eb F,A,C# ## ## Gb/F# Gb,Bb,Db Gb,A,Db E Gb,Bb,D ## ## G G,B,D G,Bb,D F G,B,D# ## ## Ab/G# Ab,C,Eb Ab,B,Eb F# Ab,C,E ## ## A A,C#,E A,C,E G A,C#,F ## ## Bb/A# Bb,D,F Bb,Db,F Ab Bb,D,Gb ## ## B B,D#,F# B,D,F# A B,D#,G ## ## NOTE: ## Major chord - is made up of the 1,3, and 5 note in that key's scale. ## Minor chord - flat the 3rd note of the major scale. ## Augmented 5th chord - sharp the 5th note of the major scale. ## Major 7th chord - add the flatted 7th note of the major scale. ## ##+################# ## THE GUI WIDGETS: ## ## The options available to the user are indicated by ## the following 'sketch' of the GUI: ## ## FRAMEnames ## VVVVVVVVVV ## ------------------------------------------------------------------------------------------ ## tkPlayChords --- using the Sox system 'play' command ## [window title] ## ------------------------------------------------------------------------------------------ ## ## .fRbuttons {Exit} {Help} {PlayChordsFile} Chords filename: __________________ {GetFilename} ## ## .fRinstrmnt Instrument: O Guitar O Piano O Harpsichord O Harp O Chimes ## ## [An '.fRbottom' FRAME, below the '.fRbuttons' frame, contains at least ## 12 frames left to right --- each of which will contain a stack of buttons.] ## ## ['.fR_C' ['.fR_C#' .............................................. ['.fR_B' ## frame ] frame] frame ] ## ## [These 12 frames contain the following stacks of a label & several buttons.] ## ## {aug5} {aug5} ............................................... {aug5} ## {maj7} {maj7} ............................................... {maj7} ## {min} {min} ............................................... {min} ## {maj} {maj} ............................................... {maj} ## ## [labels->] C C#/Db ............................................... B ## ## ------------------------------------------------------------------- ## ## In the above sketch of the GUI: ## ## SQUARE BRACKETS indicate a comment (not to be placed on the GUI). ## BRACES indicate a Tk 'button' widget. ## UNDERSCORES indicate a Tk 'entry' widget. ## A COLON indicates that the text before the colon is on a 'label' widget. ## CAPITAL-O indicates a Tk 'radiobutton' widget. ## CAPITAL-X indicates a Tk 'checkbutton' widget (if any). ## Vertical bars (and horizontal hyphens) outline a 'listbox' widget. ## Less-than and greater-than signs indicate the left and right ends of a horizontal 'scrollbar'. ## Capital-V and Capital-A letters indicate the bottom and top ends of a vertical 'scrollbar'. ## ##+############## ## GUI components: ## ## From the GUI 'sketch' above, it is seen that the GUI consists of ## about ## ## - 52 button widgets (or more) ## - 13 label widgets ## - 1 entry widget ## - 3 radiobutton widgets (or more) ## - 0 checkbutton widgets ## - 0 scale widgets ## - 0 listbox widgets ## - 0 canvas widgets ## - 0 text widgets ## ##+######################################################################## ## 'CANONICAL' STRUCTURE OF THIS TK CODE: ## ## 0) Set general window & widget parms (win-name, win-position, ## win-color-scheme, fonts, widget-geometry-parms, win-size-control). ## ## 1a) Define ALL frames (and sub-frames, if any). ## 1b) Pack ALL frames and sub-frames. ## ## 2) Define all widgets in the frames. Pack them. ## ## 3) Define keyboard or mouse/touchpad/touch-sensitive-screen action ## BINDINGS, if needed. ## ## 4) Define PROCS, if needed. ## ## 5) Additional GUI INITIALIZATION (typically with one or two of ## the procs), if needed. ## ## ## Some detail about the code structure of this particular script: ## ## 1a) Define ALL frames: ## ## Top-level : '.fRbuttons' '.fRinstrmnt' '.fRbottom' ## ## Sub-frames: '.fRbottom.fR_C' ## '.fRbottom.fR_C#' ## .................. ## .................. ## ....12 frames..... ## ....(at least).... ## ...Left-to-right.. ## .................. ## .................. ## '.fRbottom.fR_B' ## ## 1b) Pack ALL frames. ## ## 2) Define all widgets in the frames (and pack them): ## ## - In '.fRbuttons': ## several button widgets ('Exit', 'Help' , 'PlayChordsFile', ...) ## ## - In '.fRinstrmnt': ## 1 label widget and several radiobutton widgets ## ## - In the 12 subframes of the '.fRbottom' frame: ## there is a stack of at least 4 buttons in each frame ## for a total of at least 48 buttons. ## ## 3) Define bindings: none, initially ## ## 4) Define procs: ## ## - 'play_chord' called by the following 'play_' procs. ## ## - 'play_Cmaj' ## - 'play_Cmin' ## - 'play_C7th' ## - 'play_Caug5' ## ## and at least 11 more groups of 4 (or more) similar procs ## in each group. ## ## - 'get_filename' - called by the 'GetFilename' button ## - 'play_chords_file' - called by the 'PlayChordsFile' button ## ## - 'popup_msgVarWithScroll' - called by the Help button ## ## 5) Additional GUI initialization: ## Not much here --- may eventually contain a setting of a variable ## to hold an initial directory name, to start navigating to ## a chords-file to select. ## ##+######################################################################## ## DEVELOPED WITH: ## Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october release, 'Karmic Koala'). ## ## $ wish ## % puts "$tcl_version $tk_version" ## showed 8.5 8.5 on Ubuntu 9.10 ## after Tcl-Tk 8.4 was replaced by 8.5 --- to get anti-aliased fonts. ##+####################################################################### ## MAINTENANCE HISTORY: ## Created by: Blaise Montandon 2016jan24 ## ## Changed by: Blaise Montandon 2016jan25 Add 'fRinstrmnt' frame with ## several radiobuttons. ## Changed by: Blaise Montandon 2016jan27 Add filename entry field and ## 'GetFilename' button and procs ## 'get_filename' & 'play_chords_file'. ## Changed by: Blaise Montandon 2016feb04 Add the 'set_guitar_parms' proc and ## vars ATTACKsecs_guitar, DECAYsecs_guitar, ## interPLUCKsecs_guitar, and DELAYsecs_guitar. ##+####################################################################### ##+####################################################################### ## Set general window parms (win-title,win-position). ##+####################################################################### wm title . "tkPlayChords --- using the 'play' command of the Sox system" wm iconname . "PlayChords" wm geometry . +15+30 ##+###################################################### ## Set the color scheme for the window and set the ## background color for the 'trough' in some widgets. ##+###################################################### tk_setPalette "#e0e0e0" set entryBKGD "#f0f0f0" set radbuttBKGD "#f0f0f0" # set chkbuttBKGD "#f0f0f0" # set scaleBKGD "#f0f0f0" # set listboxBKGD "#f0f0f0" ##+######################################################## ## Use a VARIABLE-WIDTH FONT for label and button widgets. ## ## Use a FIXED-WIDTH FONT for listboxes (and ## entry fields, if any). ##+######################################################## font create fontTEMP_varwidth \ -family {comic sans ms} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_varwidth \ -family {comic sans ms} \ -size -12 \ -weight bold \ -slant roman ## Some other possible (similar) variable width fonts: ## Arial ## Bitstream Vera Sans ## DejaVu Sans ## Droid Sans ## FreeSans ## Liberation Sans ## Nimbus Sans L ## Trebuchet MS ## Verdana font create fontTEMP_fixedwidth \ -family {liberation mono} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_fixedwidth \ -family {liberation mono} \ -size -12 \ -weight bold \ -slant roman ## Some other possible fixed width fonts (esp. on Linux): ## Andale Mono ## Bitstream Vera Sans Mono ## Courier 10 Pitch ## DejaVu Sans Mono ## Droid Sans Mono ## FreeMono ## Nimbus Mono L ## TlwgMono ##+########################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. width and height of canvas, and padding for Buttons) ##+########################################################### ## BUTTON geom parameters: set PADXpx_button 0 set PADYpx_button 0 set BDwidthPx_button 2 set RELIEF_button "raised" set WIDTHchars_button 6 ## LABEL geom parameters: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 set RELIEF_label "ridge" ## ENTRY widget geom settings: set BDwidthPx_entry 2 set initFileEntryWidthChars 30 set xyrangevarEntryWidthChars 7 ## RADIOBUTTON widget geom settings: set BDwidthPx_radbutt 2 set RELIEF_radbutt "ridge" ## SCALE geom parameters: set BDwidthPx_scale 2 # set initScaleLengthPx 100 set scaleThicknessPx 10 set scaleRepeatDelayMillisecs 800 ## DE-ACTIVATE THE FOLLOWING WIDGET-GEOMETRY ## SETTING STATEMENTS. Not used yet. if {0} { ## LISTBOX geom settings: set BDwidthPx_listbox 2 set initListboxWidthChars 30 set initListboxHeightChars 8 ## CHECKBUTTON widget geom settings: set BDwidthPx_chkbutt 2 set RELIEF_chkbutt "ridge" ## CANVAS geom parameters: set initCanWidthPx 600 set initCanHeightPx 200 set minCanHeightPx 24 # set BDwidthPx_canvas 2 set BDwidthPx_canvas 0 } ## END OF if {0} ##+################################################################### ## Set a MINSIZE of the window. ## ## For WIDTH, allow for the minwidth of the '.fRbuttons' frame: ## about 3 buttons (Exit,Help,PlayChordsFile). ## We want to at least be able to see the Exit button. ## ## For HEIGHT, allow ## 1 char high for the '.fRbuttons' frame ## 1 char high for the '.fRinstrmnt' frame ## 4 chars high for the '.fRbottom' frame ##+################################################################### ## MIN WIDTH: ## Allow for showing at least 3 buttons in the ## '.fRbuttons' frame at the top of the GUI. set minWinWidthPx [font measure fontTEMP_varwidth \ "Exit Help PlayChordsFile"] ## Add some pixels to account for right-left-side window decoration ## (about 8 pixels), about 3 x 4 pixels/widget for borders/padding for ## 3 widgets --- 3 buttons. set minWinWidthPx [expr {20 + $minWinWidthPx}] ## MIN HEIGHT --- allow ## 1 char high for 'fRbuttons' ## 1 char high for 'fRinstrmnt' ## 4 chars high for 'fRbottom' set CharHeightPx [font metrics fontTEMP_varwidth -linespace] set minWinHeightPx [expr {6 * $CharHeightPx}] ## Add about 28 pixels for top-bottom window decoration, ## about 5x4 pixels for the 'fRbuttons' frame and each of ## the 4 stacked frames within the 'fRbottom' frame --- ## and their widgets (their borders/padding). set minWinHeightPx [expr {$minWinHeightPx + 48}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## We allow the window to be resizable and we pack the canvas with ## '-fill both -expand 1' so that the canvas can be enlarged by enlarging ## the window. ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ##+#################################################################### ## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+#################################################################### ## if { "$VARlocale" == "en"} ## For widgets in 'fRbuttons' frame: set aRtext(buttEXIT) "Exit" set aRtext(buttHELP) "Help" set aRtext(buttPLAY) "PlayChordsFile" set aRtext(labelFILENAME) "Chords filename:" set aRtext(buttGETFILE) "GetFilename" ## For widgets in 'fRinstrmnt' frame: set aRtext(labelINSTRMNT) "Instrument:" set aRtext(radbuttGUITAR) "guitar" set aRtext(radbuttPIANO) "piano" set aRtext(radbuttHARPSI) "harpsichord" set aRtext(radbuttHARP) "harp" set aRtext(labelCHORDSECS) "Chord secs:" ## For widgets in 'fR_C' frame: set aRtext(labC) " C" set aRtext(buttCMAJ) "maj" set aRtext(buttCMIN) "min" set aRtext(buttCMAJ7) "maj7" set aRtext(buttCAUG5) "aug5" ## For widgets in 'fR_C#' frame: set aRtext(labC#) " C#/Db" set aRtext(buttC#MAJ) "maj" set aRtext(buttC#MIN) "min" set aRtext(buttC#MAJ7) "maj7" set aRtext(buttC#AUG5) "aug5" ## For widgets in 'fR_D' frame: set aRtext(labD) " D" set aRtext(buttDMAJ) "maj" set aRtext(buttDMIN) "min" set aRtext(buttDMAJ7) "maj7" set aRtext(buttDAUG5) "aug5" ## For widgets in 'fR_D#' frame: set aRtext(labD#) " D#/Eb" set aRtext(buttD#MAJ) "maj" set aRtext(buttD#MIN) "min" set aRtext(buttD#MAJ7) "maj7" set aRtext(buttD#AUG5) "aug5" ## For widgets in 'fR_E' frame: set aRtext(labE) " E" set aRtext(buttEMAJ) "maj" set aRtext(buttEMIN) "min" set aRtext(buttEMAJ7) "maj7" set aRtext(buttEAUG5) "aug5" ## For widgets in 'fR_F' frame: set aRtext(labF) " F" set aRtext(buttFMAJ) "maj" set aRtext(buttFMIN) "min" set aRtext(buttFMAJ7) "maj7" set aRtext(buttFAUG5) "aug5" ## For widgets in 'fR_F#' frame: set aRtext(labF#) " F#/Gb" set aRtext(buttF#MAJ) "maj" set aRtext(buttF#MIN) "min" set aRtext(buttF#MAJ7) "maj7" set aRtext(buttF#AUG5) "aug5" ## For widgets in 'fR_G' frame: set aRtext(labG) " G" set aRtext(buttGMAJ) "maj" set aRtext(buttGMIN) "min" set aRtext(buttGMAJ7) "maj7" set aRtext(buttGAUG5) "aug5" ## For widgets in 'fR_G#' frame: set aRtext(labG#) " G#/Ab" set aRtext(buttG#MAJ) "maj" set aRtext(buttG#MIN) "min" set aRtext(buttG#MAJ7) "maj7" set aRtext(buttG#AUG5) "aug5" ## For widgets in 'fR_A' frame: set aRtext(labA) " A" set aRtext(buttAMAJ) "maj" set aRtext(buttAMIN) "min" set aRtext(buttAMAJ7) "maj7" set aRtext(buttAAUG5) "aug5" ## For widgets in 'fR_A#' frame: set aRtext(labA#) " A#/Bb" set aRtext(buttA#MAJ) "maj" set aRtext(buttA#MIN) "min" set aRtext(buttA#MAJ7) "maj7" set aRtext(buttA#AUG5) "aug5" ## For widgets in 'fR_B' frame: set aRtext(labB) " B" set aRtext(buttBMAJ) "maj" set aRtext(buttBMIN) "min" set aRtext(buttBMAJ7) "maj7" set aRtext(buttBAUG5) "aug5" ## END OF if { "$VARlocale" == "en"} ##+################################################################ ## DEFINE *ALL* THE FRAMES: ## ## Top-level : '.fRbuttons' '.fRinstrmnt' '.fRbottom' ## ## Sub-frames: '.fRbottom.fR_C' ## '.fRbottom.fR_C#' ## .... at least 12 frames total, left to right ## '.fRbottom.fR_B' ##+################################################################ ## FOR TESTING change 0 to 1: ## (Example1: To see appearance of frames when borders are drawn.) ## (Example2: To see sizes of frames for various '-fill' options.) ## (Example3: To see how frames expand as window is resized.) if {0} { set RELIEF_frame raised set BDwidthPx_frame 2 } else { set RELIEF_frame flat set BDwidthPx_frame 0 } frame .fRbuttons -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRinstrmnt -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_C -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_C# -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_D -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_D# -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_E -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_F -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_F# -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_G -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_G# -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_A -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_A# -relief $RELIEF_frame -borderwidth $BDwidthPx_frame frame .fRbottom.fR_B -relief $RELIEF_frame -borderwidth $BDwidthPx_frame ##+############################## ## PACK the top-level FRAMES. ##+############################## pack .fRbuttons \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRinstrmnt \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRbottom \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRbottom.fR_C \ .fRbottom.fR_C# \ .fRbottom.fR_D \ .fRbottom.fR_D# \ .fRbottom.fR_E \ .fRbottom.fR_F \ .fRbottom.fR_F# \ .fRbottom.fR_G \ .fRbottom.fR_G# \ .fRbottom.fR_A \ .fRbottom.fR_A# \ .fRbottom.fR_B \ -side left \ -anchor nw \ -fill x \ -expand 0 ##+######################################################### ## OK. Now we are ready to define the widgets in the frames. ##+######################################################### ##+##################################################################### ## In the '.fRbuttons' FRAME --- DEFINE-and-PACK ## - an exit-button, a help-button, a play-button. ##+##################################################################### button .fRbuttons.buttEXIT \ -text "$aRtext(buttEXIT)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {exit} button .fRbuttons.buttHELP \ -text "$aRtext(buttHELP)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext" +10+10} button .fRbuttons.buttPLAY \ -text "$aRtext(buttPLAY)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_chords_file} # .fRbuttons.buttPLAY configure -state disabled label .fRbuttons.labelFILENAME \ -text "$aRtext(labelFILENAME)" \ -font fontTEMP_varwidth \ -padx $PADXpx_label \ -pady $PADYpx_label entry .fRbuttons.entryFILENAME \ -textvariable CHORDSfilename \ -width 35 \ -font fontTEMP_fixedwidth \ -bg $entryBKGD \ -relief sunken \ -bd $BDwidthPx_entry button .fRbuttons.buttGETFILE \ -text "$aRtext(buttGETFILE)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -command {get_filename} ##+########################################### ## Pack the widgets in the 'fRbuttons' frame. ##+########################################### pack .fRbuttons.buttEXIT \ .fRbuttons.buttHELP \ .fRbuttons.buttPLAY \ .fRbuttons.labelFILENAME \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbuttons.entryFILENAME \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRbuttons.buttGETFILE \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRinstrmnt' frame -- ## put a LABEL widget and 3 RADIOBUTTONS ## (for an insturment, such as 'guitar' or 'piano'). ##+######################################################## label .fRinstrmnt.labelINSTRMNT \ -text "$aRtext(labelINSTRMNT)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label ## 'VARinstrmnt' is the var for these 3 radiobuttons. set VARinstrmnt "guitar" radiobutton .fRinstrmnt.radbuttGUITAR \ -text "$aRtext(radbuttGUITAR)" \ -font fontTEMP_varwidth \ -anchor w \ -variable VARinstrmnt \ -value "guitar" \ -selectcolor "$radbuttBKGD" \ -relief $RELIEF_radbutt \ -bd $BDwidthPx_radbutt radiobutton .fRinstrmnt.radbuttPIANO \ -text "$aRtext(radbuttPIANO)" \ -font fontTEMP_varwidth \ -anchor w \ -variable VARinstrmnt \ -value "piano" \ -selectcolor "$radbuttBKGD" \ -relief $RELIEF_radbutt \ -bd $BDwidthPx_radbutt .fRinstrmnt.radbuttPIANO configure -state disabled radiobutton .fRinstrmnt.radbuttHARPSI \ -text "$aRtext(radbuttHARPSI)" \ -font fontTEMP_varwidth \ -anchor w \ -variable VARinstrmnt \ -value "harpsichord" \ -selectcolor "$radbuttBKGD" \ -relief $RELIEF_radbutt \ -bd $BDwidthPx_radbutt .fRinstrmnt.radbuttHARPSI configure -state disabled radiobutton .fRinstrmnt.radbuttHARP \ -text "$aRtext(radbuttHARP)" \ -font fontTEMP_varwidth \ -anchor w \ -variable VARinstrmnt \ -value "harp" \ -selectcolor "$radbuttBKGD" \ -relief $RELIEF_radbutt \ -bd $BDwidthPx_radbutt .fRinstrmnt.radbuttHARP configure -state disabled #+######################################### ## Provide a scale widget to set CHORDsecs. ##+######################################### label .fRinstrmnt.labelCHORDSECS \ -text "$aRtext(labelCHORDSECS)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief ridge \ -bd $BDwidthPx_label ## Set this widget var in the GUI initialization section ## at the bottom of this script. # set CHORDsecs 4.0 scale .fRinstrmnt.scaleCHORDSECS \ -from 0.5 -to 5.0 \ -resolution 0.05 \ -bigincrement 0.1 \ -repeatdelay $scaleRepeatDelayMillisecs \ -length 120 \ -font fontTEMP_SMALL_varwidth \ -variable CHORDsecs \ -showvalue true \ -orient horizontal \ -bd $BDwidthPx_scale \ -width $scaleThicknessPx ## PACK the widgets in the 'fRinstrmnt' frame. pack .fRinstrmnt.labelINSTRMNT \ .fRinstrmnt.radbuttGUITAR \ .fRinstrmnt.radbuttPIANO \ .fRinstrmnt.radbuttHARPSI \ .fRinstrmnt.radbuttHARP \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRinstrmnt.scaleCHORDSECS \ .fRinstrmnt.labelCHORDSECS \ -side right \ -anchor e \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_C' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_C.labC \ -text $aRtext(labC) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_C.buttCMAJ \ -text "$aRtext(buttCMAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Cmaj $CHORDsecs bg} button .fRbottom.fR_C.buttCMIN \ -text "$aRtext(buttCMIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Cmin $CHORDsecs bg} button .fRbottom.fR_C.buttCMAJ7 \ -text "$aRtext(buttCMAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Cmaj7 $CHORDsecs bg} button .fRbottom.fR_C.buttCAUG5 \ -text "$aRtext(buttCAUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Caug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_C' frame. pack .fRbottom.fR_C.labC \ .fRbottom.fR_C.buttCMAJ \ .fRbottom.fR_C.buttCMIN \ .fRbottom.fR_C.buttCMAJ7 \ .fRbottom.fR_C.buttCAUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_C#' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_C#.labC# \ -text $aRtext(labC#) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_C#.buttC#MAJ \ -text "$aRtext(buttC#MAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_C#maj $CHORDsecs bg} button .fRbottom.fR_C#.buttC#MIN \ -text "$aRtext(buttC#MIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_C#min $CHORDsecs bg} button .fRbottom.fR_C#.buttC#MAJ7 \ -text "$aRtext(buttC#MAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_C#maj7 $CHORDsecs bg} button .fRbottom.fR_C#.buttC#AUG5 \ -text "$aRtext(buttC#AUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_C#aug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_C#' frame. pack .fRbottom.fR_C#.labC# \ .fRbottom.fR_C#.buttC#MAJ \ .fRbottom.fR_C#.buttC#MIN \ .fRbottom.fR_C#.buttC#MAJ7 \ .fRbottom.fR_C#.buttC#AUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_D' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_D.labD \ -text $aRtext(labD) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_D.buttDMAJ \ -text "$aRtext(buttDMAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Dmaj $CHORDsecs bg} button .fRbottom.fR_D.buttDMIN \ -text "$aRtext(buttDMIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Dmin $CHORDsecs bg} button .fRbottom.fR_D.buttDMAJ7 \ -text "$aRtext(buttDMAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Dmaj7 $CHORDsecs bg} button .fRbottom.fR_D.buttDAUG5 \ -text "$aRtext(buttDAUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Daug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_D' frame. pack .fRbottom.fR_D.labD \ .fRbottom.fR_D.buttDMAJ \ .fRbottom.fR_D.buttDMIN \ .fRbottom.fR_D.buttDMAJ7 \ .fRbottom.fR_D.buttDAUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_D#' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_D#.labD# \ -text $aRtext(labD#) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_D#.buttD#MAJ \ -text "$aRtext(buttD#MAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_D#maj $CHORDsecs bg} button .fRbottom.fR_D#.buttD#MIN \ -text "$aRtext(buttD#MIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_D#min $CHORDsecs bg} button .fRbottom.fR_D#.buttD#MAJ7 \ -text "$aRtext(buttD#MAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_D#maj7 $CHORDsecs bg} button .fRbottom.fR_D#.buttD#AUG5 \ -text "$aRtext(buttD#AUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_D#aug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_D#' frame. pack .fRbottom.fR_D#.labD# \ .fRbottom.fR_D#.buttD#MAJ \ .fRbottom.fR_D#.buttD#MIN \ .fRbottom.fR_D#.buttD#MAJ7 \ .fRbottom.fR_D#.buttD#AUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_E' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_E.labE \ -text $aRtext(labE) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_E.buttEMAJ \ -text "$aRtext(buttEMAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Emaj $CHORDsecs bg} button .fRbottom.fR_E.buttEMIN \ -text "$aRtext(buttEMIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Emin $CHORDsecs bg} button .fRbottom.fR_E.buttEMAJ7 \ -text "$aRtext(buttEMAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Emaj7 $CHORDsecs bg} button .fRbottom.fR_E.buttEAUG5 \ -text "$aRtext(buttEAUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Eaug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_E' frame. pack .fRbottom.fR_E.labE \ .fRbottom.fR_E.buttEMAJ \ .fRbottom.fR_E.buttEMIN \ .fRbottom.fR_E.buttEMAJ7 \ .fRbottom.fR_E.buttEAUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_F' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_F.labF \ -text $aRtext(labF) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_F.buttFMAJ \ -text "$aRtext(buttFMAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Fmaj $CHORDsecs bg} button .fRbottom.fR_F.buttFMIN \ -text "$aRtext(buttFMIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Fmin $CHORDsecs bg} button .fRbottom.fR_F.buttFMAJ7 \ -text "$aRtext(buttFMAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Fmaj7 $CHORDsecs bg} button .fRbottom.fR_F.buttFAUG5 \ -text "$aRtext(buttFAUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Faug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_F' frame. pack .fRbottom.fR_F.labF \ .fRbottom.fR_F.buttFMAJ \ .fRbottom.fR_F.buttFMIN \ .fRbottom.fR_F.buttFMAJ7 \ .fRbottom.fR_F.buttFAUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_F#' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_F#.labF# \ -text $aRtext(labF#) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_F#.buttF#MAJ \ -text "$aRtext(buttF#MAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_F#maj $CHORDsecs bg} button .fRbottom.fR_F#.buttF#MIN \ -text "$aRtext(buttF#MIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_F#min $CHORDsecs bg} button .fRbottom.fR_F#.buttF#MAJ7 \ -text "$aRtext(buttF#MAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_F#maj7 $CHORDsecs bg} button .fRbottom.fR_F#.buttF#AUG5 \ -text "$aRtext(buttF#AUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_F#aug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_F#' frame. pack .fRbottom.fR_F#.labF# \ .fRbottom.fR_F#.buttF#MAJ \ .fRbottom.fR_F#.buttF#MIN \ .fRbottom.fR_F#.buttF#MAJ7 \ .fRbottom.fR_F#.buttF#AUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_G' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_G.labG \ -text $aRtext(labG) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_G.buttGMAJ \ -text "$aRtext(buttGMAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Gmaj $CHORDsecs bg} button .fRbottom.fR_G.buttGMIN \ -text "$aRtext(buttGMIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Gmin $CHORDsecs bg} button .fRbottom.fR_G.buttGMAJ7 \ -text "$aRtext(buttGMAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Gmaj7 $CHORDsecs bg} button .fRbottom.fR_G.buttGAUG5 \ -text "$aRtext(buttGAUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Gaug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_G' frame. pack .fRbottom.fR_G.labG \ .fRbottom.fR_G.buttGMAJ \ .fRbottom.fR_G.buttGMIN \ .fRbottom.fR_G.buttGMAJ7 \ .fRbottom.fR_G.buttGAUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_G#' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_G#.labG# \ -text $aRtext(labG#) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_G#.buttG#MAJ \ -text "$aRtext(buttG#MAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_G#maj $CHORDsecs bg} button .fRbottom.fR_G#.buttG#MIN \ -text "$aRtext(buttG#MIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_G#min $CHORDsecs bg} button .fRbottom.fR_G#.buttG#MAJ7 \ -text "$aRtext(buttG#MAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_G#maj7 $CHORDsecs bg} button .fRbottom.fR_G#.buttG#AUG5 \ -text "$aRtext(buttG#AUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_G#aug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_G#' frame. pack .fRbottom.fR_G#.labG# \ .fRbottom.fR_G#.buttG#MAJ \ .fRbottom.fR_G#.buttG#MIN \ .fRbottom.fR_G#.buttG#MAJ7 \ .fRbottom.fR_G#.buttG#AUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_A' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_A.labA \ -text $aRtext(labA) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_A.buttAMAJ \ -text "$aRtext(buttAMAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Amaj $CHORDsecs bg} button .fRbottom.fR_A.buttAMIN \ -text "$aRtext(buttAMIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Amin $CHORDsecs bg} button .fRbottom.fR_A.buttAMAJ7 \ -text "$aRtext(buttAMAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Amaj7 $CHORDsecs bg} button .fRbottom.fR_A.buttAAUG5 \ -text "$aRtext(buttAAUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Aaug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_A' frame. pack .fRbottom.fR_A.labA \ .fRbottom.fR_A.buttAMAJ \ .fRbottom.fR_A.buttAMIN \ .fRbottom.fR_A.buttAMAJ7 \ .fRbottom.fR_A.buttAAUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_A#' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_A#.labA# \ -text $aRtext(labA#) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_A#.buttA#MAJ \ -text "$aRtext(buttA#MAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_A#maj $CHORDsecs bg} button .fRbottom.fR_A#.buttA#MIN \ -text "$aRtext(buttA#MIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_A#min $CHORDsecs bg} button .fRbottom.fR_A#.buttA#MAJ7 \ -text "$aRtext(buttA#MAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_A#maj7 $CHORDsecs bg} button .fRbottom.fR_A#.buttA#AUG5 \ -text "$aRtext(buttA#AUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_A#aug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_A#' frame. pack .fRbottom.fR_A#.labA# \ .fRbottom.fR_A#.buttA#MAJ \ .fRbottom.fR_A#.buttA#MIN \ .fRbottom.fR_A#.buttA#MAJ7 \ .fRbottom.fR_A#.buttA#AUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRbottom.fR_B' frame -- ## define 4 BUTTONS. Then PACK them, top to bottom. ##+######################################################## label .fRbottom.fR_B.labB \ -text $aRtext(labB) \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief $RELIEF_label \ -bd $BDwidthPx_label button .fRbottom.fR_B.buttBMAJ \ -text "$aRtext(buttBMAJ)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Bmaj $CHORDsecs bg} button .fRbottom.fR_B.buttBMIN \ -text "$aRtext(buttBMIN)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Bmin $CHORDsecs bg} button .fRbottom.fR_B.buttBMAJ7 \ -text "$aRtext(buttBMAJ7)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Bmaj7 $CHORDsecs bg} button .fRbottom.fR_B.buttBAUG5 \ -text "$aRtext(buttBAUG5)" \ -width $WIDTHchars_button \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_Baug5 $CHORDsecs bg} ## PACK the widgets in the '.fRbottom.fR_B' frame. pack .fRbottom.fR_B.labB \ .fRbottom.fR_B.buttBMAJ \ .fRbottom.fR_B.buttBMIN \ .fRbottom.fR_B.buttBMAJ7 \ .fRbottom.fR_B.buttBAUG5 \ -side bottom \ -anchor w \ -fill none \ -expand 0 ##+######################################## ## END OF the DEFINITION OF THE GUI WIDGETS ##+######################################## ##+############################### ## BINDINGS SECTION: none, for now ##+############################### ##+###################################################################### ## PROCS SECTION: ## ## - 'play_chord' - called by the following 'play_' procs. ## ## - 'set_guitar_parms' - called in the 'Additional GUI Initialization' ## section at the bottom of this script --- to set ## parms used by the following 'play_' procs. ## ## - 'play_Cmaj' - called by a button ## - 'play_Cmin' - called by a button ## - 'play_Cmaj7' - called by a button ## - 'play_Caug5' - called by a button ## ## and 11 more groups of procs like these four. ## ## - 'get_filename' - called by the 'GetFilename' button ## - 'play_chords_file' - called by the 'PlayChordsFile' button ## ## - 'popup_msgVarWithScroll' - called by the 'Help' button ## ##+####################################################################### ##+##################################################################### ## PROC play_chord ## ## PURPOSE: Plays a chord according to arguments passed to the ## 'play' command of the Sox system. ## ## The last argument, 'fgORbg', is used to indicate whether ## to run the 'play' command in the foreground (fg) or ## background (bg) or background-and-wait (bgw), where the ## wait is hard-coded to about 1 second. ## ## The 'bgw' option allows the 'play_chords_file' proc ## to start playing a chord before the previous one is ## done decaying. ## ## CALLED BY: the following 'play_ procs. ##+##################################################################### proc play_chord {notes delays fadeparms fgORbg} { global PLAYERexe CHORDsecs if {"$fgORbg" == "fg"} { ## This 'foreground' mode can cause a rather long delay before ## a next chord can play --- because the notes' decay time may cause ## a soundless period when the last notes decay into apparent silence. eval exec $PLAYERexe -n synth $notes delay $delays \ remix - fade $fadeparms norm -1 2> /dev/null } elseif {"$fgORbg" == "bgw"} { ## This 'background-with-wait' mode is used to play chord-files. eval exec $PLAYERexe -n synth $notes delay $delays \ remix - fade $fadeparms norm -1 2> /dev/null & ## This is the 'wait' part: ## Get the 'sustain-secs' out of the 3 'fadeparms'. ## Use that to calculate a wait time (somewhat less than ## 'sustain-secs') to read-and-play the next chord (or rest). set SPLITlist [split $fadeparms] set ATTACKsecs [lindex $SPLITlist 0] set SUSTAINsecs [lindex $SPLITlist 1] set DECAYsecs [lindex $SPLITlist 2] after [expr {int(500 * $SUSTAINsecs)}] ## An alternative: # after [expr {int(1000 * ($SUSTAINsecs - (0.5 * $DECAYsecs)))}] } else { ## This 'background' mode is used for the chord buttons on the GUI ## --- to allow a chord to start playing before a previous chord ## has completely decayed. eval exec $PLAYERexe -n synth $notes delay $delays \ remix - fade $fadeparms norm -1 2> /dev/null & } } ## END OF PROC 'play_chord' ##+##################################################################### ## PROC set_guitar_parms ## ## PURPOSE: Sets values in several global vars: ## ATTACKsecs_guitar , DECAYsecs_guitar ## and DELAYS6_guitar, DELAYS5_guitar, DELAYS4_guitar ## ## CALLED BY: the 'play_' procs. ##+##################################################################### proc set_guitar_parms {} { global DELAYS6_guitar DELAYS5_guitar DELAYS4_guitar DELAYS3_guitar \ ATTACKsecs_guitar DECAYsecs_guitar ## We can experiment with the following 3 parameters ## to evaluate their effect on guitar chord sound. set ATTACKsecs_guitar 0.0 set DECAYsecs_guitar 0.5 set interPLUCKsecs_guitar 0.05 set DELAYsecs1 0.0 set DELAYsecs2 [expr {$DELAYsecs1 + $interPLUCKsecs_guitar}] set DELAYsecs3 [expr {$DELAYsecs2 + $interPLUCKsecs_guitar}] set DELAYsecs4 [expr {$DELAYsecs3 + $interPLUCKsecs_guitar}] set DELAYsecs5 [expr {$DELAYsecs4 + $interPLUCKsecs_guitar}] set DELAYsecs6 [expr {$DELAYsecs5 + $interPLUCKsecs_guitar}] set DELAYS6_guitar "$DELAYsecs1 $DELAYsecs2 $DELAYsecs3 $DELAYsecs4 $DELAYsecs5 $DELAYsecs6" set DELAYS5_guitar "$DELAYsecs1 $DELAYsecs2 $DELAYsecs3 $DELAYsecs4 $DELAYsecs5" set DELAYS4_guitar "$DELAYsecs1 $DELAYsecs2 $DELAYsecs3 $DELAYsecs4" set DELAYS3_guitar "$DELAYsecs1 $DELAYsecs2 $DELAYsecs3" ## FOR TESTING: # puts "DELAYS6_guitar: $DELAYS6_guitar" } ## END OF PROC 'set_guitar_parms' ##+##################################################################### ## PROC play_Cmaj ## ## PURPOSE: Plays a C major chord. ## ## CALLED BY: a Cmaj button. ##+##################################################################### proc play_Cmaj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl C2 pl E2 pl G2 pl C3 pl G3 pl C4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Cmaj' ##+##################################################################### ## PROC play_Cmin ## ## PURPOSE: Plays a C minor chord. ## ## CALLED BY: a Cmin button. ##+##################################################################### proc play_Cmin {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl C2 pl D#2 pl G2 pl C3 pl G3 pl C4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg # play_chord "pl C2 pl D#2 pl G2 pl C3" \ # "$DELAYS4_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg # play_chord "pl C2 pl D#2 pl G2" \ # "$DELAYS3guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg # play_chord "pl C2 pl D#2 pl G2 pl D#3" \ # "$DELAYS4_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl C2 pl D#2 pl G2 pl C3 pl D#3" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Cmin' ##+##################################################################### ## PROC play_Cmaj7 ## ## PURPOSE: Plays a C major 7th chord. ## ## CALLED BY: a Cmaj7 button. ##+##################################################################### proc play_Cmaj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl C2 pl E2 pl G2 pl A#3 pl C3 pl G3" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Cmaj7' ##+##################################################################### ## PROC play_Caug5 ## ## PURPOSE: Plays a C augmented 5th chord. ## ## CALLED BY: a Caug5 button. ##+##################################################################### proc play_Caug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl C2 pl E2 pl G#2 pl C3 pl G#3 pl C4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Caug5' ##+##################################################################### ## PROC play_C#maj ## ## PURPOSE: Plays a C# major chord. ## ## CALLED BY: a C#maj button. ##+##################################################################### proc play_C#maj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl C#2 pl E#2 pl G#2 pl C#3 pl G#3 pl C#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_C#maj' ##+##################################################################### ## PROC play_C#min ## ## PURPOSE: Plays a C# minor chord. ## ## CALLED BY: a C#min button. ##+##################################################################### proc play_C#min {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl C#2 pl E2 pl G#2 pl C#3 pl G#3 pl C#4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl C#2 pl E2 pl G#2 pl C#3 pl E3" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_C#min' ##+##################################################################### ## PROC play_C#maj7 ## ## PURPOSE: Plays a C# major 7th chord. ## ## CALLED BY: a C#maj7 button. ##+##################################################################### proc play_C#maj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl C#2 pl E#2 pl G#2 pl B3 pl C#3 pl G#3" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_C#maj7' ##+##################################################################### ## PROC play_C#aug5 ## ## PURPOSE: Plays a C# augmented 5th chord. ## ## CALLED BY: a C#aug5 button. ##+##################################################################### proc play_C#aug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl C#2 pl E#2 pl A3 pl C#3 pl A4 pl C#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_C#aug5' ##+##################################################################### ## PROC play_Dmaj ## ## PURPOSE: Plays a D major chord. ## ## CALLED BY: a D major button. ##+##################################################################### proc play_Dmaj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl D2 pl F#2 pl A3 pl D3 pl A4 pl D4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Dmaj' ##+##################################################################### ## PROC play_Dmin ## ## PURPOSE: Plays a D minor chord. ## ## CALLED BY: a Dmin button. ##+##################################################################### proc play_Dmin {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl D2 pl F2 pl A3 pl D3 pl A4 pl D4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl D2 pl F2 pl A3 pl D3 pl F3" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Dmin' ##+##################################################################### ## PROC play_Dmaj7 ## ## PURPOSE: Plays a D major 7th chord. ## ## CALLED BY: a Dmaj7 button. ##+##################################################################### proc play_Dmaj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl D2 pl F#2 pl A3 pl C3 pl D3 pl A4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Dmaj7' ##+##################################################################### ## PROC play_Daug5 ## ## PURPOSE: Plays a D augmented 5th chord. ## ## CALLED BY: a Daug5 button. ##+##################################################################### proc play_Daug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl D2 pl F#2 pl A#3 pl D3 pl A#4 pl D4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Daug5' ##+##################################################################### ## PROC play_D#maj ## ## PURPOSE: Plays a D# major chord. ## ## CALLED BY: a D# major button. ##+##################################################################### proc play_D#maj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl D#2 pl G2 pl A#3 pl D#3 pl A#4 pl D#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_D#maj' ##+##################################################################### ## PROC play_D#min ## ## PURPOSE: Plays a D# minor chord. ## ## CALLED BY: a D#min button. ##+##################################################################### proc play_D#min {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl D#2 pl F#2 pl A#3 pl D#3 pl A#4 pl D#4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl D#2 pl F#2 pl A#3 pl D#3 pl F#3" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_D#min' ##+##################################################################### ## PROC play_D#maj7 ## ## PURPOSE: Plays a D# major 7th chord. ## ## CALLED BY: a D#maj7 button. ##+##################################################################### proc play_D#maj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl D#2 pl G2 pl A#3 pl C#3 pl D#3 pl A#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_D#maj7' ##+##################################################################### ## PROC play_D#aug5 ## ## PURPOSE: Plays a D# augmented 5th chord. ## ## CALLED BY: a D#aug5 button. ##+##################################################################### proc play_D#aug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl D#2 pl G2 pl B3 pl D#3 pl B4 pl D#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_D#aug5' ##+##################################################################### ## PROC play_Emaj ## ## PURPOSE: Plays a E major chord. ## ## CALLED BY: a E major button. ##+##################################################################### proc play_Emaj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl E2 pl G#2 pl B3 pl E3 pl B4 pl E4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Emaj' ##+##################################################################### ## PROC play_Emin ## ## PURPOSE: Plays a E minor chord. ## ## CALLED BY: a Emin button. ##+##################################################################### proc play_Emin {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl E2 pl G2 pl B3 pl E3 pl G3 pl E4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl E2 pl G2 pl B3 pl E3 pl G3" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Emin' ##+##################################################################### ## PROC play_Emaj7 ## ## PURPOSE: Plays a E major 7th chord. ## ## CALLED BY: a Emaj7 button. ##+##################################################################### proc play_Emaj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl E2 pl G#2 pl B3 pl D3 pl E3 pl B3" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Emaj7' ##+##################################################################### ## PROC play_Eaug5 ## ## PURPOSE: Plays a E augmented 5th chord. ## ## CALLED BY: a Eaug5 button. ##+##################################################################### proc play_Eaug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl E2 pl G#2 pl C3 pl E3 pl C4 pl E4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Eaug5' ##+##################################################################### ## PROC play_Fmaj ## ## PURPOSE: Plays a F major chord. ## ## CALLED BY: a F major button. ##+##################################################################### proc play_Fmaj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl F2 pl A3 pl C3 pl F3 pl C4 pl F4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Fmaj' ##+##################################################################### ## PROC play_Fmin ## ## PURPOSE: Plays a F minor chord. ## ## CALLED BY: a Fmin button. ##+##################################################################### proc play_Fmin {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl F2 pl G#2 pl C3 pl F3 pl C4 pl F4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl F2 pl G#2 pl C3 pl F3 pl G#4" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Fmin' ##+##################################################################### ## PROC play_Fmaj7 ## ## PURPOSE: Plays a F major 7th chord. ## ## CALLED BY: a Fmaj7 button. ##+##################################################################### proc play_Fmaj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl F2 pl A3 pl C3 pl D#3 pl F3 pl A4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Fmaj7' ##+##################################################################### ## PROC play_Faug5 ## ## PURPOSE: Plays a F augmented 5th chord. ## ## CALLED BY: a Faug5 button. ##+##################################################################### proc play_Faug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl F2 pl A3 pl C#3 pl F3 pl C#4 pl F4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Faug5' ##+##################################################################### ## PROC play_F#maj ## ## PURPOSE: Plays a F# major chord. ## ## CALLED BY: a F# major button. ##+##################################################################### proc play_F#maj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl F#2 pl A#2 pl C#3 pl F#3 pl C#4 pl F#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_F#maj' ##+##################################################################### ## PROC play_F#min ## ## PURPOSE: Plays a F# minor chord. ## ## CALLED BY: a F#min button. ##+##################################################################### proc play_F#min {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl F#2 pl A3 pl C#3 pl F#3 pl C#4 pl F#4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl F#2 pl A3 pl C#3 pl F#3 pl A4" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_F#min' ##+##################################################################### ## PROC play_F#maj7 ## ## PURPOSE: Plays a F# major 7th chord. ## ## CALLED BY: a F#maj7 button. ##+##################################################################### proc play_F#maj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl F#2 pl A#3 pl C#3 pl E3 pl F#3 pl A#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_F#maj7' ##+##################################################################### ## PROC play_F#aug5 ## ## PURPOSE: Plays a F# augmented 5th chord. ## ## CALLED BY: a F#aug5 button. ##+##################################################################### proc play_F#aug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl F#2 pl A#3 pl D3 pl F#3 pl D4 pl F#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_F#aug5' ##+##################################################################### ## PROC play_Gmaj ## ## PURPOSE: Plays a G major chord. ## ## CALLED BY: a G major button. ##+##################################################################### proc play_Gmaj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl G2 pl B2 pl D3 pl G3 pl D4 pl G4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Gmaj' ##+##################################################################### ## PROC play_Gmin ## ## PURPOSE: Plays a G minor chord. ## ## CALLED BY: a Gmin button. ##+##################################################################### proc play_Gmin {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl G2 pl A#3 pl D3 pl G3 pl D4 pl G4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl G2 pl A#3 pl D3 pl G3 pl A#4" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Gmin' ##+##################################################################### ## PROC play_Gmaj7 ## ## PURPOSE: Plays a G major 7th chord. ## ## CALLED BY: a Gmaj7 button. ##+##################################################################### proc play_Gmaj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl G2 pl B3 pl D3 pl F3 pl G3 pl B4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Gmaj7' ##+##################################################################### ## PROC play_Gaug5 ## ## PURPOSE: Plays a G augmented 5th chord. ## ## CALLED BY: a Gaug5 button. ##+##################################################################### proc play_Gaug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl G2 pl B3 pl D#3 pl G3 pl D#4 pl G4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Gaug5' ##+##################################################################### ## PROC play_G#maj ## ## PURPOSE: Plays a G# major chord. ## ## CALLED BY: a G# major button. ##+##################################################################### proc play_G#maj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl G#2 pl C2 pl D#3 pl G#3 pl D#4 pl G#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_G#maj' ##+##################################################################### ## PROC play_G#min ## ## PURPOSE: Plays a G# minor chord. ## ## CALLED BY: a G#min button. ##+##################################################################### proc play_G#min {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl G#2 pl B3 pl D#3 pl G#3 pl D#4 pl G#4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl G#2 pl B3 pl D#3 pl G#3 pl B4" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_G#min' ##+##################################################################### ## PROC play_G#maj7 ## ## PURPOSE: Plays a G# major 7th chord. ## ## CALLED BY: a G#maj7 button. ##+##################################################################### proc play_G#maj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl G#2 pl C3 pl D#3 pl F#3 pl G#3 pl C4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_G#maj7' ##+##################################################################### ## PROC play_G#aug5 ## ## PURPOSE: Plays a G# augmented 5th chord. ## ## CALLED BY: a G#aug5 button. ##+##################################################################### proc play_G#aug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl G#2 pl C3 pl E3 pl G#3 pl E4 pl G#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_G#aug5' ##+##################################################################### ## PROC play_Amaj ## ## PURPOSE: Plays a A major chord. ## ## CALLED BY: a A major button. ##+##################################################################### proc play_Amaj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl A2 pl C#2 pl E3 pl A3 pl E4 pl A4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Amaj' ##+##################################################################### ## PROC play_Amin ## ## PURPOSE: Plays a A minor chord. ## ## CALLED BY: a Amin button. ##+##################################################################### proc play_Amin {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl A2 pl C2 pl E2 pl A3 pl E3 pl A4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl A2 pl C2 pl E2 pl A3 pl C4" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Amin' ##+##################################################################### ## PROC play_Amaj7 ## ## PURPOSE: Plays a A major 7th chord. ## ## CALLED BY: a Amaj7 button. ##+##################################################################### proc play_Amaj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl A2 pl C#2 pl E2 pl G2 pl A3 pl C#3" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Amaj7' ##+##################################################################### ## PROC play_Aaug5 ## ## PURPOSE: Plays a A augmented 5th chord. ## ## CALLED BY: a Aaug5 button. ##+##################################################################### proc play_Aaug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl A2 pl C#3 pl F3 pl A3 pl F4 pl A4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Aaug5' ##+##################################################################### ## PROC play_A#maj ## ## PURPOSE: Plays a A# major chord. ## ## CALLED BY: a A# major button. ##+##################################################################### proc play_A#maj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl A#2 pl D2 pl F3 pl A#3 pl D4 pl F4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_A#maj' ##+##################################################################### ## PROC play_A#min ## ## PURPOSE: Plays a A# minor chord. ## ## CALLED BY: a A#min button. ##+##################################################################### proc play_A#min {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl A#2 pl C#2 pl F2 pl A#3 pl F3 pl A#4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl A#2 pl C#2 pl F2 pl A#3 pl C#3" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_A#min' ##+##################################################################### ## PROC play_A#maj7 ## ## PURPOSE: Plays a A# major 7th chord. ## ## CALLED BY: a A#maj7 button. ##+##################################################################### proc play_A#maj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl A#2 pl D2 pl F2 pl G#2 pl A#3 pl D3" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_A#maj7' ##+##################################################################### ## PROC play_A#aug5 ## ## PURPOSE: Plays a A# augmented 5th chord. ## ## CALLED BY: a A#aug5 button. ##+##################################################################### proc play_A#aug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl A#2 pl D2 pl F#2 pl A#3 pl F#3 pl A#4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_A#aug5' ##+##################################################################### ## PROC play_Bmaj ## ## PURPOSE: Plays a B major chord. ## ## CALLED BY: a B major button. ##+##################################################################### proc play_Bmaj {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl B2 pl D#2 pl F#3 pl B3 pl F#4 pl B4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Bmaj' ##+##################################################################### ## PROC play_Bmin ## ## PURPOSE: Plays a B minor chord. ## ## CALLED BY: a Bmin button. ##+##################################################################### proc play_Bmin {secs fgORbg} { global VARinstrmnt DELAYS5_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { # play_chord "pl B2 pl D2 pl F#2 pl B3 pl F#3 pl B4" \ # "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg play_chord "pl B2 pl D2 pl F#2 pl B3 pl D3" \ "$DELAYS5_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Bmin' ##+##################################################################### ## PROC play_Bmaj7 ## ## PURPOSE: Plays a B major 7th chord. ## ## CALLED BY: a Bmaj7 button. ##+##################################################################### proc play_Bmaj7 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl B2 pl D#2 pl F#2 pl A3 pl B3 pl D#3" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Bmaj7' ##+##################################################################### ## PROC play_Baug5 ## ## PURPOSE: Plays a B augmented 5th chord. ## ## CALLED BY: a Baug5 button. ##+##################################################################### proc play_Baug5 {secs fgORbg} { global VARinstrmnt DELAYS6_guitar ATTACKsecs_guitar DECAYsecs_guitar if {"$VARinstrmnt" == "guitar"} { play_chord "pl B2 pl D#2 pl G2 pl B3 pl G3 pl B4" \ "$DELAYS6_guitar" "$ATTACKsecs_guitar $secs $DECAYsecs_guitar" $fgORbg } } ## END OF PROC 'play_Baug5' ##+##################################################################### ## PROC play_R ## ## PURPOSE: 'Plays' a rest by pausing the indicated amount of time. ## ## CALLED BY: proc 'play_chords_file' ##+##################################################################### proc play_R {secs fgORbg} { set millisecs [expr {int(1000 * $secs)}] after $millisecs } ## END OF PROC 'play_R' ##+#################################################################### ## PROC: 'get_filename' ##+#################################################################### ## PURPOSE: To load a filename into the CHORDSfilename global var. ## METHOD: Uses the built-in Tk utility 'tk_getOpenFile'. ## CALLED BY: button .fRbuttons.buttGETFILE ##+#################################################################### proc get_filename { } { global CHORDSfilename DIRin env ############################################# ## Get a chords file name. ############################################# set fName [tk_getOpenFile -parent . \ -title "Select Directory-and-Filename - of a chords file" \ -initialdir "$DIRin" ] ## FOR TESTING: # puts "fName : $fName" ################################ ## Check if fName var is empty. ################################ if {"$fName" == ""} {return} ##################################################### ## Put $fName in CHORDSfilename. Reset the DIRin var. ##################################################### if {[file exists "$fName"]} { set CHORDSfilename "$fName" ## Put the end of the filename in view. .fRbuttons.entryFILENAME xview end set DIRin [ dirname "$CHORDSfilename" ] } ## END OF if file-exists } ## END of proc 'get_filename' ##+######################################################################## ## PROC 'play_chords_file' ##+######################################################################## ## PURPOSE: Reads the chords file with filename CHORDSfilename ## and plays each chord specified in the file for the ## specified time. ## ## METHOD: Reads each record and uses the appropriate ## 'play_' proc to play the chord for the ## indicated time. Rests are skipped (no playing) ## for the specified time. 'R' indicates a rest. ## ## Example format of a chords file for this utility: ## ## 1.0 Cmaj ## 1.0 Cmaj ## 1.0 Fmaj ## 1.0 Gmaj ## 1.0 Cmaj ## 1.0 R ## 0.5 Gmaj ## 0.5 Fmaj ## 0.5 Cmaj ## 0.5 Cmaj ## ## To allow the user some control over the time each chord is 'held', ## these time values are multiplied times the global CHORDsecs value ## (from the scale widget on the GUI) to control the time that the ## chords are played --- and the time when the next note is started. ## ## CALLED BY: the 'PlayChordsFile' button ##+######################################################################## proc play_chords_file {} { ## FOR TESING: (to dummy out this proc) # return global CHORDSfilename CHORDsecs ############################################ ## Open the file, with some error checking. ############################################ ## This is too simplistic: ## set f [open "$CHORDSfilename" r] ############################################ set RETcode [catch "open $CHORDSfilename r" f] ## FOR TESTING: # puts "proc 'play_chords_file' > RETcode: $RETcode" if {"$RETcode" == "1"} { set FILEopenERRmsg "Cannot open file $CHORDSfilename It is likely that the file is not found. Check spelling." popup_msgVarWithScroll_wait .fRerrmsg "$FILEopenERRmsg" return } ############################################################# ## START OF WHILE-LOOP for the 'gets' file-READING. ## The while-test below is equivalent to 'while {![eof $f]}'. ############################################################# while {[eof $f] == 0} { ############################################################ ## GET the next line (up to a line feed) --- and its length. ############################################################ set lineLen [gets $f line] ################################################# ## Remove white space from both ends of the line. ################################################# set line [string trim $line] ###################################################### ## If the record is empty, skip it, read the next rec. ###################################################### if {"$line" == ""} {continue} ################################################################# ## If the record is a comment record, skip it, read the next rec. ################################################################# set recCOL1 [ string range $line 0 0 ] if {"$recCOL1" == "#"} {continue} ################################################################# ## If we get to this point, this should be a valid chord record ## containing a time (in seconds) and a chord name such as Gmaj7. ## ## Split the line into separate list items. ## Then put col1 item into var TEMPtime ## and put col2 item into var TEMPname. ################################################################# set SPLITlist [split $line] set TEMPtime [lindex $SPLITlist 0] set TEMPname [lindex $SPLITlist 1] ################################################################# ## Set the chord 'sustain' time (including decay time). ################################################################# set TEMPsecs [expr {$TEMPtime * $CHORDsecs}] ################################################################# ## Play the specified chord for the specified time. ################################################################# # eval play_${TEMPname} $TEMPsecs fg ;# Too slow in playing next chord. eval play_${TEMPname} $TEMPsecs bgw } ## END OF LOOP while {[eof $f] == 0} ###################################### ## We hit end of file. Close the file. ###################################### close $f } ## END OF PROC 'play_chords_file' ##+######################################################################## ## PROC 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we use this 'toplevel-text' method, ## rather than the 'tk_dialog' method -- like on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext ULloc} { ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global. ## global fontTEMP_fixedwidth #; Not needed. 'wish' makes this global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 # wm geometry $toplevName +100+50 wm geometry $toplevName $ULloc wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### if {$VARheight > 10} { text $toplevName.text \ -wrap none \ -font fontTEMP_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" } else { text $toplevName.text \ -wrap none \ -font fontTEMP_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 } button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 if {$VARheight > 10} { ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } else { pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+######################################################## ## Set the 'HELPtext' var. ##+######################################################## set HELPtext "\ \ \ ** HELP for this Play-Chords GUI utility ** (an initial, experimental utility) This Tk GUI script allows the user to play guitar chords by clicking on buttons that are in 12 columns corresponding to 12 notes in an octave scale. (More columns/octaves could be added by editing this Tk script.) The buttons in each column allow the user to play - major - minor - major-seventh - augmented-fifth chords. (Additional chords could be added by editing this Tk script to add buttons to each stack/column, where each stack/column corresponds to a note of the musical scale. For example, a minor-seventh chord could be added by adding one button in each stack/column.) (Eventually, the intent is to add the ability to play chords that sound like they come from other instruments --- piano, harpsichord, harp, chimes, etc. --- by simply changing a radiobutton setting on the GUI.) ************** METHOD OF PLAY: The chords are played with the 'play' command (that comes with the 'sox' audio command system) --- with commands like this guitar example from the 'man' help for sox: play -n synth pl G2 pl B2 pl D3 pl G3 pl D4 pl G4 \\ delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1 which plays 6 notes over multiple octaves in a G major chord, and where 'pl' is an abbreviation for 'pluck'. ************************ The 'Chord secs' option The 'Chord secs' scale widget on the GUI allows the user to experiment with the length of the chord played by the chord buttons. This length corresponds to the '4' in the '0 4 .1' string in the 'fade' parameter in the command above. Other parameters such as the attack (fade-in) and decay (fade-out) parameters of 'fade' are hard-coded in this utility. The user can experiment with them by editing their values in the 'set_guitar_parms' proc. *************************** The 'PlayChordsFile' Option This utility includes an option to read a text file containing a sequence of chord names (one per line in the text file) and play those chords. The length of each chord (in 'normalized' time units) is supplied with the chord name. The file also allows for specifying pauses ('rests') in the 'chords file'. Example format: ## START OF FILE ## Format of each record: chord-time chord-name ## ## 'R' indicates a rest. A rest generates a pause ## for the specified time. ## ## Empty lines and lines starting with '#' are not played. ## 1.0 Cmaj 1.0 Cmaj 1.0 Fmaj 1.0 Gmaj 1.0 Cmaj 1.0 Cmaj 0.5 Gmaj 0.5 R 0.5 Fmaj 0.5 R 1.0 Cmaj 1.0 Cmaj ## END OF FILE The 'Chord secs' value of the scale widget on the GUI is also used to control the number of seconds assigned to each of these time units. For example, if 'Chord secs' on the GUI is set to 3.0 seconds, each of the 1.0 units in the example above should 'render' in about 3.0 seconds and each of the 0.5 units in the example above should 'render' in about 1.5 seconds. *************** NOTES IN CHORDS: (12 chords, C to B) The chords could be formed using various note combinations. For example, a C-major chord could start with a 5th note (G) rather than the 'tonic' note (C). And various octaves could be involved. For each chord (for example, C-major) we supply a single combination of notes --- basically using the following note sequences in each chord. Add Chord Major Minor 7th Aug(+) ------ ------ ------ ---- ------ C C,E,G C,Eb,G Bb C,E,G# Db/C# Db,F,Ab Db,E,Ab B Db,F,A D D,F#,A D,F,A C D,F#,Bb Eb/D# Eb,G,Bb Eb,Gb,Bb Db Eb,G,B E E,G#,B E,G,B D E,G#,C F F,A,C F,Ab,C Eb F,A,C# Gb/F# Gb,Bb,Db Gb,A,Db E Gb,Bb,D G G,B,D G,Bb,D F G,B,D# Ab/G# Ab,C,Eb Ab,B,Eb F# Ab,C,E A A,C#,E A,C,E G A,C#,F Bb/A# Bb,D,F Bb,Db,F Ab Bb,D,Gb B B,D#,F# B,D,F# A B,D#,G NOTE: Major chord - made up of the 1,3, and 5 notes in the scale of the chord's key. Minor chord - flat the 3rd note of the major chord. Augmented-fifth chord - sharp the 5th note of the major chord. Major 7th chord - add the flatted 7th note of the scale to the major chord. ********************* VARIOUS INSTRUMENTS: Eventually (when we can determine appropriate parameters for the Sox 'play' command), we may activate the instrument-radiobuttons on the GUI --- to allow for playing the chords such that they sound like they are coming from a piano or harpsichord or harp or pipe-organ or chimes or another instrument. ********************* SOME UNSETTLED ISSUES: When clicking on the chord-buttons, there may be times when the chord does not immediately play. It would be nice to be able to guarantee that a chord plays precisely when it is requested. Some similar timing issues may be encountered when playing chords in a chord-file. " ##+##################################################### ##+##################################################### ## ADDITIONAL GUI INITIALIZATION, if needed (or wanted). ##+##################################################### ##+##################################################### ##+######################################################## ## Set the name of the audio player --- the 'play' command ## of the Sox system. ##+######################################################## set PLAYERexe "/usr/bin/play" ##+##################################################### ## Set the full-name of the directory containing this ## Tk script. ##+##################################################### ## FOR TESTING: # puts "argv0: $argv0" set DIRthisScript "[file dirname $argv0]" ## For ease of testing in a Linux/Unix terminal and located at the ## directory containing this Tk script. Set the full directory name. if {"$DIRthisScript" == "."} { set DIRthisScript "[pwd]" } ##+######################################################## ## Set the initial name of a directory from which to start ## searching for chord files. ##+######################################################## # set DIRin "$env(HOME)" # set DIRin "/tmp" set DIRin "$DIRthisScript" ##+######################################################## ## Set an initial chord time --- which is user-selectable ## by a scale widget on the GUI. ##+######################################################## set CHORDsecs 4.0 ##+######################################################## ## Set values of global variables used for guitar chords. ##+######################################################## set_guitar_parms ##+######################################################## ## Set the initial name of aan example chords file -- ## for immediate availability for playing with the 'play' ## command of the Sox system. ##+######################################################## set CHORDSfilename "$DIRin/chords_example.txt" ## Put the end of the filename in view. .fRbuttons.entryFILENAME xview end