Audio Edit Utility - Clip, Change-Volume, Convert, etc. - a front-end for the 'ffmpeg' command

uniquename - 2014jun22

I recently (2014jun18) published a utility for editing movie files at a page titled

Movie Edit Utility - Clip, Crop, Convert, etc. - a front-end for the 'ffmpeg' command

I mentioned at the bottom of that page that I planned to create a similar 'ffmpeg'-based 'tkAudioEdit' utility.

Such an AUDIO-file-editing utility (a front-end for the 'ffmpeg' command) is the subject of this page.

Like the title of this page implies, the main functions of that utility are intended to be

  • extracting audio 'clips'
  • changing the audio volume
  • converting to another audio format

for audio files of the many formats supported by the 'ffmpeg' command.

---

THE GOALS

My goals for the Tcl-Tk script for this GUI were similar to those for the 'tkMovieEdit' utility, but without the video options. Namely:

*** Provide entry widgets for an input audio file and an output audio file --- along with a 'Browse' button to easily select the input file.

*** Provide a listbox widget by which to select the edit operation to be performed --- CLIP, CHG-VOLUME, CONVERT, etc. Also provide PROPERTIES-IN and PROPERTIES-OUT options to query the properties of the input and output files --- after they have been selected and created, respectively.

*** Provide entry widgets for the approximately 5 parameters that can be specified to 'ffmpeg' to specify the audio parameters for creating the output audio file. Provide working defaults for the parameters.

*** Provide an 'ExecOption' button to start the execution of the option that the user selected from the listbox.

*** Provide an entry widget to allow the user to specify an audio-file-player program with which to play either the input or the output audio file.

*** To avoid overwhelming the user with the number of recording parameters available, provide a checkbutton on the GUI to only show the audio-and-other parameters if the user requests to see them.

---

THE GUI LAYOUT

Like for the 'movie-edit' utility that I posted here, I made a 'text-sketch' for the GUI for this 'audio-edit' utility.

CONVENTIONS for the GUI 'text-sketch' below:

  • SQUARE-BRACKETS indicate a comment not to be included 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.
  ----------------------------------------------------------------------------------------
  Audio Edit ( Clip, Change Volume, Convert, Etc. ) - a front-end for the 'ffmpeg' command
  [window title]
  ----------------------------------------------------------------------------------------

  [On the left of the following frames will be a Tk 'listbox' widget in frame '.fRleft'.
   The following frames will be contained in frame '.fRright'.]

  '.fRright'
   SubFrame
    names
     |
     V

 .fRbuttons   {Exit} {Help} {ExecOption} {PlayOutAudio} {PlayInAudio}  X MoreAudioOutParms (audio,other)

 .fRinfile    Input audio filename : $env(HOME)/input_audio.mp3_______________________  {Browse...}

 .fRmsg       Select an input file and an audio-processing option from the listbox on the left. Then provide
              processing parameters at prompts in the 'ExecOption Parameters' section that appears below.
              An 'xterm' window will appear when processing starts. You can see processing messages in
              that window. When processing is finished, use the 'PlayOutAudio' button to play the audio.
              [This initial message in a label widget may be changed when the 'Exec' button is clicked.]

              --------------------------------------------------------------------------------------
 .fRoutHead   Output File parameters:
              --------------------------------------------------------------------------------------

 .fRencoder   Encoding format: O MP3 (.mp3)  O Vorbis (.oga)  O AAC (.aac)  O FLAC (.flac)  O Mpeg2 (.mp2)

 .fRoutfile   Output audio filename : /tmp/$env(USER)_output_audio.mp3___________________

 .fRplayer    Player for audio in/out file: xffplay____ Examples: xffplay  xmplayer   gmplayer  totem  vlc {Help}

              --------------------------------------------------------------------------------------
 .fRoptsHead   ExecOption Parameters:   [This label may dynamically change according to option selected.
                                        Examples: '  (CLIP)' or  ' (CONVERT)' may be added after 'Parameters:'.]
              --------------------------------------------------------------------------------------

 .fRexecOpts  [The sub-frames and widgets that appear here
               will depend on the listbox line currently selected.
               An example, for CLIP, is seen in a screenshot below.]

 .fRaudparms  [This frame and its following subframes are shown if
               the 'MoreAudioOutParms' checkbuttons is set ON.]

  '.fRaudparms'
   SubFrame
    names
     |
     V
              -------------------------------------------------------------------------------------
 .fRaudioHead Audio-out parameters:
              -------------------------------------------------------------------------------------

 .fRacodec    Audio-out Codec: libmp3lame__ Examples: libmp3lame  libvorbis  libfaac  flac  mp2  pcm_s16le 

 .fRachannels Audio-out Channels: 1_ Examples: 1  2

 .fRasrate    Audio-out Sampling Rate: 22050__ Examples: 44100 22050 11025

 .fRabrate    Audio-out Bit Rate: 96k__ Examples: 64k  96k  128k  160k  192k (multiples of 32k)

 .fRaother    Other audio-out parms: _________________________________________________

              --------------------------------------------------------------------------------------
 .fRother     Other output recording parameters:
              --------------------------------------------------------------------------------------

 .fRthreads   Threads: 1___ (to take advantage of a multi-core computer ; may not work for some coders)

 .fRguide     NOTE: This utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages from 'ffmpeg'
              can be seen in that window. You may minimize the 'xterm' window while processing, if you do not
              want to monitor the processing messages. When processing is done, the terminal does not close,
              so that you can examine messages. The output file, if good, can be shown in an audio player,
              that you specify above.  See 'Help' for details.
              [a 'label' widget]
             ---------------------------------------------------------------------------------------

---

GUI Components

From the GUI 'sketch' above, it is seen that the GUI (not counting the widgets in the 'execOpts' frame) consists of ABOUT:

   7 'button' widgets
  22 'label'  widgets (many are for entry fields)
   9 'entry'  widgets
   1 'checkbutton' widget
   5 'radiobutton' widgets (in one group)
   1 'listbox' widget (with scrollbars)
   0 'scale'  widgets
   0 'canvas' widgets
   0 'text' widgets

All but the 'label' widgets provide operating parameters/options in this utility. Hence there are about 7+9+1+5 = 22 options on this utility --- not counting the user-selectable options in the listbox (approximately another 7 options, eventually) --- and most of those 7 'exec-options' have input parameters.

---

I should point out here that I was not especially interested in coming up with a 'beautiful utility'. I just wanted a utility that would make 'semi-interactive' editing of audio files with 'ffmpeg' as simple as a few clicks --- on a listbox and an 'Exec' button and a 'Play' button --- and perhaps entering a few characters in a couple of entry widgets.

I am certainly interested in making pretty GUI's --- as I have expressed on my 'bio' page at uniquename, and as my pages at Experiments in making embellished GUI's and Version 2 of a demo of THEMES for Tk GUI's, using images and colors have indicated.

But at this time, I am satisfied to implement the 'functionality', and let the 'beauty' go for a later date (when I have more beauty tools/code at hand).


SCREENSHOTS OF THE GUI

On the basis of the GUI-layout sketch above, I ended up with the GUI seen in the following image.

tkAudioEdit_initialGUI_screenshot_835x307.jpg

The basic operatiing sequence is

0) Select an input audio file. The 'Browse..' button to the right of the audio filename entry filed to select a valid filename.

1) Click on the listbox to select an option, like CLIP.

2) Enter option parameters in the widgets that pop up in the 'ExecOption Parameters' section/frame of the GUI.

3) Optionally, use the 'PlayInMovie' and/or the 'PROPERTIES-IN' options to get information needed to set some editing parameters.

4) Optionally, change the audio 'encoding' format for the output file, via the radiobuttons on the GUI --- and optionally use the 'MoreAudioOutParms' checkbutton to reveal the audio-and-other parameters that can be changed.

5) Click on the 'ExecOption' button to launch the 'ffmpeg' job.

6) When the output is complete, use the 'PlayOutMovie' button (and perhaps the 'PROPERTIES-OUT' option) on the output audio file.

(You can change some of the initial values on the GUI, like the initial encoding-format, by changing a 'set ENCODERname' statement at the bottom of the Tk script.)

---

If the user wants to change (or simply check) the audio and 'other' parameters that are set according to a choice of the 'encoding format', the user can click on the 'MoreAudioOutParms' checkbutton at the top of the GUI.

When that checkbutton is clicked, the GUI expands downward, as can be seen in the following image.

tkAudioEdit_expandedGUI_audioParms_screenshot_841x609.jpg

---

When the 'ExecOption' button is clicked and an 'ffmpeg' edit operation starts, an 'xterm' window pops up that shows the messages coming from the 'ffmpeg' program during its operation.

---

THE AUDIO ENCODING FORMATS

I tested the 5 encoding-format radiobuttons to confirm that the audio parameters that I have provided for each encoding-format do indeed result in a successful output audio file creation.

So I have created '.mp3' , '.oga' , '.aac' , '.flac' , and '.mp2' files.

When the user clicks on the 'Help' button of the GUI, there is some information on these formats --- and many web links (URL's) that will give further information.


DESCRIPTION OF THE CODE

Below, I provide the Tk script code for this 'audio-edit' utility.

I follow my usual 'canonical' structure for Tk code for this Tk script:

  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts-for-widgets, widget-geometry-parms,
     text-array-for-labels-etc, win-size-control).

  1a) Define ALL frames (and sub-frames, if any).
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.
              Within each frame, define ALL the widgets.
              Then pack the widgets.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.

This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This structure makes it easy for me to find code sections --- while generating and testing a Tk script, and when looking for code snippets to include in other scripts (code re-use).

I call your attention to step-zero. One thing that I started doing in 2013 is use of a text-array for text in labels, buttons, and other widgets in the GUI. This can make it easier for people to internationalize my scripts. I will be using a text-array like this in most of my scripts in the future.


Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', '-expand' --- on all of the 'pack' commands for the frames and widgets.

That helps me when I am initially testing the behavior of a GUI (the various widgets within it) as I resize the main window.

I think that I have used a pretty nice choice of the 'pack' parameters. The label and button and radiobutton widgets stay fixed in size and relative-location if the window is re-sized --- while the input/output filename and 'player-program' entry widgets expand/contract horizontally whenever the window is re-sized horizontally.

I decided to make the listbox width fixed and devote most of the window space to the widgets on the right side of the GUI.

You can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various frames and widgets --- to get the widget behavior that you want.

---

Additional experimentation: You might want to change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'normal' to 'bold' (if you have a screen resolution bigger than 1024x768) --- or change '-slant' from 'roman' to 'italic' --- or change the font sizes. Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding. And I have included the '-relief' parameter on the definitions of frames and widgets. Feel free to experiment with those 'appearance' parameters as well.

If you find the gray palette of the GUI is not to your liking, you can change the value of the RGB parameter supplied to the 'tk_setPalette' command near the top of the code.


Some features in the code

There are plenty of comments in the code, to describe what most of the code-sections are doing.

You can look at the top of the PROCS section of the code to see a list of the procs used in this script, along with brief descriptions of how they are called and what they do.

The main procs are

  'get_INfilename'               - called by the audio in-file 'Browse' button.

  'get_chars_before_last'        - called by the proc 'get_INfilename'.

  'set_defaults_for_encoding'    - called by bindings on the ENCODING FORMAT
                                   radiobuttons.

                                   Sets defaults for the audio-and-other
                                   GUI widgets, for a given encoding type.

  'loadOptsFrame_perListboxSelection' - called by a click on the listbox.

                                 Calls on a 'show_*_opts' proc depending on
                                 the listbox line (audio-exec-operation) selected.

                                 Example proc name: 'show_CLIP_opts'

  'exec_audio_operation'       - called by a click on the 'ExecOption' button.

                                 Calls on a 'set_*_cmd' proc depending on
                                 the listbox line (media-file-operation) selected.

                                 Example proc name: 'set_CLIP_cmd'

                                 Then executes the 'ffmpeg' command string built by
                                 the 'set_*_cmd' proc --- in an 'xterm' window.

  --------------------------------------------------------------------------------------
  For each ExecOption added to the listbox, a 'show_*_opts' proc and a 'set_*_cmd' proc
  should be provided --- like the following.
           (And calls will need to be added to the 2 procs above:
            'loadOptsFrame_perListboxSelection' and 'exec_audio_operation'.)
  --------------------------------------------------------------------------------------
  'show_CLIP_opts'            - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'clip' frames and widgets into an 'execOpts' frame.

  'set_CLIP_cmd'              - called by the 'exec_audio_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for CLIPPING --- to be
                                used in the proc 'exec_audio_operation'.

  --------------------------------------------------------------------------------------
  'show_CHG-VOLUME_opts'      - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'chg-volume' frames and widgets into an 'execOpts' frame.

  'set_CHG-VOLUME_cmd'        - called by the 'exec_audio_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for CHG-VOLUME --- to be
                                used in the proc 'exec_audio_operation'.

  --------------------------------------------------------------------------------------
  'show_PROPSin_opts'         - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'PROPSin' frames and widgets into an 'execOpts' frame.

  'set_PROPSin_cmd'           - called by the 'exec_audio_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for showing properties
                                of the input media file. The command string is to be used
                                in the proc 'exec_audio_operation'.

  --------------------------------------------------------------------------------------
  'show_PROPSout_opts'        - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'PROPSout' frames and widgets into an 'execOpts' frame.

  'set_PROPSout_cmd'          - called by the 'exec_audio_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for showing properties
                                of the output media file. The command string is to be used
                                in the proc 'exec_audio_operation'.

  --------------------------------------------------------------------------------------
  'show_CONVERT_opts'         - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'convert' frames and widgets into an 'execOpts' frame.

  'set_CONVERT_cmd'           - called by the 'exec_audio_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for CONVERTING the input
                                media file to a new audio format.
                                The command string is to be used in the proc
                                'exec_audio_operation'.

  --------------------------------------------------------------------------------------

  'play_audio_file'          - called by the 'PlayInAudio' and 'PlayOutAudio'buttons.
                               Launches an audio 'player' program to play the input
                               or output audio file.

  'set_width_of_labels'      - called in the 'Additional GUI Initialization'
                               section at the bottom of this script.

                               Sets a nice common width of the labels on the
                               left of each of the GUI sections:
                                - audio
                                - other
                               according to the font being used for labels.

  'pack_more_outparms_frame'  - called by button1-release binding on the
                                'MoreAudioOutParms' checkbutton.

                                Shows the 'audio' and 'other' frames of the
                                GUI if the 'MoreAudioOutParms' checkbutton
                                is ON. OR, 'forgets' the frame containing
                                the 'audio' and 'other' frames.

  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.

I used the following statement to allow the GUI to be expanded in the x-direction, but NOT the y-direction.

   wm resizable . 1 0

whether or not the 'audio-and-other' parameter frames are showing. That is, whether or not the 'MoreMovieOutParms' checkbutton is ON or OFF. You can look for the string 'resizable' in the code to see how this was done by toggling the y-resizing on and off.


It is my hope that the copious comments in the code will help Tcl-Tk coding 'newbies' get started in making GUI's like this.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch 'Tsunamis Gone Wild' videos.


 Code for Tk script 'audioClipChgVolumeConvertEtc_ffmpeg_FrontEnd.tk' :
#!/usr/bin/wish -f
##
## Tk SCRIPT NAME: audioClipChgVolumeConvertEtc_ffmpeg_FrontEnd.tk
##
##+#######################################################################
## PURPOSE:  This Tk script provides a GUI for using the 'ffmpeg' program
##           to process AUDIO files in various ways --- Clip, Change volume,
##           Convert, etc.
##
##           In other words, this is a MULTI-PURPOSE audio processing utility.
##
##           The GUI offers multiple audio-processing options via a
##           Tk 'listbox' widget that contains processing-type indicators
##           such as 'CLIP', 'CHANGE-VOLUME', 'PROPERTIES-IN', 'PROPERTIES-OUT',
##           'CONVERT', 'EXTRACT-CHANNEL', 'ADD-CHANNEL', etc.
##
##           For a given user-selected processing option, an 'execOpts'
##           Tk 'frame' widget in the GUI is filled with parameter-prompting
##           widgets suited to the option selected.  For example:
##
##           - If CLIP is selected, entry fields are provided to enter
##             a start-time and a duration-time for the clipping operation.
##
##           In addition, there are radiobutton widgets by which the
##           user can select an 'encoding format' for the output audio file.
##
##           And there is a stack of about 6 frames (the stack is defaulted to hidden)
##           that contain widgets by which the user can specify the audio
##           encoding parameters --- for making the output audio file.
##           These widgets contain defaults that are determined by the
##           'encoding format' that is selected.
##
##           The GUI is intended to make the user aware of the options
##           available without the user needing to use the
##           'man ffmpeg' or 'ffmpeg -h' commands or other 'ffmpeg'
##           documentation --- for example, documentation found via
##           web searches.
##
##           Various 'label' widgets on the GUI provide examples to indicate
##           to the user the typical parameter values that may be entered in
##           'entry' widgets.
##
##           Also the GUI is meant to provide defaults for the audio-encoding
##           parameters that are known to work (provided the necessary audio
##           codec libraries are available.)
##
##           The options available to the user are indicated
##           by the following 'sketch' of the GUI:
##
## ---------------------------------------------------------------------
##
## THE SKETCH CONVENTIONS for GUI sketch below:
##
## SQUARE-BRACKETS indicate a comment not to be included 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.
##
##  ----------------------------------------------------------------------------------------
##  Audio Edit ( Clip, Change Volume, Convert, Etc. ) - a front-end for the 'ffmpeg' command
##  [window title]
##  ----------------------------------------------------------------------------------------
##
##  [On the left of the following frames will be a Tk 'listbox' widget in frame '.fRleft'.
##   The following frames will be contained in frame '.fRright'.]
##
##  '.fRright'
##   SubFrame
##    names
##     |
##     V
##
## .fRbuttons   {Exit} {Help} {ExecOption} {PlayOutAudio} {PlayInAudio}  X MoreAudioOutParms (audio,other)
##
## .fRinfile    Input audio filename : $env(HOME)/input_audio.mp3_______________________  {Browse...}
##
## .fRmsg       Select an input file and an audio-processing option from the listbox on the left. Then provide
##              processing parameters at prompts in the 'ExecOption Parameters' section that appears below.
##              An 'xterm' window will appear when processing starts. You can see processing messages in
##              that window. When processing is finished, use the 'PlayOutAudio' button to play the audio.
##              [This initial message in a label widget may be changed when the 'Exec' button is clicked.]
##
##              --------------------------------------------------------------------------------------
## .fRoutHead   Output File parameters:
##              --------------------------------------------------------------------------------------
##
## .fRencoder   Encoding format: O MP3 (.mp3)  O Vorbis (.oga)  O AAC (.aac)  O FLAC (.flac)  O Mpeg2 (.mp2)
##
## .fRoutfile   Output audio filename : /tmp/$env(USER)_output_audio.mp3___________________
##
## .fRplayer    Player for audio in/out file: xffplay____ Examples: xffplay  xmplayer   gmplayer  totem  vlc {Help}
##
##              --------------------------------------------------------------------------------------
## .fRoptsHead   ExecOption Parameters:   [This label may dynamically change according to option selected.
##                                        Examples: '  (CLIP)' or  ' (CONVERT)' may be added after 'Parameters:'.]
##              --------------------------------------------------------------------------------------
##
## .fRexecOpts  [The sub-frames and widgets that appear here
##               will depend on the listbox line currently selected.
##               A couple of examples, for CLIP and CHG-VOLUME, are shown below.]
##
## .fRaudparms  [This frame and its following subframes are shown if
##               the 'MoreAudioOutParms' checkbuttons is set ON.]
##
##  '.fRaudparms'
##   SubFrame
##    names
##     |
##     V
##              -------------------------------------------------------------------------------------
## .fRaudioHead Audio-out parameters:
##              -------------------------------------------------------------------------------------
##
## .fRacodec    Audio-out Codec: libmp3lame__ Examples: libmp3lame  libvorbis  libfaac  flac  mp2  pcm_s16le 
##
## .fRachannels Audio-out Channels: 1_ Examples: 1  2
##
## .fRasrate    Audio-out Sampling Rate: 22050__ Examples: 44100 22050 11025
##
## .fRabrate    Audio-out Bit Rate: 96k__ Examples: 64k  96k  128k  160k  192k (multiples of 32k)
##
## .fRaother    Other audio-out parms: _________________________________________________
##
##              --------------------------------------------------------------------------------------
## .fRother     Other output recording parameters:
##              --------------------------------------------------------------------------------------
##
## .fRthreads   Threads: 1___ (to take advantage of a multi-core computer ; may not work for some coders)
##
## .fRguide     NOTE: This utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages from 'ffmpeg'
##              can be seen in that window. You may minimize the 'xterm' window while processing, if you do not
##              want to monitor the processing messages. When processing is done, the terminal does not close,
##              so that you can examine messages. The output file, if good, can be shown in an audio player,
##              that you specify above.  See 'Help' for details.
##              [a 'label' widget]
##             ---------------------------------------------------------------------------------------
##
##+##############
## GUI components:
##
## From the GUI 'sketch' above, it is seen that the GUI (not counting the widgets in the
## 'execOpts' frame) consists of ABOUT:
##
##   7 'button' widgets
##  22 'label'  widgets (many are for entry fields)
##   9 'entry'  widgets
##   1 'checkbutton' widget
##   5 'radiobutton' widgets (in one group)
##   1 'listbox' widget (with scrollbars)
##   0 'scale'  widgets
##   0 'canvas' widgets
##   0 'text' widgets
##
##+##########################################################
## SOME SAMPLE SUB-FRAMES and WIDGETS IN FRAME 'execOpts':
##
##  'execOpts'
##   SubFrame
##    names
##     |
##     V
## FOR CLIPPING:
##
## .fRclip1      Start time (hrs:min:sec): 00:01:23__   Duration (hrs:min:sec):  00:00:22__
##
## FOR CHG-VOLUME:
##
## .fRchgvol1    Change volume factor (percent): 10__ Examples: 25  50  120  200
##
##+#####################################################################
## CALLED BY:  This script could be put in a sub-directory of the
##             users home directory, such as
##                   $HOME/apps/tkEditAudio.
##
##             Then the user can use their desktop system (such as
##             Gnome or KDE) to set up the script as an icon on the
##             desktop.
##
##             Then, whenever the user wants to edit an audio file, the user
##             can click on the icon to startup the script.
##+########################################################################
## STRUCTURE OF THIS CODE:
##
##  0) Set general window parms (win-name, win-position, win-color-scheme,
##     fonts, widget-geom-parms, text-array-for-labels-etc, win-size-control).
##
##  1a) Define ALL frames (and sub-frames, if any).
##  1b) Pack the frames.
##
##  2) Define & pack all widgets in the frames, frame by frame.
##     After all the widgets for a frame are defined, pack them in the frame.
##
##  3) Define keyboard and/or mouse/touchpad/touch-sensitive-screen 'event'
##     BINDINGS, if needed.
##  4) Define PROCS, if needed.
##  5) Additional GUI INITIALIZATION (typically with one or more of
##     the procs), if needed.
##
## In more detail:
##
##  1a) Define ALL frames -- and sub-frames:
##
##   Top-level frames:
##   '.fRleft'   to hold a listbox widget with xy scrollbars.
##   '.fRright'  to hold the following sub-frames:
##
##   '.fRright.fRbuttons'     for Exit, Help, Exec, Play buttons.
##   '.fRright.fRinfile'      for label-entry-button widgets.
##   '.fRright.fRmsg'         for a label widget (for messages).
##   '.fRright.fRoutHead'     for a label widget (for a heading).
##   '.fRright.fRencoder'     for a label and several radiobutton widgets.
##   '.fRright.fRoutfile'     for label-entry widgets.
##   '.fRright.fRplayer'      for label-entry-label widgets.
##   '.fRright.fRoptsHead'    for a label widget.
##   '.fRright.fRexecOpts'    for 1 or more sub-frames.
##
##   '.fRright.fRaudparms'    for the following sub-frames:
##
##   '.fRright.fRaudparms.fRaudioHead'   for a label widget (for a heading).
##   '.fRright.fRaudparms.fRacodec'      for label-entry-label widgets.
##   '.fRright.fRaudparms.fRachannels'   for label-entry-label widgets.
##   '.fRright.fRaudparms.fRasrate'      for label-entry-label widgets.
##   '.fRright.fRaudparms.fRabrate'      for label-entry-label widgets.
##   '.fRright.fRaudparms.fRaother'      for label-entry-label widgets.
##   '.fRright.fRaudparms.fRotherHead'   for a label widget (for a heading).
##   '.fRright.fRaudparms.fRthreads'     for label-entry-label widgets.
##   '.fRright.fRaudparms.fRguide'       for a label widget (for usage info).
##
##       This is about 24 frames and sub-frames, not counting a variable
##       number of sub-frames in 'fRexecOpts'.
##       Most of these sub-frames are 1 character high.
##
##  1b) Pack ALL these frames and sub-frames --- except 'fRaudparms'.
##
##      (We use 'show_*_opts' procs to replace the 'fRexecOpts' frame according to
##       the user's listbox selection, and we use a 'pack_more_outparms_frame'
##       proc to pack or pack-forget 'fRaudparms' according to whether the
##      'MoreAudioOutParms' checkbutton is ON or OFF.)
##
##  2) Define & pack all widgets in these frames -- basically going through
##     frames & their interiors in  left-to-right, top-to-bottom order:
##
##  3) Define bindings:  See BINDINGS section below.
##
##     SOME bindings are:
##
##     - A button1-release binding on the listbox widget will trigger a proc
##       that shows the appropriate widgets in the 'fRexecOpts' frame.
##
##     - A button1-release binding on the 'MoreAudioOutParms' checkbutton widget
##       will trigger a proc that shows/hides the 'fRaudparms' frame.
##
##  4) Define procs:   See the PROCS section below.
##
##     SOME of the procs are:
##
##  'get_INfilename'             - called by the audio in-file 'Browse' button.
##
##  'set_defaults_for_encoding'  - called by button1-release bindings on the ENCODING
##                                 FORMAT radiobuttons. Also called in the 'Additional
##                                 GUI Initialization' at the bottom of this script.
##
##                                 Sets defaults for the audio-and-other widgets
##                                 for a given output encoding type.
##
##  'loadOptsFrame_perListboxSelection' - called by a click on the listbox.
##
##                                 Calls on a 'show_*_opts' proc (below) depending on
##                                 the listbox line (audio-operation) selected.
##
##                                 Example 'show_*_opts' proc name: 'show_CLIP_opts'
##
##  'exec_audio_operation'       - called by a click on the 'ExecOption' button.
##
##                                 Calls on a 'set_*_cmd' proc depending on
##                                 the listbox line (audio-operation) selected.
##
##                                 Example 'set_*_cmd' proc name: 'set_CLIP_cmd'
##
##                                 Then executes the 'ffmpeg' command built by the
##                                 'set_*_cmd' proc --- in an 'xterm' window.
##
##--------------------------------------------------------------------------------------
## For each ExecOption added to the listbox, a 'show_*_opts' proc and a 'set_*_cmd' proc
## should be provided --- like the following.
##           (And calls to the 2 new procs will need to be added, in two procs:
##            'loadOptsFrame_perListboxSelection' and 'exec_audio_operation'.)
##--------------------------------------------------------------------------------------
##
##  'show_CLIP_opts'            - called by a button1-release binding on the listbox.
##
##                                Loads frames and widgets into the 'execOpts' frame.
##
##  'set_CLIP_cmd'              - called by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string --- with user-selected
##                                parameters for clipping and with parameters for creating
##                                the output audio file.
##
##--------------------------------------------------------------------------------------
##  'show_CONVERT_opts'         - called by a button1-release binding on the listbox
##
##                                Loads frames and widgets into the 'execOpts' frame.
##
##  'set_CONVERT_cmd'           - called by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string --- with user-selected
##                                parameters for creating the output audio file.
##--------------------------------------------------------------------------------------
##
##  'play_audio_file'           - called by the 'PlayInAudio' and 'PlayOutAudio'buttons.
##                                Launches an audio 'player' program to play the input
##                                or output audio file.
##
##  'pack_more_outparms_frame'  - called by button1-release binding on the
##                                'MoreAudioOutParms' checkbutton --- to show/hide
##                                the audio-and-other parameter frames.
##
##  'popup_msgVarWithScroll'    - called by 'Help' button to show the HELPtext var.
##                                Also used to show various warning/error/info
##                                messages to the user.
##
##  5) Additional GUI initialization:  See this section at the bottom
##                                     of this script.
##+#######################################################################
## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala')
##
##   $ wish
##   % puts "$tcl_version $tk_version"
##
## showed
##     8.5 8.5
## but this script should work in most previous 8.x versions, and probably
## even in some 7.x versions (if font handling is made 'old-style').
##+########################################################################
## MAINTENANCE HISTORY:
## Started by: Blaise Montandon 2014jun19 Started development, on Ubuntu 9.10,
##                                        based on a Tk script that contains
##                                        most of the frames and widgets that
##                                        are needed:
##                                        'movieClipCropEtc_ffmpeg_FrontEnd.tk'
## Updated by: Blaise Montandon 2014jun20 Got GUI up. Started touching it up.
##                                        Got most of the procs working.
## Updated by: Blaise Montandon 2014jun20 Added a 'Help' button to show help
##                                        for a selected 'player' program.
##+#######################################################################

##+######################################################
## Set WINDOW TITLE and POSITION.
##+######################################################

wm title    . "Audio Edit ( Clip, Change Volume, Convert, ... ) - a front-end for the 'ffmpeg' command"
wm iconname . "AudioEdit"

wm geometry . +15+30


##+######################################################
## Set the COLOR SCHEME for the window and its widgets ---
## such as listbox and entry field background color.
##+######################################################

tk_setPalette "#e0e0e0"

  set headBKGD  "#a0a0a0"
  set guideBKGD "#00ff00"

  set entryBKGD   "#ffffff"
  set textBKGD    "#f0f0f0"
  set radbuttBKGD "#c0c0c0"
  set chkbuttBKGD "#c0c0c0"
  set listboxBKGD "#ffffff"
# set scaleBKGD   "#f0f0f0"

##+########################################################
## DEFINE (temporary) FONT NAMES.
##
## We use a VARIABLE-WIDTH font for text on LABEL and
## BUTTON widgets.
##
## We use a FIXED-WIDTH font for LISTBOX lists,
## for text in ENTRY fields --- and often for text in
## TEXT widgets.
##
## 'weight' can be 'bold' or 'normal'.
## 'slant'  can be 'roman' or 'italic'.
##+########################################################

font create fontTEMP_varwidth \
   -family {comic sans ms} \
   -size -12 \
   -weight normal \
   -slant roman

font create fontTEMP_SMALL_varwidth \
   -family {comic sans ms} \
   -size -10 \
   -weight normal \
   -slant roman

## Some possible (similar) variable width fonts:
##  Arial
##  Bitstream Vera Sans
##  Comic Sans MS
##  DejaVu Sans
##  Droid Sans
##  FreeSans
##  Liberation Sans
##  Nimbus Sans L
##  Trebuchet MS
##  Verdana


font create fontTEMP_fixedwidth  \
   -family {droid sans mono} \
   -size -12 \
   -weight normal \
   -slant roman

font create fontTEMP_SMALL_fixedwidth  \
   -family {droid sans mono} \
   -size -10 \
   -weight normal \
   -slant roman

## Some possible fixed width fonts (esp. on Linux):
##  Andale Mono
##  Bitstream Vera Sans Mono
##  Courier 10 Pitch
##  DejaVu Sans Mono
##  Droid Sans Mono
##  FreeMono
##  Liberation Mono
##  Nimbus Mono L
##  TlwgMono


##+###########################################################
## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS.
## (e.g. width and height of canvas, and padding for Buttons)
##+###########################################################

## LABEL widget geom settings:

set PADXpx_label 0
set PADYpx_label 0
set BDwidthPx_label 2
set RELIEF_label_lo "flat"


## BUTTON widget geom settings:

set PADXpx_button 0
set PADYpx_button 0
set BDwidthPx_button 2
## We use '-relief raised' for all 'button' widgets.


## ENTRY widget geom settings:

set BDwidthPx_entry 2
## We use '-relief sunken' for all 'entry' widgets.


## LISTBOX widget geom settings:

set initListboxWidthChars 25
set initListboxHeightChars 15
set BDwidthPx_listbox 2
## We use '-relief sunken' for the 'listbox' widget.


## RADIOBUTTON widget geom settings:

set PADXpx_radbutton 0
set PADYpx_radbutton 0
set BDwidthPx_radbutt 2
set RELIEF_radbutt_hi "raised"


## CHECKBUTTON widget geom settings:

set PADXpx_chkbutton 0
set PADYpx_chkbutton 0
set BDwidthPx_chkbutt 2
set RELIEF_chkbutt_hi "raised"

## TEXT widget geom settings:

set BDwidthPx_text 2
# set RELIEF_numtext "ridge"

## SCALE widget geom parameters:

# set BDwidthPx_scale 2
# set scaleThicknessPx 10


##+##############################################################
## 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 '.fRright.fRbuttons' frame:

set aRtext(buttonEXIT)    "Exit"
set aRtext(buttonHELP)    "Help"
set aRtext(buttonEXEC)    "ExecOption"
set aRtext(buttonPLAYOUT) "PlayOutAudio"
set aRtext(buttonPLAYIN)  "PlayInAudio"
set aRtext(chkbuttMOREoutparms) "MoreAudioOutParms (audio,other)"

## For '.fRright.fRmsg' frame:

set aRtext(labelMSG) \
"Select an input file and an audio-processing option from the listbox on the left. Then provide processing
parameters at prompts in the 'ExecOption Parameters' section that appears below. For most options, an
'xterm' window will appear when processing starts. You can see processing messages in that window.  When
processing is finished, use the 'PlayOutAudio' button to play the audio. Use 'Help' button for details."

## For '.fRright.fRinfile' frame:

set aRtext(labelINFILE) "Input  audio  filename :"
set aRtext(buttBROWSE)  "Browse..."

## For '.fRright.fRoutHead' frame:

set aRtext(labelOUTHEAD) "Output File Parameters:"

## For '.fRright.fRencoder' frame:

set aRtext(labelENCODER) "Encoding format:"

set aRtext(radbuttMP3)    "MP3 (.mp3)"
set aRtext(radbuttVORBIS) "Vorbis (.oga)"
set aRtext(radbuttAAC)    "AAC (.aac)"
set aRtext(radbuttFLAC)   "FLAC (.flac)"
set aRtext(radbuttMP2)    "MP2 (.mp2)"

## For '.fRright.fRoutfile' frame:

set aRtext(labelOUTFILE) "Output  audio  filename :"

## For '.fRright.fRplayer' frame:

set aRtext(labelPLAYER1) "Player for audio in/out files:"
set aRtext(labelPLAYER2) "Examples:  xffplay  xmplayer  gmplayer  totem  vlc"
set aRtext(buttHELPplayer) "Help"

## For '.fRright.fRoptsHead' frame:

set aRtext(labelOPTShead) "ExecOption Parameters:"

## For '.fRright.fRexecOpts' frame:

set aRtext(labelEXECopts) \
"SELECT AN OPTION FROM THE LISTBOX. Appropriate parameter prompts will appear here."


## For '.fRright.fRaudparms.fRaudioHead' frame:

set aRtext(labelAUDIOHEAD) "Audio-out recording parameters:"


## For '.fRright.fRaudparms.fRacodec' frame:

set aRtext(labelACODEC1) "Audio-out coder:"
set aRtext(labelACODEC2) "Examples: libmp3lame  libvorbis  vorbis  libfaac  flac  mp2  pcm_s16le"

## For '.fRright.fRaudparms.fRachannels' frame:

set aRtext(labelACHANNELS1) "Audio channels:"
set aRtext(labelACHANNELS2) "Examples: 1  2"

## For '.fRright.fRaudparms.fRasrate' frame:

set aRtext(labelASRATE1) "Audio-out Sampling Rate:"
set aRtext(labelASRATE2) "Examples: 44100  22050  11025  48000  32000  24000 ..."

##  For '.fRright.fRaudparms.fRabrate' frame:

set aRtext(labelABRATE1) "Audio-out Bit Rate:"
set aRtext(labelABRATE2) "Examples: 64k  96k  128k  160k  192k (multiples of 32k)"

## For '.fRright.fRaudparms.fRaother' frame:

set aRtext(labelAOTHER) "Other audio-out parameters:"


## For '.fRright.fRaudparms.fRotherHead' frame:

set aRtext(labelOTHERHEAD) "Other output recording parameters:"

## For '.fRright.fRaudparms.fRthreads' frame:

set aRtext(labelTHREADS1) "Threads:"
set aRtext(labelTHREADS2) "(to take advantage of a multi-core computer ; may not work for some coders)"


## For '.fRright.fRaudparms.fRguide' frame:

set aRtext(labelGUIDE) \
"NOTE: For most ExecOptions, this utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages
from 'ffmpeg' can be seen in that window. You may minimize the 'xterm' window while processing, if you
do not want to monitor the processing messages. When processing is done, the 'xterm' window does not close,
so that you can examine messages. The output file, if good, can be shown in an audio player, that you
specify above.  See 'Help' for details."

##+#############################
## For the 'execOpts' sub-frames:
##+#############################

## For the CLIP option:

set aRtext(labelSTARTtime)    "Start time (hh:mm:ss\[.xxx\]):"
set aRtext(labelDURATIONtime) "Duration (hh:mm:ss\[.xxx\]):"


## For the CHANGE-VOLUME option:

set aRtext(labelCHGVOLUME1)  "Volume change factor (percent):"
set aRtext(labelCHGVOLUME2)  "Examples: 10  25  50  120  200"


## For the PROPERTIES-IN option:

set aRtext(labelPROPERTIESin) \
"**CLICK THE 'ExecOption' BUTTON.** The PROPERTIES of the INPUT file will be shown in a popup window."


## For the PROPERTIES-OUT option:

set aRtext(labelPROPERTIESout) \
"**CLICK THE 'ExecOption' BUTTON.** The PROPERTIES of the OUTPUT file are to be shown in a popup window."


## For the CONVERT option:

set aRtext(labelCONVERT) \
"Set 'CONVERT' parms with the 'encoding format' radiobuttons and the 'MoreOutAudioParms' widgets.
OR take the defaults for the audio-encoding and 'other' parameters."


## For the ADD-CHANNEL option:  (later)


## END OF  if { "$VARlocale" == "en"}


##+######################################################################
## Set a MIN-SIZE of the window (roughly).
##
## For WIDTH, allow for a min-width via the  '.fRleft' frame and
## '.fRright.fRbuttons' frame.
##
## For HEIGHT, allow for the INITIAL stacked (unhidden) frames:
##      1 char   high for the '.fRright.fRbuttons'   frame
##      1 char   high for the '.fRright.fRinfile'    frame
##      4 chars  high for the '.fRright.fRmsg'       frame
##      1 char   high for the '.fRright.fRoutHead'   frame
##      1 char   high for the '.fRright.fRencoder'   frame
##      1 char   high for the '.fRright.fRoutfile'   frame
##      1 char   high for the '.fRright.fRplayer'    frame
##      1 char   high for the '.fRright.fRoptsHead'  frame
##      1 char   high for the '.fRright.fRexecOpts'  frame
##+#####################################################################

## FOR WIDTH: (allow for the listbox in the '.fRleft' frame and the
## button widgets in the '.fRright.fRbuttons' frame)

set minWidthPx [font measure fontTEMP_varwidth \
   " $aRtext(buttonEXIT) $aRtext(buttonHELP) $aRtext(buttonEXEC)  \
$aRtext(buttonPLAYOUT) $aRtext(buttonPLAYIN) $aRtext(chkbuttMOREoutparms)"]

## We add some pixels to account for right-left-size of
## window-manager decoration (~8 pixels) and some pixels for
## frame/widget borders (~6 widgets x 4 pixels/widget = 24 pixels).

set minWinWidthPx [expr {32 + $minWidthPx}]

## Also add pixels for the listbox --- along with about 10 pixels
## for its vertical scrollbar.

set charWidthPx [font measure fontTEMP_varwidth "W"]

set minWinWidthPx \
   [expr {10 + ($initListboxWidthChars * $charWidthPx) + $minWidthPx}]

##+#################################################
## For HEIGHT --- for
##      1 char   high for the '.fRright.fRbuttons'   frame
##      1 char   high for the '.fRright.fRinfile'    frame
##      4 chars  high for the '.fRright.fRmsg'       frame
##      1 char   high for the '.fRright.fRoutHead'   frame
##      1 char   high for the '.fRright.fRencoder'   frame
##      1 char   high for the '.fRright.fRoutfile'   frame
##      1 char   high for the '.fRright.fRplayer'    frame
##      1 char   high for the '.fRright.fRoptsHead'  frame
##      1 char   high for the '.fRright.fRexecOpts'  frame
##    --------
##     12 chars  high for the 9 frames
##+#################################################

set charHeightPx [font metrics fontTEMP_varwidth -linespace]

set minWinHeightPx [expr {12 * $charHeightPx}]

## Add about 20 pixels for top-bottom window decoration --
## and some pixels for top-and-bottom of frame/widget borders
## (~9 widgets x 4 pixels/widget = 36 pixels).

set minWinHeightPx [expr {56 + $minWinHeightPx}]


## FOR TESTING:
#   puts "minWinWidthPx = $minWinWidthPx"
#   puts "minWinHeightPx = $minWinHeightPx"

wm minsize . $minWinWidthPx $minWinHeightPx


## We may allow the window to be resizable.  We pack some entry widgets
## (and the frames that contain them --- .fRoutfile, .fRvother, .fRaother)
## with '-fill x -expand 1' so that the entry widgets 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

## If you want the window to resize in x-direction, but not y.
   wm resizable . 1 0

##+####################################################################
##+####################################################################
## DEFINE *ALL* THE FRAMES:
##
##   Top-level :
##   '.fRleft'   to hold a listbox widget with xy scrollbars
##   '.fRright'  to hold the following sub-frames:
##
##   '.fRright.fRbuttons'     for Exit, Help, Exec, Play buttons, one chkbutton.
##   '.fRright.fRinfile'      for label-entry-button widgets.
##   '.fRright.fRmsg'         for a label widget (for messages).
##   '.fRright.fRoutHead'     for a label widget (for a heading).
##   '.fRright.fRencoder'   for a label and several radiobutton widgets.
##   '.fRright.fRoutfile'     for label-entry widgets.
##   '.fRright.fRplayer'      for label-entry-label widgets.
##   '.fRright.fRoptsHead'    for a label widget (for a heading).
##   '.fRright.fRexecOpts'    for an initial frame with a label widget. This frame
##                            will be replaced by a frame and 1 or more sub-frames
##                            and widgets in the 'show_*_opts' procs.
##
##   '.fRright.fRaudparms'      for the following sub-frames:
##               (But do not pack '.fRright.fRaudparms'. That will be done if
##                the user clicks the 'MoreAudioOutParms' checkbutton.)
##
##   '.fRright.fRaudparms.fRaudioHead'   for a label widget (for a heading).
##   '.fRright.fRaudparms.fRacodec'      for label-entry-label widgets.
##   '.fRright.fRaudparms.fRachannels'   for label-entry-label widgets.
##   '.fRright.fRaudparms.fRasrate'      for label-entry-label widgets.
##   '.fRright.fRaudparms.fRabrate'      for label-entry-label widgets.
##   '.fRright.fRaudparms.fRaother'      for label-entry widgets.
##   '.fRright.fRaudparms.fRotherHead'   for a label widget (for a heading).
##   '.fRright.fRaudparms.fRthreads'     for label-entry-label widgets.
##   '.fRright.fRaudparms.fRguide'       for a label widget (for usage info).
##+####################################################################
##+####################################################################

set RELIEF_frame flat
set BDwidth_frame 0

## FOR TESTING of expansion of frames (esp. during window expansion):
# set RELIEF_frame raised
# set BDwidth_frame 2

frame .fRleft    -relief $RELIEF_frame  -bd $BDwidth_frame
frame .fRright   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRleft.fRlistbox    -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRright.fRbuttons   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRinfile    -relief $RELIEF_frame  -bd $BDwidth_frame

# frame .fRright.fRmsg     -relief $RELIEF_frame  -bd $BDwidth_frame
  frame .fRright.fRmsg     -relief raised         -bd 2


frame .fRright.fRoutHead   -relief raised  -borderwidth 2

frame .fRright.fRencoder -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRoutfile   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRplayer    -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRright.fRoptsHead   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRexecOpts  -relief $RELIEF_frame  -bd $BDwidth_frame

## This 'execOpts' frame will be replaced by a frame (containing
## sub-frames and widgets) --- such as 'fRright.fRparametersCLIP'.
## The new frame, sub-frames, and widgets will be defined and packed
## in 'show_*_opts' procs like 'show_CLIP_opts' and 'show_CONVERT_opts'.
## A 'pack forget' command will be used, in these procs, to replace
## the previously existing frame in this position.

frame .fRright.fRaudparms    -relief $RELIEF_frame  -bd $BDwidth_frame

## We go ahead and define the sub-frames of frame '.fRright.fRaudparms',
## even though they are initially hidden, because the user is quite
## likely to click on the 'MoreAudioOutParms' checkbutton. (The GUI
## comes up quickly in spite of the little bit of processing that
## creates these frames that are initially hidden).

frame .fRright.fRaudparms.fRaudioHead   -relief raised         -bd 2

frame .fRright.fRaudparms.fRacodec      -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRaudparms.fRachannels   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRaudparms.fRasrate      -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRaudparms.fRabrate      -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRaudparms.fRaother      -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRright.fRaudparms.fRotherHead   -relief raised         -bd 2

frame .fRright.fRaudparms.fRthreads     -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRaudparms.fRguide       -relief raised         -bd 2


##+########################################################
## PACK (almost) *ALL* the FRAMES.
##+########################################################

## Top-level:

pack .fRleft \
   -side left \
   -anchor nw \
   -fill y \
   -expand 0

pack .fRright \
   -side left \
   -anchor nw \
   -fill both \
   -expand 1


## Sub-frames of '.fRleft':
## (In case we want to put another widget or frame in the
##  '.fRleft' frame, we provide a frame for the listbox
##  and its scrollbars.)

pack .fRleft.fRlistbox \
   -side top \
   -anchor nw \
   -fill y \
   -expand 1


## Sub-frames of '.fRright':

pack .fRright.fRbuttons \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRright.fRinfile \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1

pack .fRright.fRmsg \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRright.fRoutHead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRright.fRencoder \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRright.fRoutfile \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1

pack .fRright.fRplayer \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1

pack .fRright.fRoptsHead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

## We pack the frame '.fRright.fRexecOpts'. As was noted above,
## this frame will be replaced by frames (containing sub-frames and
## widgets). The new frames and their sub-frames and widgets will be
## defined and packed by 'show_*_opts' procs like 'show_CLIP_opts'
## and 'show_CONVERT_opts'.

pack .fRright.fRexecOpts \
   -side top \
   -anchor nw \
   -fill both \
   -expand 1

##+#############################################################
## We do not pack the '.fRright.fRaudparms' frame here.
## We pack (and 'pack forget') the '.fRright.fRaudparms' frame
## (which was defined above) in the proc 'pack_more_outparms_frame'
## which is in the PROCS section below.
## That proc can be used to show/hide the 'more-out-parms' frames,
## via a checkbutton on the GUI.
##+#############################################################

##+#############################################################
## But we go ahead and pack all the sub-frames of
## the '.fRright.fRaudparms' frame here.
##+#############################################################

pack .fRright.fRaudparms.fRaudioHead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRright.fRaudparms.fRacodec \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRright.fRaudparms.fRachannels \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRright.fRaudparms.fRasrate \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRright.fRaudparms.fRabrate \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRright.fRaudparms.fRaother \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1

pack .fRright.fRaudparms.fRotherHead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRright.fRaudparms.fRthreads \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRright.fRaudparms.fRguide \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1


## OK. All frames are DEFINED (except for frames that will replace
## '.fRright.fRexecOpts', and sub-frames of those frames) --- and
## all these frames are PACKED (except the '.fRright.fRaudparms' frame
## and the frames that will replace '.fRright.fRexecOpts').
##
## Now define-and-pack the widgets --- except for widgets in
## frames that will replace '.fRright.fRexecOpts'. Those widgets
## will be defined-and-packed in 'show_*_opts' procs.


##+################################################################
##+################################################################
## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES.
##+################################################################
##+################################################################


##+######################################################
## In FRAME '.fRleft.fRlistbox' -
## DEFINE-and-PACK a LISTBOX WIDGET,
## with scrollbars --- for a list of 'ffmpeg' ExecOptions.
##+######################################################

listbox .fRleft.fRlistbox.listbox \
   -width $initListboxWidthChars \
   -height $initListboxHeightChars \
   -font fontTEMP_fixedwidth \
   -relief raised \
   -borderwidth $BDwidthPx_listbox \
   -state normal \
   -yscrollcommand ".fRleft.fRlistbox.scrbary set" \
   -xscrollcommand ".fRleft.fRlistbox.scrbarx set"

scrollbar .fRleft.fRlistbox.scrbary \
   -orient vertical \
   -command ".fRleft.fRlistbox.listbox yview"

scrollbar .fRleft.fRlistbox.scrbarx \
   -orient horizontal \
   -command ".fRleft.fRlistbox.listbox xview"


##+##########################################################################
## INSERT 'ffmpeg' 'ExecOption' LISTBOX ENTRIES that hold brief,
## unique audio-file operation identifiers ---
## followed by a separator character (#) --- followed by an
## arbitrary amount of descriptive info.
##
## By adding a '#' at the beginning of each line, we signal
## that that operation is not implemented yet --- but it
## is being considered for addition at some future date.
##+##########################################################################
## FOR EACH OPERATION OPTION ADDED, ADD 2 PROCS TO THE PROCS SECTION.
##
## Note that for each listbox-line added here, there should be
## a couple of procs added to the PROCS section below:
##     'show_*_opts' --- to provide subframe and widget definitions-and-packing.
##                       Example name: 'show_CLIP_opts'
##     'set_*_cmd' --- to execute 'ffmpeg' with appropriate parameters.
##                     Example name: 'set_CLIP_cmd'
##
## In the proc 'show_*_opts', there should be
## frame and widget definitions and pack statements for
## the new frame and new widgets.
##
## See the 'show_CLIP_opts' and 'show_CONVERT_opts' procs for examples of how
## the previous parameters-frame is REMOVED by a 'pack forget' command,
## and THEN the CLIP or CONVERT frame is packed.
##+##########################################################################

## Make sure the listbox is empty.

.fRleft.fRlistbox.listbox delete 0 end

## New OPERATION OPTIONS are to be added/activated here:
## (Also add corresponding 'show_*_opts' & 'set_*_cmd' procs in the PROCS section below.)

.fRleft.fRlistbox.listbox insert end "CLIP # For a given start-time and duration-time, makes an audio 'clip' from the input audio file."
.fRleft.fRlistbox.listbox insert end "CHG-VOLUME # Makes a new audio file with changed audio volume."
.fRleft.fRlistbox.listbox insert end "PROPERTIES-IN # Shows properties of the INPUT audio file, using 'ffmpeg -i'"
.fRleft.fRlistbox.listbox insert end "PROPERTIES-OUT # Shows properties of the OUTPUT audio file, using 'ffmpeg -i'."
.fRleft.fRlistbox.listbox insert end "CONVERT # Converts the input audio file to a new audio format with specified audio-encoding parameters."

.fRleft.fRlistbox.listbox insert end "## NOT IMPLEMENTED YET:"
.fRleft.fRlistbox.listbox insert end "# ADD-CHANNEL # Adds audio channel(s) to an audio file, making a new audio file."
.fRleft.fRlistbox.listbox insert end "# EXTRACT-CHANNEL # Extracts an audio channel into a new audio file."
.fRleft.fRlistbox.listbox insert end "# REMOVE-CHANNEL # Makes a new audio file by removing an audio channel from the input audio file."

##+##############################################################
## Get the number of exec-operations loaded into the listbox ---
## to show users how many are in the listbox, including those that
## may be out of sight. This number may be displayed on the right
## of the '.fRbuttons' frame, for example.
##+##############################################################

set numExecOps [.fRleft.fRlistbox.listbox index end]


##+####################################
## Pack the listbox and its scrollbars.
##+####################################

pack .fRleft.fRlistbox.scrbary \
   -side right \
   -anchor e \
   -fill y \
   -expand 0

pack .fRleft.fRlistbox.scrbarx \
   -side bottom \
   -anchor s \
   -fill x \
   -expand 0

## We need to pack the listbox AFTER
## the scrollbars, to get the scrollbars
## positioned properly --- BEFORE
## the listbox FILLS the pack area.

pack .fRleft.fRlistbox.listbox \
   -side top \
   -anchor nw \
   -fill both \
   -expand 1


##+##################################################################
## IN THE '.fRright.fRbuttons' frame -- DEFINE several BUTTON widgets
## --- Exit, Help, ExecOption, PlayOutAudio, PlayInAudio.
## Also DEFINE a CHECKBUTTON widget. Then PACK THE WIDGETS.
##+##################################################################

button .fRright.fRbuttons.buttEXIT \
   -text "$aRtext(buttonEXIT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {exit}

button .fRright.fRbuttons.buttHELP \
   -text "$aRtext(buttonHELP)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {popup_msgVarWithScroll .topHELP "$HELPtext"}

button .fRright.fRbuttons.buttEXEC \
   -text "$aRtext(buttonEXEC)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {exec_audio_operation}


button .fRright.fRbuttons.buttPLAYOUT \
   -text "$aRtext(buttonPLAYOUT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {play_audio_file "$OUTfilename"}

button .fRright.fRbuttons.buttPLAYIN \
   -text "$aRtext(buttonPLAYIN)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {play_audio_file "$INfilename"}

## DEFINE Checkbutton for Show/Hide-MoreOutParms.

set SHOWoutparms0or1 0

checkbutton  .fRright.fRbuttons.chkbuttMOREoutparms \
   -text "$aRtext(chkbuttMOREoutparms)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable SHOWoutparms0or1 \
   -selectcolor "$chkbuttBKGD" \
   -relief $RELIEF_chkbutt_hi \
   -bd $BDwidthPx_chkbutt


##+###################################################
## Pack the widgets in the '.fRright.fRbuttons' frame.
##+###################################################
## You can easily change the order of the buttons by
## re-arranging the order of these widgets in the pack
## statement. For example, you could move 'buttPLAYOUT'
## above 'buttPLAYIN', to move the 'PlayOutAudio' button
## to the left of the 'PlayInAudio' button on the GUI.
##+####################################################

pack .fRright.fRbuttons.buttEXIT \
     .fRright.fRbuttons.buttHELP \
     .fRright.fRbuttons.buttEXEC \
     .fRright.fRbuttons.buttPLAYIN \
     .fRright.fRbuttons.buttPLAYOUT \
     .fRright.fRbuttons.chkbuttMOREoutparms \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+##########################################################
## IN THE '.fRright.fRinfile' frame -- DEFINE 1 LABEL widget
## and 1 ENTRY widget and 1 BUTTON widget. Then PACK THEM.
##+##########################################################

label .fRright.fRinfile.labelINFILE \
   -text "$aRtext(labelINFILE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRinfile.entryINFILE \
   -textvariable INfilename \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

button .fRright.fRinfile.buttBROWSE \
   -text "$aRtext(buttBROWSE)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {get_INfilename}

## PACK the widgets in the '.fRright.fRinfile' frame.

pack .fRright.fRinfile.labelINFILE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRright.fRinfile.entryINFILE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRright.fRinfile.buttBROWSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRright.fRmsg' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+########################################################

label .fRright.fRmsg.labelMSG \
   -text "$aRtext(labelMSG)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg "#ccffcc"

pack .fRright.fRmsg.labelMSG \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+##########################################################
## IN THE '.fRright.fRoutHead' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+##########################################################

label .fRright.fRoutHead.labelOUTHEAD \
   -text "$aRtext(labelOUTHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRright.fRoutHead.labelOUTHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+############################################################
## IN THE '.fRright.fRencoder' frame -- DEFINE 1 LABEL widget,
## and several RADIOBUTTON widgets. Then PACK THEM.
##+############################################################

label .fRright.fRencoder.labelENCODER \
   -text "$aRtext(labelENCODER)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for encoding formats :
## (To set the value of the variable for each radiobutton, we may use
##  the exact string that 'ffmpeg' uses to specify the encoding format.)

radiobutton .fRright.fRencoder.radbuttMP3 \
   -text "$aRtext(radbuttMP3)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable ENCODERname \
   -value "libmp3lame" \
   -selectcolor "$radbuttBKGD" \
   -relief $RELIEF_radbutt_hi \
   -bd $BDwidthPx_radbutt

radiobutton .fRright.fRencoder.radbuttVORBIS \
   -text "$aRtext(radbuttVORBIS)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable ENCODERname \
   -value "libvorbis" \
   -selectcolor "$radbuttBKGD" \
   -relief $RELIEF_radbutt_hi \
   -bd $BDwidthPx_radbutt

# -value "vorbis"

# .fRright.fRencoder.radbuttVORBIS configure -state disabled

radiobutton .fRright.fRencoder.radbuttAAC \
   -text "$aRtext(radbuttAAC)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable ENCODERname \
   -value "libfaac" \
   -selectcolor "$radbuttBKGD" \
   -relief $RELIEF_radbutt_hi \
   -bd $BDwidthPx_radbutt

# .fRright.fRencoder.radbuttAAC configure -state disabled

radiobutton .fRright.fRencoder.radbuttFLAC \
   -text "$aRtext(radbuttFLAC)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable ENCODERname \
   -value "flac" \
   -selectcolor "$radbuttBKGD" \
   -relief $RELIEF_radbutt_hi \
   -bd $BDwidthPx_radbutt

# .fRright.fRencoder.radbuttFLAC configure -state disabled


radiobutton .fRright.fRencoder.radbuttMP2 \
   -text "$aRtext(radbuttMP2)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable ENCODERname \
   -value "mp2" \
   -selectcolor "$radbuttBKGD" \
   -relief $RELIEF_radbutt_hi \
   -bd $BDwidthPx_radbutt

# .fRright.fRencoder.radbuttMP2 configure -state disabled

## COMMENTED, for now.
if {0} {
radiobutton .fRright.fRencoder.radbuttPCM \
   -text "$aRtext(radbuttPCM)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable ENCODERname \
   -value "pcm_s16le" \
   -selectcolor "$radbuttBKGD" \
   -relief $RELIEF_radbutt_hi \
   -bd $BDwidthPx_radbutt
}
## END OF if {0}

# .fRright.fRencoder.radbuttPCM configure -state disabled

## Pack the widgets in frame '.fRencoder'.

pack .fRright.fRencoder.labelENCODER \
     .fRright.fRencoder.radbuttMP3 \
     .fRright.fRencoder.radbuttVORBIS \
     .fRright.fRencoder.radbuttAAC \
     .fRright.fRencoder.radbuttFLAC \
     .fRright.fRencoder.radbuttMP2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+##########################################################
## IN THE '.fRright.fRoutfile' frame -- DEFINE 1 LABEL widget
## and 1 ENTRY widget. Then PACK THEM.
##+##########################################################

label .fRright.fRoutfile.labelOUTFILE \
   -text "$aRtext(labelOUTFILE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRoutfile.entryOUTFILE \
   -textvariable OUTfilename \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

## COMMENTED OUT this 'Browse' button, for now.
if {0} {
button .fRright.fRoutfile.buttBROWSE \
   -text "$aRtext(buttonBROWSE)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {get_OUTfilename}
}

## PACK the widgets in the '.fRright.fRoutfile' frame.

pack .fRright.fRoutfile.labelOUTFILE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRright.fRoutfile.entryOUTFILE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

## COMMENTED OUT this 'Browse' button, for now.
if {0} {
pack .fRright.fRoutfile.buttBROWSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0
}

##+##############################################################
## IN THE '.fRright.fRplayer' frame -- DEFINE a LABEL-ENTRY-LABEL
## triplet of widgets, and a Help BUTTON. Then PACK THEM.
##+##############################################################

label .fRright.fRplayer.labelPLAYER1 \
   -text "$aRtext(labelPLAYER1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRplayer.entryPLAYER \
   -textvariable ENTRYplayer \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRright.fRplayer.labelPLAYER2 \
   -text "$aRtext(labelPLAYER2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

button .fRright.fRplayer.buttHELPplayer \
   -text "$aRtext(buttHELPplayer)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {help_for_player}

## PACK the widgets in the '.fRright.fRplayer' frame.

pack .fRright.fRplayer.labelPLAYER1 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRright.fRplayer.entryPLAYER \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRright.fRplayer.labelPLAYER2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRright.fRplayer.buttHELPplayer \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+##########################################################
## IN THE '.fRright.fRoptsHead' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+##########################################################

label .fRright.fRoptsHead.labelOPTShead \
   -text "$aRtext(labelOPTShead)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRright.fRoptsHead.labelOPTShead \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

##+##########################################################
## IN THE '.fRright.fRexecOpts' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+##########################################################

label .fRright.fRexecOpts.labelEXECopts \
   -text "$aRtext(labelEXECopts)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

pack .fRright.fRexecOpts.labelEXECopts \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

## Set a variable that we will use to replace this frame
## with other 'execOpts' frames, using 'pack forget' in
## the 'set_*_opts' procs.

set curEXECOPTSframe ".fRright.fRexecOpts"


##+############################################################
## IN THE '.fRright.fRaudparms.fRaudioHead' frame -- DEFINE one
## LABEL widget.  Then PACK IT.
##+############################################################

label .fRright.fRaudparms.fRaudioHead.labelAUDIOHEAD \
   -text "$aRtext(labelAUDIOHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

## PACK the widgets in the '.fRright.fRaudparms.fRaudioHead' frame.

pack  .fRright.fRaudparms.fRaudioHead.labelAUDIOHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+##############################################################
## IN THE '.fRright.fRaudparms.fRacodec' frame -- DEFINE a
## LABEL-ENTRY-LABEL triplet of widgets. Then PACK THEM.
##+##############################################################

label .fRright.fRaudparms.fRacodec.labelACODEC1 \
   -text "$aRtext(labelACODEC1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRaudparms.fRacodec.entryACODEC \
   -textvariable AUDIOcodec \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRright.fRaudparms.fRacodec.labelACODEC2 \
   -text "$aRtext(labelACODEC2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

## PACK the widgets in the '.fRright.fRaudparms.fRacodec' frame:

pack .fRright.fRaudparms.fRacodec.labelACODEC1 \
     .fRright.fRaudparms.fRacodec.entryACODEC \
     .fRright.fRaudparms.fRacodec.labelACODEC2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+###############################################################
## IN THE '.fRright.fRaudparms.fRachannels' frame -- DEFINE a
## LABEL-ENTRY-LABEL triplet of widgets. Then PACK THEM.
##+###############################################################

label .fRright.fRaudparms.fRachannels.labelACHANNELS1 \
   -text "$aRtext(labelACHANNELS1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRaudparms.fRachannels.entryACHANNELS \
   -textvariable AUDIOchannels \
   -bg $entryBKGD \
   -width 3 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRright.fRaudparms.fRachannels.labelACHANNELS2 \
   -text "$aRtext(labelACHANNELS2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label


## PACK the widgets in the '.fRright.fRaudparms.fRachannels' frame:

pack .fRright.fRaudparms.fRachannels.labelACHANNELS1 \
     .fRright.fRaudparms.fRachannels.entryACHANNELS \
     .fRright.fRaudparms.fRachannels.labelACHANNELS2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+###############################################################
## IN THE '.fRright.fRaudparms.fRasrate' frame -- DEFINE a
## LABEL-ENTRY-LABEL triplet of widgets. Then PACK THEM.
##+###############################################################

label .fRright.fRaudparms.fRasrate.labelASRATE1 \
   -text "$aRtext(labelASRATE1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRaudparms.fRasrate.entryASRATE \
   -textvariable ASAMPLErate \
   -bg $entryBKGD \
   -width 8 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRright.fRaudparms.fRasrate.labelASRATE2 \
   -text "$aRtext(labelASRATE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label


## PACK the widgets in the '.fRright.fRaudparms.fRasrate' frame:

pack .fRright.fRaudparms.fRasrate.labelASRATE1 \
     .fRright.fRaudparms.fRasrate.entryASRATE \
     .fRright.fRaudparms.fRasrate.labelASRATE2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+###############################################################
## IN THE '.fRright.fRaudparms.fRabrate' frame -- DEFINE a
## LABEL-ENTRY-LABEL triplet of widgets. Then PACK THEM.
##+###############################################################

label .fRright.fRaudparms.fRabrate.labelABRATE1 \
   -text "$aRtext(labelABRATE1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRaudparms.fRabrate.entryABRATE \
   -textvariable ABITrate \
   -bg $entryBKGD \
   -width 8 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRright.fRaudparms.fRabrate.labelABRATE2 \
   -text "$aRtext(labelABRATE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label


## PACK the widgets in the '.fRright.fRaudparms.fRabrate' frame:

pack .fRright.fRaudparms.fRabrate.labelABRATE1 \
     .fRright.fRaudparms.fRabrate.entryABRATE \
     .fRright.fRaudparms.fRabrate.labelABRATE2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0



##+#############################################################
## IN THE '.fRright.fRaudparms.fRaother' frame -- DEFINE a
## LABEL-ENTRY pair of widgets. Then PACK THEM.
##+#############################################################

label .fRright.fRaudparms.fRaother.labelAOTHER \
   -text "$aRtext(labelAOTHER)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRaudparms.fRaother.entryAOTHER \
   -textvariable AUDIOotherParms \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

#   -width 30 \

## PACK the widgets in the '.fRright.fRaudparms.fRaother' frame:

pack .fRright.fRaudparms.fRaother.labelAOTHER \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRright.fRaudparms.fRaother.entryAOTHER \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+############################################################
## IN THE '.fRright.fRaudparms.fRotherHead' frame -- DEFINE one
## LABEL widget.  Then PACK IT.
##+############################################################

label .fRright.fRaudparms.fRotherHead.labelOTHERHEAD \
   -text "$aRtext(labelOTHERHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRright.fRaudparms.fRotherHead.labelOTHERHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+###############################################################
## IN THE '.fRright.fRaudparms.fRthreads' frame -- DEFINE one
## LABEL-ENTRY-LABEL triplet of widgets. Then PACK THEM.
##+###############################################################

label .fRright.fRaudparms.fRthreads.labelTHREADS1 \
   -text "$aRtext(labelTHREADS1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRaudparms.fRthreads.entryTHREADS \
   -textvariable Nthreads \
   -bg $entryBKGD \
   -width 3 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRright.fRaudparms.fRthreads.labelTHREADS2 \
   -text "$aRtext(labelTHREADS2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

## PACK the widgets in the '.fRright.fRaudparms.fRthreads' frame:

pack .fRright.fRaudparms.fRthreads.labelTHREADS1 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRright.fRaudparms.fRthreads.entryTHREADS \
   -side left \
   -anchor w \
   -fill x \
   -expand 0

pack .fRright.fRaudparms.fRthreads.labelTHREADS2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRright.fRaudparms.fRguide' frame -- DEFINE one
## LABEL widget.  Then PACK IT.
##+########################################################

label .fRright.fRaudparms.fRguide.labelGUIDE \
   -text "$aRtext(labelGUIDE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $guideBKGD

## PACK the widgets in the '.fRright.fRaudparms.fRguide' frame:

pack .fRright.fRaudparms.fRguide.labelGUIDE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+#####################################################################
## END OF SECTION TO DEFINE AND PACK THE GUI WIDGETS.
##+#####################################################################

##+#####################################################################
##+#####################################################################
## DEFINE BINDINGS:  button1-release bindings on ENCODING-FORMAT radiobuttons.
##                   Also bindings on the checkbutton and the listbox.
##+#####################################################################

## Bindings for the 'Encoding format' radiobuttons.

bind .fRright.fRencoder.radbuttMP3  <ButtonRelease-1>  \
   {set_defaults_for_encoding libmp3lame}

bind .fRright.fRencoder.radbuttVORBIS  <ButtonRelease-1>  \
   {set_defaults_for_encoding libvorbis}

bind .fRright.fRencoder.radbuttAAC  <ButtonRelease-1>  \
   {set_defaults_for_encoding libfaac}

bind .fRright.fRencoder.radbuttFLAC  <ButtonRelease-1>  \
   {set_defaults_for_encoding flac}

bind .fRright.fRencoder.radbuttMP2  <ButtonRelease-1>  \
   {set_defaults_for_encoding mp2}


## Bindings for the 'MoreAudioOutParms' checkbutton.

bind .fRright.fRbuttons.chkbuttMOREoutparms  <ButtonRelease-1>  \
   {pack_more_outparms_frame}


## Bindings for the listbox widget.

bind .fRleft.fRlistbox.listbox <ButtonRelease-1>  {loadOptsFrame_perListboxSelection}


##+##########################################################################
##+##########################################################################
## DEFINE PROCEDURES:
##
##  'get_INfilename'               - called by the audio in-file 'Browse' button.
##
##  'get_chars_before_last'        - called by the proc 'get_INfilename'.
##
##  'set_defaults_for_encoding'    - called by bindings on the ENCODING FORMAT
##                                   radiobuttons.
##
##                                   Sets defaults for the audio-and-other
##                                   GUI widgets, for a given encoding type.
##
##  'loadOptsFrame_perListboxSelection' - called by a click on the listbox.
##
##                                 Calls on a 'show_*_opts' proc depending on
##                                 the listbox line (audio-exec-operation) selected.
##
##                                 Example proc name: 'show_CLIP_opts'
##
##  'exec_audio_operation'       - called by a click on the 'ExecOption' button.
##
##                                 Calls on a 'set_*_cmd' proc depending on
##                                 the listbox line (media-file-operation) selected.
##
##                                 Example proc name: 'set_CLIP_cmd'
##
##                                 Then executes the 'ffmpeg' command string built by
##                                 the 'set_*_cmd' proc --- in an 'xterm' window.
##
##--------------------------------------------------------------------------------------
## For each ExecOption added to the listbox, a 'show_*_opts' proc and a 'set_*_cmd' proc
## should be provided --- like the following.
##           (And calls will need to be added to the 2 procs above:
##            'loadOptsFrame_perListboxSelection' and 'exec_audio_operation'.)
##--------------------------------------------------------------------------------------
##  'show_CLIP_opts'            - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'clip' frames and widgets into an 'execOpts' frame.
##
##  'set_CLIP_cmd'              - called by the 'exec_audio_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for CLIPPING --- to be
##                                used in the proc 'exec_audio_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_CHG-VOLUME_opts'      - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'chg-volume' frames and widgets into an 'execOpts' frame.
##
##  'set_CHG-VOLUME_cmd'        - called by the 'exec_audio_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for CHG-VOLUME --- to be
##                                used in the proc 'exec_audio_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_PROPSin_opts'         - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'PROPSin' frames and widgets into an 'execOpts' frame.
##
##  'set_PROPSin_cmd'           - called by the 'exec_audio_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for showing properties
##                                of the input media file. The command string is to be used
##                                in the proc 'exec_audio_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_PROPSout_opts'        - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'PROPSout' frames and widgets into an 'execOpts' frame.
##
##  'set_PROPSout_cmd'          - called by the 'exec_audio_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for showing properties
##                                of the output media file. The command string is to be used
##                                in the proc 'exec_audio_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_CONVERT_opts'         - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'convert' frames and widgets into an 'execOpts' frame.
##
##  'set_CONVERT_cmd'           - called by the 'exec_audio_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for CONVERTING the input
##                                media file to a new audio format.
##                                The command string is to be used in the proc
##                                'exec_audio_operation'.
##
##--------------------------------------------------------------------------------------
##
##  'play_audio_file'          - called by the 'PlayInAudio' and 'PlayOutAudio' buttons.
##                               Launches an audio 'player' program to play the input or
##                               output audio file.
##
##  'set_width_of_labels'      - called in the 'Additional GUI Initialization'
##                               section at the bottom of this script.
##
##                               Sets a nice common width of the labels on the
##                               left of each of the GUI sections:
##                                - audio
##                                - other
##                               according to the font being used for labels.
##
##  'pack_more_outparms_frame'  - called by button1-release binding on the
##                                'MoreAudioOutParms' checkbutton.
##
##                                Shows the 'audio' and 'other' frames of the
##                                GUI if the 'MoreAudioOutParms' checkbutton
##                                is ON. OR, 'forgets' the frame containing
##                                the 'audio' and 'other' frames.
##
##  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##+#####################################################################
##+#####################################################################

##+#####################################################################
## PROC 'get_INfilename'
##+#####################################################################
## PURPOSE: To get a filename to use for the input audio file.
##          Put the filename in the entry field variable, INfilename.
##
## CALLED BY: the 'Browse ...' button in frame '.fRinfile'.
##+#####################################################################

proc get_INfilename {} {

   ## INPUT globals:
   global inDIR
   # global env

   ## INPUT-OUTPUT globals:
   global INfilename

   ## Get a file name.

   set fName [tk_getOpenFile -parent . \
      -title "Select the filename of the input audio file." \
      -initialdir "$inDIR" ]

   ## FOR TESTING:
   #   puts "fName : $fName"

   ## Check if fName var is empty.

   if {"$fName" == ""} {return}

   ## Put $fName in INfilename. Reset the inDIR var.

   if {[file exists "$fName"]} {
      set INfilename "$fName"
      .fRright.fRinfile.entryINFILE xview end
      set inDIR [ get_chars_before_last / in "$INfilename" ]
   }

}
## END OF PROC 'get_INfilename'


##+###################################################################
## PROC 'get_chars_before_last'
##+###################################################################
## INPUT:  A character and a string.
##         Note: The "in" parameter is there only for clarity.
##
## OUTPUT: Returns all of the characters in the string "strng" that
##         are BEFORE the last occurence of the characater "char".
##
## CALLED BY: proc 'get_img_filename'
##+##################################################################

proc get_chars_before_last { char in strng } {

   set endIDX [ expr [string last $char $strng ] - 1 ]
   set output [ string range $strng 0 $endIDX ]

   ## FOR TESTING:
   # puts "From 'get_chars_before_last' proc:"
   # puts "STRING: $strng"
   # puts "CHAR: $char"
   # puts "RANGE up to LAST CHAR - start: 0   endIDX: $endIDX"

   return $output

}
## END OF PROC 'get_chars_before_last'


##+#####################################################################
## PROC 'set_defaults_for_encoding'
##+#####################################################################
## PURPOSE: For a given encoding type, to set defaults for
##          the widgets on the GUI --- esp. the entry widgets.
##
## NOTE1: We set the default 'player' here, according to the 'encoding format'
##        chosen for the output file, just in case there are cases
##        where a certain 'player' is more successful with certain
##        'audio encoding' formats.
##
## NOTE2: The output types here correspond to the output types that
##        the Audacity interactive editor supports:
##           OGG Vorbis, MP3, MP2, FLAC (and maybe someday some
##           uncompressed formats: WAV, AIIF, PCM)
##        Reference: http://wiki.audacityteam.org/wiki/FFmpeg_integration
##        The main thing is this utility will read uncompressed formats
##        like WAV, AIFF, PCM, and make the compressed formats
##        Vorbis, MP3, MP2, AAC, and FLAC.
##        For a good description of these formats, see
## http://hopewiki.socialhistoryportal.org/index.php/List_of_Audio_File_Formats
##
## CALLED BY: a button1-release binding on the 'encoding format' radiobuttons
##            and called once in the 'Additional GUI Initialization'
##            section at the bottom of this script.
##+#####################################################################

proc set_defaults_for_encoding { encodeType } {

   ## FOR TESTING: (to dummy out this proc)
   #  return

   ## INPUT globals:
   global outDIR env

   ## OUTPUT globals:
   global OUTfilename OUTformat ENTRYplayer \
      AUDIOcodec AUDIOchannels ASAMPLErate ABITrate AUDIOotherParms Nthreads

   ############################
   ## FOR 'libmp3lame' ENCODING:
   ############################

   if {"$encodeType" == "libmp3lame"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.mp3"
      set OUTformat "mp3"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      set AUDIOcodec "libmp3lame"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      ## We use the '-aq' (audio quality) parameter for VBR (Variable Bit Rate)
      ## encoding, instead of '-ab' (audio bit rate) for CBR (Constant Bit Rate)
      ## encoding. The MP3 format supports VBR.
      set ABITrate ""
      # set ABITrate "128k"
      set AUDIOotherParms "-aq 2"
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "libmp3lame"}


   ###########################
   ## FOR 'libvorbis' ENCODING:
   ###########################

   if {"$encodeType" == "libvorbis"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.oga"
      set OUTformat "ogg"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      # set AUDIOcodec "vorbis"
      set AUDIOcodec "libvorbis"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      ## We use the '-aq' (audio quality) parameter for VBR (Variable Bit Rate)
      ## encoding, instead of '-ab' (audio bit rate) for CBR (Constant Bit Rate)
      ## encoding. The Vorbis format supports VBR.
      set ABITrate ""
      # set ABITrate "128k"
      set AUDIOotherParms "-aq 5"
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "libvorbis"}


   #########################
   ## FOR 'libfaac' ENCODING:
   ## "Advanced Audio Coding (AAC) is a standardized, lossy compression
   ##  and encoding scheme for digital audio.  Designed to be the successor
   ##  of the MP3 format, AAC generally achieves better sound quality than
   ##  MP3 at similar bitrates."
   #########################

   if {"$encodeType" == "libfaac"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.aac"
      set OUTformat "adts"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      set AUDIOcodec "libfaac"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      ## This format does not like a bit-rate.
      ## It causes the error "ffmpeg: unrecognized option '-br'".
      set ABITrate ""
      set AUDIOotherParms ""
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "libfaac"}


   #####################
   ## FOR 'flac' ENCODING:
   #####################

   if {"$encodeType" == "flac"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.flac"
      set OUTformat "flac"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      set AUDIOcodec "flac"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      ## This format does not like a bit-rate.
      ## It causes the error "ffmpeg: unrecognized option '-br'".
      set ABITrate ""
      set AUDIOotherParms ""
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "flac"}

   #####################
   ## FOR 'mp2' ENCODING:
   #####################

   if {"$encodeType" == "mp2"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.mp2"
      set OUTformat "mp2"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      set AUDIOcodec "mp2"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      ## This format does not like a bit-rate.
      ## It causes the error "ffmpeg: unrecognized option '-br'".
      set ABITrate ""
      set AUDIOotherParms ""
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "mp2"}


   ###########################
   ## FOR 'pcm_s16le' ENCODING:
   ###########################

   ## COMMENTED, for now.
   if {0} {
   if {"$encodeType" == "pcm_s16le"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.pcm" 
      ## An example of creating a '.pcm' file:
      ## http://stackoverflow.com/questions/11986279/can-ffmpeg-convert-audio-from-raw-pcm-to-wav
      ## NOTE the statment:
      ## "The wav container just adds a simple header to the raw PCM data.
      ##  The header includes the format, sample rate, and number of channels."
      set OUTformat "s16le"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      set AUDIOcodec "pcm_s16le"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      set ABITrate "128k" OR "" ?
      set AUDIOotherParms ""
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "pcm"}
   }
   ## END OF  if {0} (commenting)


   ###########################
   ## FOR 'wav' ENCODING:
   ###########################

   ## COMMENTED, for now.
   if {0} {
   if {"$encodeType" == "wav"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.wav" 
      ## An example of creating a '.wav' file:
      ## http://savvyadmin.com/extract-audio-from-video-files-to-wav-using-ffmpeg/
      ## NOTE the acodec used in the command:
      ## ffmpeg -i video.mkv -acodec pcm_s16le -ac 2 audio.wav
      set OUTformat "wav"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      set AUDIOcodec "pcm_s16le"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      set ABITrate "128k" OR "" ?
      set AUDIOotherParms ""
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "wav"}
   }
   ## END OF  if {0} (commenting)


   ###########################
   ## FOR 'aiff' ENCODING:
   ###########################

   ## COMMENTED, for now.
   if {0} {
   if {"$encodeType" == "aiff"} {
      set OUTfilename "$outDIR/$env(USER)_output_audio.aif" 
      ## An example of creating a '.aif' file:
      ##    ffmeg .... ??? ....
      ## NOTE: There are lots of web pages on going from AIFF
      ## to MP3, but not much on creating an AIFF.
      set OUTformat "aiff"
      set ENTRYplayer "xffplay"
      # set ENTRYplayer "xmplayer"
      # set ENTRYplayer "gmplayer"
      # set ENTRYplayer "totem"
      # set ENTRYplayer "vlc"
      set AUDIOcodec "pcm_s16le"
      set AUDIOchannels "2"
      set ASAMPLErate "44100"
      set ABITrate "128k" OR "" ?
      set AUDIOotherParms ""
      set Nthreads "1"
   }
   ## END OF   if {"$encodeType" == "aiff"}
   }
   ## END OF  if {0} (commenting)

}
## END OF PROC 'set_defaults_for_encoding'


##+#########################################################################
## proc  'loadOptsFrame_perListboxSelection'
##+#########################################################################
## PURPOSE: Calls on a 'show_*_opts' proc
##          depending on the exec-options listbox line selected.
##
## CALLED BY: button1-release on the listbox.
##
## See the listbox insert statements above (where the listbox widget was
## defined) for the exec-option ID strings that were loaded in the listbox.
##+#########################################################################

proc loadOptsFrame_perListboxSelection {} {

   ## FOR TESTING: (to dummy out this proc)
   #  return

   ## OUTPUT globals:
   global VARexecOption

   set sel_INDEX [ .fRleft.fRlistbox.listbox curselection ]

   if { $sel_INDEX != "" } {
      set EXECline  [ .fRleft.fRlistbox.listbox get $sel_INDEX ]

      ## Extract the first part of the selected listbox line (before the
      ## first '#' character) into the variable 'VARexecOption'.

      set TEMPlist [split $EXECline #]
      set VARexecOption [lindex $TEMPlist 0]
      set VARexecOption [string trim $VARexecOption]
   } else {return}


   ## FOR TESTING:
   #   puts "proc 'loadOptsFrame_perListboxSelection' >  VARexecOption: $VARexecOption"

   if {"$VARexecOption" == ""} {return}

   #####################################################################################
   ## For the just-selected ExecOption, run the corresponding 'show_*_opts' proc.
   #####################################################################################

   if {"$VARexecOption" == "CLIP"} {show_CLIP_opts}

   if {"$VARexecOption" == "CHG-VOLUME"} {show_CHG-VOLUME_opts}

   if {"$VARexecOption" == "PROPERTIES-IN"} {show_PROPSin_opts}

   if {"$VARexecOption" == "PROPERTIES-OUT"} {show_PROPSout_opts}

   if {"$VARexecOption" == "CONVERT"} {show_CONVERT_opts}

   ####################################################################################
   ## THE FOLLOWING EXEC-OPTIONS ARE ON MY 'TO-IMPLEMENT' LIST.
   ####################################################################################

   # if {"$VARexecOption" == "ADD-CHANNEL"} {show_ADD-CHANNEL_opts}

   # if {"$VARexecOption" == "EXTRACT-CHANNEL"} {show_EXTRACT-CHANNEL_opts}

   # if {"$VARexecOption" == "REMOVE-CHANNEL"} {show_REMOVE-CHANNEL_opts}

}
## END OF PROC 'loadOptsFrame_perListboxSelection'


##+#####################################################################
## PROC 'exec_audio_operation'
##+#####################################################################
## PURPOSE: To call on the appropriate 'set_*_cmd' proc and then
##          use the 'ffmpeg' command string in the variable 'ffmpegCMD'
##          to execute 'ffmpeg' --- in an 'xterm' window.
##
## CALLED BY:  a click on the 'ExecOption' button.
##+#####################################################################

proc exec_audio_operation { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global VARexecOption INfilename OUTfilename ffmpegCMD DIRscripts

   ## The other parameters for making the audio file are used
   ## in the 'set_*_cmd' procs called below. Those parameters include
   ##   AUDIOcodec AUDIOchannels ASAMPLErate ABITrate AUDIOotherParms
   ##   Nthreads ENCODERname
   ## We do not need to declare them as global here. They are
   ## incorporated in the 'ffmpegCMD' global variable.

   ## If we ever need to, we could add a 'DELAYseconds' prompt on the GUI,
   ## and insert a pause here to delay the start of the 'ffmpeg' processing.

   # set DELAYmillisecs [expr {$DELAYseconds * 1000}]
   # after $DELAYmillisecs

   ################################################################
   ## If the no option has been selected yet, simply return.
   ## (We could popup a message here to advise the use to select
   ##  an option from the listbox.)
   ################################################################

   if {"$VARexecOption" == ""} {return}

   ## FOR TESTING:
   #   puts "proc 'exec_audio_operation': VARexecOption: $VARexecOption"

   ################################################################
   ## Advise the user that processing is starting? Not needed?
   ################################################################

   # .fRright.fRmsg.labelMSG configure -text "Processing is starting for the chosen ExecOption."
   # update idletasks


   ##############################################################
   ## Remove trailing and leading blanks (if any) from the user's
   ## entry in the input and output filename 'entry' widgets.
   ##############################################################

   set INfilename  [string trim "$INfilename"]
   set OUTfilename [string trim "$OUTfilename"]


   ###################################################################
   ## If 'VARexecOption' is 'PROPERTIES-IN' or 'PROPERTIES-OUT', we
   ## do NOT fall into the 'MAKE OUTPUT FILE' section below. We
   ## simply put the output of the 'ffmpeg -i' command in a variable
   ## and show it in a popup window and return out of this proc.
   ###################################################################


   ##############################################################
   ## Do the 'PROPERTIES-IN' processing and return.
   ##############################################################

   if {"$VARexecOption" == "PROPERTIES-IN"} {

      if {![file exists "$INfilename"]} {
         popup_msgVarWithScroll .topINFILE \
            "The file named in the INPUT-audio-file field was not found."
         return
      }

      #######################################################
      ## See the comments on 'foreground' and 'background'
      ## execution with the Tcl 'exec' command, in the
      ## 'MAKE OUTPUT FILE' section below.
      ## I try using the 'foreground' method first.
      ## I may switch this to a 'background' method later.
      ######################################################

      set PROPStext [exec $DIRscripts/audioFilePROPERTIES_ffmpeg-i.sh "$INfilename"]

      popup_msgVarWithScroll .topPROPSin "$PROPStext"

      return
   }
   ## END OF if


   ##############################################################
   ## Do the 'PROPERTIES-OUT' processing and return.
   ##############################################################

   if {"$VARexecOption" == "PROPERTIES-OUT"} {

      if {![file exists "$INfilename"]} {
         popup_msgVarWithScroll .topOUTFILE \
            "The file named in the OUTPUT-audio-file field was not found."
         return
      }

      #######################################################
      ## See the comments on 'foreground' and 'background'
      ## execution with the Tcl 'exec' command, in the
      ## 'MAKE OUTPUT FILE' section below.
      ## I try using the 'foreground' method first.
      ## I may switch this to a 'background' method later.
      ######################################################

      set PROPStext [exec $DIRscripts/audioFilePROPERTIES_ffmpeg-i.sh "$OUTfilename"]

      popup_msgVarWithScroll .topPROPSout "$PROPStext"

      return
   }
   ## END OF if


   #####################################################################
   ## If we got here, the user is trying to exec an option other than
   ## PROPERTIES-IN or PROPERTIES-OUT.
   #####################################################################
   ## According to the currently selected option in the listbox,
   ## execute the corresponding 'set_*_cmd' proc --- to set the
   ## 'ffmpegCMD' variable.
   #####################################################################

   if {"$VARexecOption" == "CLIP"} {set_CLIP_cmd}

   if {"$VARexecOption" == "CHG-VOLUME"} {set_CHG-VOLUME_cmd}

   if {"$VARexecOption" == "CONVERT"} {set_CONVERT_cmd}


   ####################################################################
   ## The following exec-options are on my 'TO-IMPLEMENT' list.
   ####################################################################

   # if {"$VARexecOption" == "ADD-CHANNEL"} {set_ADD-CHANNEL_cmd}

   # if {"$VARexecOption" == "EXTRACT-CHANNEL"} {set_EXTRACT-CHANNEL_cmd}

   # if {"$VARexecOption" == "REMOVE-CHANNEL"} {set_REMOVE-CHANNEL_cmd}


   ## FOR TESTING:  (VERY USEFUL)
   #   puts "proc 'exec_audio_operation' - ffmpegCMD: $ffmpegCMD"

   ###################################################################
   ## MAKE THE OUTPUT FILE --- by executing the 'ffmpegCMD' string
   ## in an 'xterm' window.
   ####################################################################
   ## SOME SYNTAX NOTES on running a program via the Tcl 'exec' command:
   ####################################################################
   ## On page 105 of the 4th edition of 'Practical Programming in Tcl & Tk',
   ## is the following quote on the Tcl 'exec' command:
   ##
   ## "The 'exec' command runs programs from your Tcl script. For example:
   ##      set d [exec date]
   ## The standard output of the program is returned as the value of
   ## the 'exec' command. However, if the program writes to its standard
   ## error channel or exits with a nonzero status code, then 'exec'
   ## raises an error. If you do not care about the exit status, or you
   ## use a program that insists on writing to standard error, then you
   ## can use 'catch' to mask the errors:
   ##   catch {exec program arg arg} result"
   ##
   ## Unfortunately, running a player program in 'foreground' mode
   ## like this makes the button widgets on the GUI unavailable ---
   ## in particular, the 'Help' button.
   ##
   ## A 'foreground' run per page 105 of 'Practical Programming in Tcl & Tk'.
   ## NOT USED, because it 'locks up' the GUI.
   #######################################################################
   ## On page 107 of the 4th edition of 'Practical Programming in Tcl & Tk',
   ## is the following quote on the Tcl 'exec' command and 'background' mode:
   ##
   ## "A trailing '&' causes the program to run in the background.
   ##  In this case, the process identifier is returned by the 'exec'
   ##  command. Otherwise, the 'exec' command blocks during execution
   ##  of the program, and the standard output of the program is the
   ##  return code of 'exec'."
   ##
   ## Page 83 of the same book says:
   ## "'catch' returns zero if there was no error caught,
   ##   or a nonzero error code if it did catch an error."
   ####################################################################
   ## A couple of examples of using a PID (process ID) with Tcl:
   ##
   ## catch {eval exec $feREADER_text \"$FULFILname\"  &} ProcessPID
   ##
   ## set RETcode [ catch {eval exec ${feDIR}/tkGUIs/shofil.tk \
   ##    "$FULFILname" &} ProcessPID ]
   ##
   ####################################################################
   ## An alternative form of trying 'exec':
   ##    exec  /bin/sh -c "$...."
   ####################################################################


   #########################################################################
   ## Following is a 'background' run per page 107 of
   ## 'Practical Programming in Tcl & Tk'.
   ##
   ## I run 'ffmpeg' in an 'xterm' window so that encoding messages can be
   ## seen by the user. I use the '-hold' option on 'xterm' so that the
   ## window is held open when 'ffmpeg' processing stops --- so that the
   ## user can review the 'ffmpeg' processing messages and error messages,
   ## if any.
   #########################################################################
   ## 'eval' is needed here?? No. (?)
   ###########################################################################
   ## If there are problems with calling 'xterm' and 'ffmpeg' from within this
   ## Tk script (with the many parameters to 'ffmpeg'), we could switch to
   ## using an 'external' shell script to execute the 'xterm' and 'ffmpeg'
   ## commands (with the many options and parameters).
   ###########################################################################

   set RETcode [ catch {exec xterm -title 'ffmpeg' -bg black -fg white -hold \
      -geometry 90x48+100+100 -e $ffmpegCMD &} XtermPID ]

   if {$RETcode != 0} {
      set ERRtext \
"Proc 'exec_audio_operation' encountered an error on trying to make file
[file tail "$OUTfilename"]
in directory
[file dirname "$OUTfilename"]
using the 'ffmpeg' command.

RETcode: $RETcode
Message: $XtermPID
Stopping processing."
      popup_msgVarWithScroll .topERR "$ERRtext"
      return
   }
   ## END OF if {$RETcode != 0}

   ## FOR TESTING:
   if {0} {
       puts ""
       puts "***********************"
       puts "PROC 'exec_audio_operation' ran 'ffmpeg' with"
       puts "OUTfilename: $OUTfilename"
       puts "and got"
       puts "RETcode: $RETcode"
       puts "XtermPID: $XtermPID"
       puts "***********************"
       puts ""
   }

   #############################################################
   ## Restore the message in the MSG frame? A couple of seconds
   ## after the job is submitted? Not needed?
   #############################################################

   # after 2000
   # .fRright.fRmsg.labelMSG configure -text "$aRtext(labelMSG)"

}
## END OF PROC 'exec_audio_operation'


##+#####################################################################
## PROC 'show_CLIP_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'CLIP' frames and widgets into the
##          '.fRright.fRparametersCLIP' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_CLIP_opts { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label \
      entryBKGD  BDwidthPx_entry

   ## OUTPUT globals:
   global  curEXECOPTSframe  VARstartTime  VARdurationTime

   ## If the frame for CLIP parameters is not defined yet,
   ## define the CLIP frame. Also define any SUB-frames that might
   ## be needed for lines of widgets. Also define and pack the widgets.

   if {![winfo exists .fRright.fRparametersCLIP]} {

      frame .fRright.fRparametersCLIP   -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCLIP.fRclip1   -relief $RELIEF_frame  -bd $BDwidth_frame

      ## We go ahead and define a sub-frame, just in case we ever want to add
      ## more clip parameters in another sub-frame.

      ## We pack the one sub-frame here (to do it only once), but we
      ## pack the parent frame below --- doing the parent-forget-and-pack
      ## each time a CLIP operation is requested by the user.

      pack .fRright.fRparametersCLIP.fRclip1 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      ##+########################################################
      ## In the '.fRright.fRparametersCLIP.fRclip1' frame -
      ## DEFINE 2 ENTRY widgets, for start-time and duration-time
      ## --- along with 2 LABEL widgets.
      ## PACK the 4 label and entry widgets.
      ##+########################################################

      label .fRright.fRparametersCLIP.fRclip1.labelSTARTtime \
         -text "$aRtext(labelSTARTtime)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## The entry variables, VARstartTime and VARdurationTime,
      ## could be initialized in the additional-GUI-initialization
      ## section at the bottom of this script --- if you
      ## prefer to initialize them there.

      set VARstartTime "00:00:05"

      entry .fRright.fRparametersCLIP.fRclip1.entrySTARTtime \
         -textvariable VARstartTime \
         -font fontTEMP_fixedwidth \
         -width 9 \
         -bg "$entryBKGD" \
         -relief sunken \
         -bd $BDwidthPx_entry

      label .fRright.fRparametersCLIP.fRclip1.labelDURATIONtime \
         -text "$aRtext(labelDURATIONtime)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      set VARdurationTime "00:00:23"

      entry .fRright.fRparametersCLIP.fRclip1.entryDURATIONtime \
         -textvariable VARdurationTime \
         -font fontTEMP_fixedwidth \
         -width 9 \
         -bg "$entryBKGD" \
         -relief sunken \
         -bd $BDwidthPx_entry

      ## Pack the widgets in frame '.fRright.fRparametersCLIP.fRclip1'.

      pack .fRright.fRparametersCLIP.fRclip1.labelSTARTtime \
           .fRright.fRparametersCLIP.fRclip1.entrySTARTtime \
           .fRright.fRparametersCLIP.fRclip1.labelDURATIONtime \
           .fRright.fRparametersCLIP.fRclip1.entryDURATIONtime \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersCLIP]}

   ## FOR TESTING:
   #  puts "proc 'show_CLIP_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersCLIP' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRaudparms

   set SHOWoutparms0or1 0

   pack .fRright.fRparametersCLIP \
      -side top \
      -anchor nw \
      -fill none \
      -expand 0

   set curEXECOPTSframe ".fRright.fRparametersCLIP"

   ## FOR TESTING:
   #  puts "proc 'show_CLIP_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_CLIP_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_CLIP_opts'


##+#####################################################################
## PROC 'set_CLIP_cmd'
##+#####################################################################
## PURPOSE: Builds the 'ffmpeg' command for the CLIP operation, using
##          'CLIP' parameters from 'CLIP' frames and widgets in the
##          '.fRright.fRparametersCLIP' frame --- along with
##           audio-and-other parameters from other GUI widgets.
##
##          Puts the command in global variable 'ffmpegCMD'.
##
## CALLED BY:  proc 'exec_audio_operation' which is called by a click on the
##             'ExecOption' button.
##+#####################################################################
## REFERENCE: feNautilusScripts script
## '03a_1movieFile_CLIP-start-length_ffmpeg-ss-t_toMP4-H264-AAC.sh'
##  uses the following ordering of parameters to CLIP a movie file
## --- and write out a movie file in MP4-H264-AAC container-video-audio
## format.
##
##      ffmpeg -i "$FILENAME" \
##            -ss $STARTTIME \
##            -t $DURATION -f mp4 \
##            -copyts -async 1 \
##            -vcodec libx264 \
##            -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##            -crf 22 \
##            -acodec libfaac -ab 128k -ar 22050 -ac 1 \
##            -threads 1 "$FILEOUT"
##+####################################################################

proc set_CLIP_cmd { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global INfilename OUTfilename OUTformat \
      AUDIOcodec AUDIOchannels ASAMPLErate ABITrate AUDIOotherParms \
      Nthreads ENCODERname \
      VARstartTime VARdurationTime

   set BITratePARM "-br $ABITrate"
   if {"$ABITrate" == ""} {set BITratePARM ""}

   ## OUTPUT globals:
   global ffmpegCMD

   ## Reference: https://trac.ffmpeg.org/ticket/1645
   ##            'Duration calculation error'
   ## "...everything magically works when you use both -ss
   ## before and after -i option."

   set ffmpegCMD "ffmpeg -ss $VARstartTime -i \"$INfilename\" \
      -ss $VARstartTime -t $VARdurationTime \
      -f $OUTformat -acodec $AUDIOcodec -ac $AUDIOchannels \
      -ar $ASAMPLErate $BITratePARM $AUDIOotherParms \
      -threads $Nthreads \"$OUTfilename\" "

}
## END OF PROC 'set_CLIP_cmd'


##+#####################################################################
## PROC 'show_CHG-VOLUME_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'CHG-VOLUME' frames and widgets into the
##          '.fRright.fRparametersCHGVOLUME' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_CHG-VOLUME_opts { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label \
      entryBKGD  BDwidthPx_entry

   ## OUTPUT globals:
    global  curEXECOPTSframe  VARvolumeFactor

   ## If the frame for CHG-VOLUME parameters is not defined yet,
   ## define the CHG-VOLUME frame. Also define any SUB-frames that might
   ## be needed for lines of widgets. Also define and pack the widgets.

   if {![winfo exists .fRright.fRparametersCHGVOLUME]} {

      frame .fRright.fRparametersCHGVOLUME   -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCHGVOLUME.fRvolume1   -relief $RELIEF_frame  -bd $BDwidth_frame

      ## We pack the sub-frame here (to do it only once), but we
      ## pack the parent frame below --- doing the parent-forget-and-pack
      ## each time a CHG-VOLUME operation is requested by the user.

      pack .fRright.fRparametersCHGVOLUME.fRvolume1 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      ##+########################################################
      ## In the '.fRright.fRparametersCHGVOLUME.fRvolume1' frame -
      ## DEFINE a LABEL-ENTRY-LABEL widget triplet, for entry of
      ## a change-volume-factor
      ## --- along with examples in the 2nd LABEL widget.
      ## PACK the label and entry widgets.
      ##+########################################################

      label .fRright.fRparametersCHGVOLUME.fRvolume1.labelCHGVOLUME1 \
         -text "$aRtext(labelCHGVOLUME1)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## The entry variable, VARvolumeFactor,
      ## could be initialized in the additional-GUI-initialization
      ## section at the bottom of this script --- if you
      ## prefer to initialize it there.

      # set VARvolumeFactor "10"
      set VARvolumeFactor "25"

      entry .fRright.fRparametersCHGVOLUME.fRvolume1.entryVOLUMEfactor \
         -textvariable VARvolumeFactor \
         -font fontTEMP_fixedwidth \
         -width 5 \
         -bg "$entryBKGD" \
         -relief sunken \
         -bd $BDwidthPx_entry

      label .fRright.fRparametersCHGVOLUME.fRvolume1.labelCHGVOLUME2 \
         -text "$aRtext(labelCHGVOLUME2)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## Pack the widgets in frame '.fRright.fRparametersCHGVOLUME.fRvolume1'.

      pack .fRright.fRparametersCHGVOLUME.fRvolume1.labelCHGVOLUME1 \
           .fRright.fRparametersCHGVOLUME.fRvolume1.entryVOLUMEfactor \
           .fRright.fRparametersCHGVOLUME.fRvolume1.labelCHGVOLUME2 \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersCHGVOLUME]}

   ## FOR TESTING:
   #  puts "proc 'show_CHG-VOLUME_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersCHGVOLUME' frame.

   pack forget $curEXECOPTSframe .fRright.fRaudparms

   set SHOWoutparms0or1 0

   pack .fRright.fRparametersCHGVOLUME \
      -side top \
      -anchor nw \
      -fill none \
      -expand 0

   set curEXECOPTSframe ".fRright.fRparametersCHGVOLUME"

   ## FOR TESTING:
   #  puts "proc 'show_CHG-VOLUME_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_CHG-VOLUME_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_CHG-VOLUME_opts'


##+#####################################################################
## PROC 'set_CHG-VOLUME_cmd'
##+#####################################################################
## PURPOSE: Builds the 'ffmpeg' command for the CHG-VOLUME operation, using
##          'CHG-VOLUME' parameters from 'CHG-VOLUME' frames and widgets in the
##          '.fRright.fRparametersCHGFOLUME' frame --- along with
##          audio-and-other parameters from other GUI widgets.
##
##          Puts the command in global variable 'ffmpegCMD'.
##
## CALLED BY:  proc 'exec_audio_operation' which is called by a click on the
##             'ExecOption' button.
##+#####################################################################
## REFERENCE: feNautilusScripts script
## '06a_1movieFile_CHGaudioVOLUME_ffmpeg-vol_toMP4-H264-AAC.sh'
## uses the following ordering of parameters to CHG-VOLUME of a movie file
## --- and write out a movie file in MP4-H264-AAC container-video-audio
## format.
##      ...
##      AUDIOFACTOR=`expr $AUDIOPCNT \* 256 / 100`
##      ...
##      ffmpeg -i "$FILENAME" -f mp4 \
##         -vcodec libx264 \
##         -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##         -crf 22 \
##         -acodec libfaac -ab 128k  -ar 22050 -ac 1 \
##         -vol $AUDIOFACTOR -threads 1 "$FILEOUT"
##
##+#####################################################################

proc set_CHG-VOLUME_cmd { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global INfilename OUTfilename OUTformat \
      AUDIOchannels AUDIOcodec ASAMPLErate ABITrate AUDIOotherParms \
      Nthreads ENCODERname \
      VARvolumeFactor

   ## OUTPUT globals:
   global ffmpegCMD

   set BITratePARM "-br $ABITrate"
   if {"$ABITrate" == ""} {set BITratePARM ""}

   set tempVOLUMEfactor [expr {($VARvolumeFactor * 256)/100}]

   set ffmpegCMD "ffmpeg -i \"$INfilename\" -f $OUTformat \
      -acodec $AUDIOcodec -ac $AUDIOchannels \
      -ar $ASAMPLErate  $BITratePARM $AUDIOotherParms \
      -vol $tempVOLUMEfactor -threads $Nthreads \"$OUTfilename\" "

}
## END OF PROC 'set_CHG-VOLUME_cmd'


##+#####################################################################
## PROC 'show_PROPSin_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'PROPERTIES-IN' frames and widgets into the
##          '.fRright.fRparametersPROPERTIESin' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_PROPSin_opts { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label

   ## OUTPUT globals:
   global  curEXECOPTSframe

   ## If the frame for PROPERTIES-IN parameters is not defined yet,
   ## define the PROPERTIES-IN frame.
   ## Also define and pack a single label widget in that frame.

   if {![winfo exists .fRright.fRparametersPROPERTIESin]} {

      frame .fRright.fRparametersPROPERTIESin   -relief $RELIEF_frame  -bd $BDwidth_frame

      ##+########################################################
      ## In the '.fRright.fRparametersPROPERTIESin' frame -
      ## DEFINE one LABEL widget.
      ## PACK the label widget.
      ##+########################################################

      label .fRright.fRparametersPROPERTIESin.labelPROPERTIESin \
         -text "$aRtext(labelPROPERTIESin)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## Pack the widget in frame '.fRright.fRparametersPROPERTIESin'.

      pack .fRright.fRparametersPROPERTIESin.labelPROPERTIESin \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersPROPERTIESin]}

   ## FOR TESTING:
   #  puts "proc 'show_PROPSin_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersPROPERTIESin' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRaudparms

   set SHOWoutparms0or1 0

   pack .fRright.fRparametersPROPERTIESin \
      -side top \
      -anchor nw \
      -fill none \
      -expand 0

   set curEXECOPTSframe ".fRright.fRparametersPROPERTIESin"

   ## FOR TESTING:
   #  puts "proc 'show_PROPSin_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_PROPSin_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_PROPSin_opts'


##+#####################################################################
## PROC 'set_PROPSin_cmd'
##+#####################################################################
## We do not need this proc.
## We do not build a string 'ffmepgCMD' for this operation.
## In the proc 'exec_audio_operation', we execute the 'ffmpeg -i'
## command on $INfilename to get the properties info.
## To get around some problems with the 'ffmpeg -i' command,
## we use an 'external' shell script to get the info.
##+####################################################################


##+#####################################################################
## PROC 'show_PROPSout_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'PROPERTIES-OUT' frames and widgets into
##          the '.fRright.fRparametersPROPERTIESout' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_PROPSout_opts { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label

   ## OUTPUT globals:
   global  curEXECOPTSframe

   ## If the frame for PROPERTIES-OUT parameters is not defined yet,
   ## define the PROPERTIES-OUT frame.
   ## Also define and pack a single label widget in that frame.

   if {![winfo exists .fRright.fRparametersPROPERTIESout]} {

      frame .fRright.fRparametersPROPERTIESout -relief $RELIEF_frame  -bd $BDwidth_frame

      ##+########################################################
      ## In the '.fRright.fRparametersPROPERTIESout' frame -
      ## DEFINE one LABEL widget.
      ## PACK the label widget.
      ##+########################################################

      label .fRright.fRparametersPROPERTIESout.labelPROPERTIESout \
         -text "$aRtext(labelPROPERTIESout)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## Pack the widget in frame '.fRright.fRparametersPROPERTIESout'.

      pack .fRright.fRparametersPROPERTIESout.labelPROPERTIESout \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersPROPERTIESout]}

   ## FOR TESTING:
   #  puts "proc 'show_PROPSout_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersPROPERTIESout' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRaudparms

   set SHOWoutparms0or1 0

   pack .fRright.fRparametersPROPERTIESout \
      -side top \
      -anchor nw \
      -fill none \
      -expand 0

   set curEXECOPTSframe ".fRright.fRparametersPROPERTIESout"

   ## FOR TESTING:
   #  puts "proc 'show_PROPSout_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_PROPSout_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_PROPSout_opts'


##+#####################################################################
## PROC 'set_PROPSout_cmd'
##+#####################################################################
## We do not need this proc.
## We do not build a string 'ffmepgCMD' for this operation.
## In the proc 'exec_audio_operation', we execute the 'ffmpeg -i'
## command on $OUTfilename to get the properties info.
## To get around some problems with the 'ffmpeg -i' command,
## we use an 'external' shell script to get the info.
##+####################################################################


##+#####################################################################
## PROC 'show_CONVERT_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'CONVERT' frames and widgets into the
##          '.fRright.fRparametersCONVERT' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_CONVERT_opts { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label \
      chkbuttBKGD  RELIEF_chkbutt_hi  BDwidthPx_chkbutt

   ## OUTPUT globals:
   global  curEXECOPTSframe

   ## If the frame for CONVERT parameters is not defined yet,
   ## define the CONVERT frame.
   ## Also define and pack a single label widget in that frame.

   if {![winfo exists .fRright.fRparametersCONVERT]} {

      frame .fRright.fRparametersCONVERT   -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCONVERT.fRconvert1 -relief $RELIEF_frame  -bd $BDwidth_frame

      ## We pack the sub-frame here (to do it only once), but we
      ## pack the parent frame below --- doing the parent-forget-and-pack
      ## each time a CONVERT operation is requested by the user.

      pack .fRright.fRparametersCONVERT.fRconvert1 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      ##+########################################################
      ## In the '.fRright.fRparametersCONVERT.fRconvert1' frame -
      ## DEFINE one LABEL widget.
      ## PACK the label widget.
      ##+########################################################

      label .fRright.fRparametersCONVERT.fRconvert1.labelCONVERT \
         -text "$aRtext(labelCONVERT)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## Pack the widget in frame '.fRright.fRparametersCONVERT.fRconvert1'.

      pack .fRright.fRparametersCONVERT.fRconvert1.labelCONVERT \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersCONVERT]}

   ## FOR TESTING:
   #  puts "proc 'show_CONVERT_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersCONVERT' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRaudparms

   set SHOWoutparms0or1 0

   pack .fRright.fRparametersCONVERT \
      -side top \
      -anchor nw \
      -fill none \
      -expand 0

   set curEXECOPTSframe ".fRright.fRparametersCONVERT"

   ## FOR TESTING:
   #  puts "proc 'show_CONVERT_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_CONVERT_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_CONVERT_opts'


##+#####################################################################
## PROC 'set_CONVERT_cmd'
##+#####################################################################
## PURPOSE: Builds the 'ffmpeg' command for the CONVERT operation, using
##          'CONVERT' parameters --- namely, audio-and-other
##          parameters from widgets in the 'fRaudparms' frame.
##
##          Puts the command in global variable 'ffmpegCMD'.
##
## CALLED BY:  proc 'exec_audio_operation' which is called by a click on the
##             'ExecOption' button.
##+#####################################################################
## REFERENCE: feNautilusScripts script
## '13m4f2_1movieFile_CONVERTto_MP4-H264-AAC_ffmpeg.sh'
##  uses the following ordering of parameters to CONVERT a movie file
## --- and write out a new movie file in MP4-H264-AAC
## container-video-audio format.
##
##      ffmpeg -i "$FILENAME" -f mp4 \
##         -vcodec libx264 \
##         -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##         -crf 22 \
##         -acodec libfaac -ab 128k  -ar 22050 -ac 1 \
##         -threads 0 "$FILEOUT"
##
##  and from feNautilusScripts script
##  '07_1movieFile_SCALE-resize_WxHpixels_ffmpeg-s_toMP4-H264-AAC.sh'
##  we have the video-size parameter '-s' in
##
##   ffmpeg -i "$FILENAME" -f mp4 \
##      -vcodec libx264 \
##      -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##      -crf 22 \
##      -acodec libfaac -ab 128k  -ar 22050 -ac 1 \
##      -s $SCALE_WxH  -threads 0  "$FILEOUT"
## and
## from a video-capture script we have the video-rate parameter '-r' in
##      -r 30
##+####################################################################

proc set_CONVERT_cmd { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global INfilename OUTfilename OUTformat \
      AUDIOcodec AUDIOchannels ASAMPLErate ABITrate AUDIOotherParms \
      Nthreads ENCODERname \
      RESIZE0or1 RERATE0or1

   ## OUTPUT globals:
   global ffmpegCMD

   set BITratePARM "-br $ABITrate"
   if {"$ABITrate" == ""} {set BITratePARM ""}

   set ffmpegCMD "ffmpeg -i \"$INfilename\" \
      -f $OUTformat -acodec $AUDIOcodec -ac $AUDIOchannels \
      -ar $ASAMPLErate $BITratePARM $AUDIOotherParms \
      -threads $Nthreads \"$OUTfilename\" "

}
## END OF PROC 'set_CONVERT_cmd'


##+#####################################################################
## PROC 'play_audio_file'
##+#####################################################################
## PURPOSE: To startup a user-selected media-player program on the
##          input or output filename specified on the GUI.
##
##          For the input file, this is helpful to find the start and end
##          times for a 'clip' operation.
##
##          For the output file, this is helpful to check that the new audio
##          was successfully encoded (good sound --- no pops/crackles/buzzes).
##          For the CHG-VOLUME operation, this is helpful to determine if
##          the audio volume of the new file is what was desired.
##
## CALLED BY:  a click on the 'PlayInAudio' or 'PlayOutAudio' button.
##+#####################################################################

proc play_audio_file { audio_filename } {

   ## FOR TESTING: (dummy out this proc)
   # return

   global ENTRYplayer DIRscripts

   #######################################################
   ## Remove trailing and leading blanks (if any) from the
   ## user entry in the filename 'entry' widget.
   #######################################################

   set audio_filename [string trim "$audio_filename"]

   if {![file exists "$audio_filename"]} {
      popup_msgVarWithScroll .topOUTFILE \
         "The file was not found.
Filename: $audio_filename"
      return
   }

   ###################################################################
   ## If ENTRYplayer is 'xmplayer' or 'xfflay' set the
   ## executable to use.
   ####################################################################
   
   set PLAYERpgm "$ENTRYplayer"

   if {"$ENTRYplayer" == "xmplayer"} {
      set PLAYERpgm "$DIRscripts/mplayer_inXterm.sh"
   }

   if {"$ENTRYplayer" == "xffplay"} {
      set PLAYERpgm "$DIRscripts/ffplay_inXterm.sh"
   }

   ###################################################################
   ## PLAY THE AUDIO FILE.
   ####################################################################
   ## FOR SOME SYNTAX NOTES on running a program via the Tcl 'exec'
   ## command, see the notes above in the 'exec_audio_operation' proc.
   ####################################################################

   ## A 'foreground' run per page 105 of 'Practical Programming in Tcl & Tk'.
   ## NOT USED, because it 'locks up' the GUI.

   # catch {eval exec $PLAYERpgm "$audio_filename"} CatchMsg


   ##########################################################################
   ## A 'background' run per page 105 of 'Practical Programming in Tcl & Tk'.
   ##
   ## We use 'eval' to avoid a 'not found' error when we append
   ## some parms (or a space) to the player command.
   ##########################################################################

   set RETcode [ catch {eval exec $PLAYERpgm "$audio_filename" 2> /dev/null &} ViewerPID ]

   if {$RETcode != 0} {
      set ERRtext \
"Proc 'play_audio_file' encountered an error on trying to play media file
[file tail "$audio_filename"]
in directory
[file dirname "$audio_filename"]
using command '$PLAYERpgm'.

RETcode: $RETcode
Message: $ViewerPID
Stopping processing."
      popup_msgVarWithScroll .topERR "$ERRtext"
      return
   }
   ## END OF if {$RETcode != 0}


   ## FOR TESTING:
   if {0} {
       puts ""
       puts "***********************"
       puts "PROC 'play_audio_out' ran the player program"
       puts "PLAYERpgm: $PLAYERpgm"
       puts "with input"
       puts "audio_filename: $audio_filename"
       puts "and got"
       puts "RETcode: $RETcode"
       puts "ViewerPID: $ViewerPID"
       puts "***********************"
       puts ""
   }


}
## END OF PROC 'play_audio_file'


##+#####################################################################
## PROC 'set_width_of_labels'
##+#####################################################################
## PURPOSE: To set a nice common width of the labels on the left of
##          each of the GUI sections:
##            - audio
##            - other
##          according to the font being used for labels.
##
## CALLED:  in the Additional GUI Initialization' section at the
##          bottom of this script.
##+#####################################################################

proc set_width_of_labels { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global aRtext

   ## OUTPUT globals:
   global lengthOUTPUTprompts lengthAUDIOprompts lengthOTHERprompts

   ## SET lengthOUTPUTprompts (in characters).

   set lengthOUTPUTprompts [string length "$aRtext(labelOUTFILE)"]
   set tempLENGTH [string length "$aRtext(labelPLAYER1)"]
   if {$tempLENGTH > $lengthOUTPUTprompts} {set lengthOUTPUTprompts $tempLENGTH}


   ## SET lengthAUDIOprompts (in characters).

   set lengthAUDIOprompts [string length "$aRtext(labelACODEC1)"]
   set tempLENGTH [string length "$aRtext(labelACHANNELS1)"]
   if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH}
   set tempLENGTH [string length "$aRtext(labelASRATE1)"]
   if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH}
   set tempLENGTH [string length "$aRtext(labelABRATE1)"]
   if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH}
   set tempLENGTH [string length "$aRtext(labelAOTHER)"]
   if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH}


   ## SET lengthOTHERprompts (in characters).

   set lengthOTHERprompts [string length "$aRtext(labelTHREADS1)"]
   # set tempLENGTH [string length "$aRtext(????)"]
   # if {$tempLENGTH > $lengthOTHERprompts} {set lengthOTHERprompts $tempLENGTH}


   ## Adjust for typical overestimate because of variable-width font
   ## used for the labels.

   set widthFACTOR 0.90
   set lengthOUTPUTprompts [expr {int(0.78 * $lengthOUTPUTprompts)}]
   set lengthAUDIOprompts  [expr {int($widthFACTOR * $lengthAUDIOprompts)}]
   set lengthOTHERprompts  [expr {int($widthFACTOR * $lengthOTHERprompts)}]

   ## FOR TESTING:
   #   puts "lengthOUTPUTprompts: $lengthOUTPUTprompts"
   #   puts "lengthAUDIOprompts:  $lengthAUDIOprompts"
   #   puts "lengthOTHERprompts:  $lengthOTHERprompts"

}
## END OF PROC 'set_width_of_labels'


##+#####################################################################
## PROC 'pack_more_outparms_frame'
##+#####################################################################
## PURPOSE: To show the 'audio' and 'other' frames of
##          the GUI if the 'MoreAudioOutParms' checkbutton is ON.
##
##          Otherwise, 'forget' the frame containing the
##          'audio' and 'other' frames.
##
## CALLED:  button1-release on the 'MoreAudioOutParms' checkbutton on the GUI
##          AND, possibly, in the Additional GUI Initialization' section
##          at the bottom of this script.
##+#####################################################################

proc pack_more_outparms_frame {} {

   ## FOR TESTING: (to dummy out this proc)
   #  return

   global SHOWoutparms0or1

   ## Allow the window to resize in both x and y directions.
   wm resizable . 1 1

   if {$SHOWoutparms0or1 == 1} {

      pack .fRright.fRaudparms \
         -side top \
         -anchor nw \
         -fill x \
         -expand 0

   } else {
      pack forget .fRright.fRaudparms
   }
   ## END OF   if {$SHOWoutparms0or1 == 1}

   ## Reset the window to resize in x-direction, but not y.
   wm resizable . 1 0

}
## END OF PROC 'pack_more_outparms_frame'


##+########################################################################
## PROC 'help_for_player'
##+########################################################################
## PURPOSE: Provide help for the player in var ENTRYplayer.
##
## CALLED BY: the 'Help' button in the 'fRplayer' frame.
###########################################################################

proc help_for_player { } {

   global ENTRYplayer HELPffplay HELPmplayer HELPgmplayer HELPtotem HELPvlc 

   if {"$ENTRYplayer" == "xffplay"} {
      popup_msgVarWithScroll .topHELPffplay "$HELPffplay"
   }

   if {"$ENTRYplayer" == "xmplayer"} {
      popup_msgVarWithScroll .topHELPmplayer "$HELPmplayer"
   }

   if {"$ENTRYplayer" == "gmplayer"} {
      popup_msgVarWithScroll .topHELPgmplayer "$HELPgmplayer"
   }

   if {"$ENTRYplayer" == "totem"} {
      popup_msgVarWithScroll .topHELPtotem "$HELPtotem"
   }

   if {"$ENTRYplayer" == "vlc"} {
      popup_msgVarWithScroll .topHELPvlc "$HELPvlc"
   }

}
## END OF PROC 'help_for_player'

##+########################################################################
## 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 } {

   ## global fontTEMP_varwidth #; 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 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 10 \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 \
         -yscrollcommand "$toplevName.scrolly set" \
         -xscrollcommand "$toplevName.scrollx set"

      ##  -height $VARheight \

      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'


##+########################
## END of PROC definitions.
##+########################


##+########################
## Set HELPffplay var.
##+########################

set HELPffplay \
"'ffplay' HELP:
**************

'ffplay' is a *light-weight* player of media files (movies and audio-only files).

'ffplay' is usually packaged with the 'ffmpeg' command. Since 'ffplay' comes from
the maintainers of the 'ffmpeg' command, 'ffplay' is likely to have the most
success (among media players) in playing the output files from 'ffmpeg'.

'ffplay' does not have any control options in a GUI surrounding a 'playback window'.
But there a few keyboard and mouse controls that take effect in the 'playback window'.

For audio-only files, 'ffplay' shows the wave form of the audio channel(s) in the
'playback' window.

Observe the elapsed-time-display in the 'xterm' window that is running the
'ffplay' program.

Here are a set of control options may be the most useful for playing audio-only files,
especially for getting the start and end times for a 'CLIP' operation.

   q or ESC       Quit.
   p or SPC       Pause.
   mouse click    Seek to percentage in file corresponding to fraction of width.
   left/right     Seek backward/forward 10 seconds.
   down/up        Seek backward/forward 1 minute.

Other 'ffplay' keyboard controls:

   w              Show audio waves.
   a              Cycle audio channel.
   v              Cycle video channel.    (Not be useful for audio-only files.)
   t              Cycle subtitle channel. (Not be useful for audio-only files.)
   f              Toggle full screen. (May not be useful for audio-only files.)
"

##+########################
## Set HELPmplayer var.
##+########################

set HELPmplayer \
"'mplayer' HELP:
***************

'mplayer' is a *medium-weight* player of media files (movies and audio-only files).
It does not have a GUI control window. The maintainers of 'mplayer' leave
the making of GUI interfaces to 'mplayer' to others --- with one exception ---
the 'gmplayer' program that they offer.

Some other GUI interfaces to 'mplayer' include 'gnome-mplayer' (quite buggy) and
'smplayer'.

Since the maintainers of 'mplayer' have a working relationship with the
the maintainers of the 'ffmpeg' command, 'mplayer' is likely to have good
success (among media players) in playing most of the output files from 'ffmpeg'.

Unfortunately, for audio-only files, 'mplayer' does not seem to provide
a 'display' window in which the user can cause the audio file to
step-back or rewind or pause or fast-forward --- operations that would be
helpful to find start and end times for a CLIP operation.

*IF* we ever find a way to cause the 'mplayer' 'display' window to appear
for an audio-only file, then the following controls might be useful.
(For now, use the time-display in the 'xterm' window that is running the
'mplayer' program.)

When the 'mplayer' 'display window' comes up, 'mplayer' does not have any
control options --- such as a toolbar and pull-down menus of control options ---
in a GUI surrounding the 'display window'.  But there a few keyboard controls
that take effect in the playback 'display window'.

Here are a set of control options may be the most useful for playing audio-only files,
especially for getting the start and end times for a 'CLIP' operation --- if we can
find a way to display the 'display' window for an audio-only file.

  q or ESC         Stop playing and quit.
  p or SPACE       Pause (pressing again unpauses).
  <- and ->        Seek backward/forward 10 seconds.
  up and down      Seek forward/backward 1 minute.
  pgup and pgdown  Seek forward/backward 10 minutes.
  .                Step  forward.  Pressing once will pause movie,
                   every consecutive press will play one frame and
                   then go into pause mode again (any other key unpauses).
  \[ and \]        Decrease/increase current playback speed by 10%.
  \{ and \}        Halve/double current playback speed.
  backspace        Reset playback speed to normal.

Other 'mplayer' keyboard controls:

  f                Toggle fullscreen.
  + and -          Adjust audio delay by +/- 0.1 seconds.
  / and *          Decrease/increase volume.
  9 and 0          Decrease/increase volume.
  ( and )          Adjust audio balance in favor of left/right channel.
  m                Mute sound.
  I                Show filename on the OSD (On Screen Display).

You can consult the 'man mplayer' info for more information
on controlling 'mplayer' as a media file is played.

The 'man' page for the 'mplayer' command is more than 8,000 lines
long (100-plus pages). There are an over-powering number of
command-line options for 'mplayer'. Many of these options can be passed
to an 'mplayer' program running in '-slave' mode. Thus one can build
GUI interfaces to the 'mplayer' program.
"

##+########################
## Set HELPgmplayer var.
##+########################

set HELPgmplayer \
"'gmplayer' HELP:
****************

The 'gmplayer' program offers a small, minimal GUI ---
with buttons to control things like
   - pause/play
   - return-to-start
   - advance/retreat
and two slider bars to
   - set audio volume
   - indicate time range and display current play position.

The latter display (of current play position, in hours-minutes-seconds)
is useful in getting the start and end times for a 'CLIP' operation of
an audio-only file.

The maintainers of the 'mplayer' command provide the 'gmplayer' program
as an example of how to provide a GUI interface to the 'mplayer' command.

Since the maintainers of 'mplayer' have a working relationship with the
the maintainers of the 'ffmpeg' command, 'gmplayer' is likely to have good
success (among media players) in playing most of the output files from 'ffmpeg'.

As an alternative (and augmentation) to its GUI controls, 'gmplayer' provides
the following keyboard control options. The first group may be the most useful
for playing audio-only files, especially for getting the start and end times
for a 'CLIP' operation from the input file.

  q or ESC         stop playing and quit program
  p or SPACE       pause media play (press any key to continue)
  <-  or  ->       seek backward/forward 10 seconds
  down or up       seek backward/forward  1 minute
  pgdown or pgup   seek backward/forward 10 minutes
  o                cycle OSD mode:  none / seekbar / seekbar + timer
                   (OSD = OnScreenDisplay info)

The following may be useful for the CHG-VOLUME operation of this GUI ---
to get an idea of the factor by which to increase or decrease the volume
of the input file:

  * or /           increase or decrease PCM (audio) volume

Other 'gmplayer' keyboard controls:

  + or -           adjust audio delay by +/- 0.1 second
  x or z           adjust subtitle delay by +/- 0.1 second
  r or t           adjust subtitle position up/down, also see -vf expand
"

##+########################
## Set HELPtotem var.
##+########################

set HELPtotem \
"'totem' HELP:
*************

'totem' has a pretty elaborate GUI for controlling the display of a
media file (movie or audio-only). For audio-only files, it displays
an 'audio visualization' display that displays 'abstract' image
animations that change in time.

Unfortunately, 'totem' is based on the 'Gstreamer' media decoding library
which sometimes does not successfully playback media files created by
the 'ffmpeg' command. For example, 'totem' may play back the audio of
an ffmpeg-created movie file but not its video.

In addition to its GUI controls (in pull-down menus in its toolbar),
'totem' has a rather plentiful set of keyboard control options.

Here are a set of control options that may be the most useful for playing
audio-only files, especially for getting the start and end times for
a 'CLIP' operation from the input file.

  q                    Quit.
  p                    Toggle between play and pause.
  h                    Toggle display of on-screen controls.
  Left-arrow           Skip back 15 seconds
  Shift+Left-arrow     Skip back 5 seconds
  Ctrl+Left-arrow      Skip back 3 minutes
  Right-arrow          Skip forward 60 seconds
  Shift+Right-arrow    Skip forward 15 seconds
  Ctrl+Right arrow     Skip forward 10 minutes

The following may be useful for the CHG-VOLUME operation of this GUI,
when used on the input file:

  Up-arrow             Increase volume by 8%
  Down-arrow           Decrease volume by 8%

Other 'totem' keyboard controls:

  f                    Toggle full screen.
  Esc                  Exit full screen mode.
  0                    Resize window to 50% original size.
  1                    Resize window to 100% original size.
  2                    Resize window to 200% original size.
  r                    Zoom in the video.
  t                    Zoom out the video.

"

##+########################
## Set HELPvlc var.
##+########################

set HELPvlc \
"'vlc' HELP:
***********

'vlc' has a rather elaborate GUI. You can determine most of its
keyboard shortcuts from the items on the toolbar drop-down menus.

Unfortunately, the maintainers of 'vlc' do not work closely with the
maintainers of 'ffmpeg' --- and they may use different decoders/libraries from 
those used by the 'ffmpeg' group. As a consequence, 'vlc' sometimes does not
successfully playback media files created by the 'ffmpeg' command.

Try a different audio player when that happens.

The 'man' page for the 'vlc' command is more than 4,500 lines
long (50-plus pages). There are an over-powering number of
command-line options for 'vlc'.
"


##+########################
## Set HELPtext var.
##+########################

set HELPtext \
"** HELP for this 'Audio-File Edit Utility' (a front-end for 'ffmpeg') **

This utility provides a GUI for 'semi-interactively' editing an audio file
--- for example, to extract a 'clip' from the audio file or to change the
'overall' volume of the audio channel(s) in the file.

The GUI provides parameters to the 'ffmpeg' program. The 'ffmpeg' program
is used to make a NEW audio file from the selected input audio file.
The input audio file is not altered.


*********************
Audio File Parameters (in particular, for the output audio file)
*********************

The 'ffmpeg' command is intended to handle MOVIE files and, as a 
'side effect', 'ffmpeg' handles AUDIO files as well.

Note that a movie file is composed of 3 formats:

- the container format       (Examples: matroska, mpeg4, mpeg, avi, webm)
- the video 'codec' format   (Examples: H.264, Mpeg4, Mpeg2, xvid, vp8)
- the audio 'codec' format   (Examples: mp3, pcm, aac, vorbis)

'codec' is an abbreviation for (en)COde-and-DECode.

For AUDIO-ONLY files, it is typical that there is no container
format involved (and certainly no video involved) --- just audio
codecs (decoders and encoders).

This GUI utility (via 'ffmpeg') does 'encoding' to make the output
audio file, and it does 'decoding' to read the input audio file.

'ffmpeg' does a quite good job of detecting the format of the input
audio file and automatically choosing the appropriate decoder.
('ffmpeg' may be helped if you use an appropriate 'extension' on
the name of the input file --- such as '.mp3', '.wav', etc.)

By default, the GUI for this utility is set to the 'MP3' audio
encoding format for the output audio file.

This default is based on the fact that probably most people will
be either
   - editing an MP3 file to make another MP3 file
or
   - converting a larger file (like WAV or FLAC) to a more compact MP3 file.

Audio parameters (such as number-of-audio-channels and sampling-rate and
bit-rate) that are compatible with the audio 'encoding format' chosen
are provided on the GUI --- in the 'MoreAudioOutParms' part of the GUI.

The user can click on the 'MoreAudioOutParms' button to see a
stack of about 6 'frames' that contain widgets by which the user
can specify the audio encoding parameters ---
for making the output audio file. These widgets contain defaults
that are determined by the 'encoding format' that is selected.

The knowledgeable user (knowledgeable in the mysterious ways
of the 'ffmpeg' program) may wish to override some of the
audio encoding parameters --- so most of the parameters on
the GUI are changeable by the user.

Since the MP3 and Vorbis encoders support VBR (Variable Bit Rate)
encoding as well as CBR (Constant Bit Rate) encoding, and since
VBR is recommended at many web sites (including ffmpeg.org),
we default the MP3 and Vorbis encoding parameters to use
the '-aq' (audio quality) parameter for VBR, rather than the
'-ab' (audio bit rate) parameter for CBR.

When the user has the parameters ready (for simplicity, the user
may simply take the defaults), a click on the 'ExecOption' button
starts up the 'ffmpeg' command.


****************************
The Basic Operating Sequence:
****************************

0) The user enters the name of an audio file at the 'input' filename
   prompt. The 'Browse..' button can be used to enter a valid
   filename in that entry field.

1) The user chooses an exec-option (such as CLIP or CONVERT) from the
   listbox on the left of the GUI.

   When the user clicks on a line of the listbox, an 'execOpts frame' in
   the lower part of the GUI provides input widgets (labels, entry fields,
   radiobuttons, whatever) corresponding the the operation selected.
   For example:

      -  If CLIP is selected, entry fields are provided to enter
         a start-time and a duration-time for the clipping operation.

2) The user can change the 'encoding' format for the output audio file
   by clicking on one of the audio 'encoding format' radiobuttons.

   The GUI is defaulted to the MP3 encoding format. (But the user could
   edit this script to change the default.)

   When you choose an audio 'encoding format' type, various audio-and-other
   encoding parameters are set to be compatible with that encoding
   format.

   As described above, if you want to change the audio encoding parameters
   for a chosen audio encoding format, you can click on the
   'MoreAudioOutParms' button and change the parameters as you wish.

3) After specifying the 'encoding' format (and audio-encoding parameters)
   for the output audio file --- and after entering the parameters
   for the chosen Audio-Exec-Option --- click on the 'ExecOption'
   button to startup the 'ffmpeg' program.

   For most operation options (the PROPERTIES options are an exception),
   this utility runs 'ffmpeg' in an 'xterm' window. Startup and coding
   messages from 'ffmpeg' can be seen in that 'xterm' window. You may
   minimize the 'xterm' window while processing, if you do not want
   to monitor the processing messages. When processing is done, the
   'xterm' window does not close, so that you can examine messages.

4) After the output audio file has been created, click on the 'PlayOutAudio'
   button to play the new audio file. You can change the 'player'
   program that is used by changing the entry at the
   'Player for audio in/out files:' prompt.


NOTE1:
If you take the initial defaults for everything, the operation can be
as simple as:
   0) Select an input audio file.
   1) Select an operation from the listbox.
   2) Provide parameters for the operation, in the 'ExecOpts' sub-frames.
   3) Click on the 'ExecOption' button.
   4) After the output audio file has been created, click on the
      'PlayOutAudio' button.

NOTE2:
The 'PlayInAudio' button is useful for operations such as the CLIP
option. You can play the audio in an audio-player like a GUI version
of 'mplayer' to determine the start-time and duration for the
'clip' that you want to extract from the audio file.


********************
The Execution Window (a.k.a. the 'ffmpeg' window or the 'xterm' window)
********************

For most operations, this utility runs the 'ffmpeg' command in a popup
'xterm' window, so that the user can see messages coming from the
media(audio/video)-making program, ffmpeg.

NOTE: If you want to hide the 'ffmpeg' window, MINIMIZE the 'ffmpeg'
window; do NOT close it. If you close it, the 'ffmpeg' program is
killed.

It would not really hurt if the user changed some audio encoding
parameters and the 'ffmpeg' program failed. The 'ffmpeg' window will
show error messages that may be helpful in determining a solution.

The 'ffmpeg' window is 'held open' --- even when the 'ffmpeg'
program ends (normally or abnormally) --- so that the user can
examine messages from the program. When done with the messages,
simply close the 'ffmpeg' window.


*************************
Playing the Audio File(s):
*************************

You can specify a 'player' program for the input and output audio files
in an entry field near the top of the GUI. After it appears that an audio
file has been created (with the output filename specified in a filename
entry field on the GUI), you can try playing the output audio file by
clicking on the 'PlayOutAudio' button.

WARNING:
I have encountered MOVIES that would NOT play with 'vlc' or 'totem',
but they WOULD play with 'ffplay' and 'mplayer' and 'gmplayer'.
The same may be true of AUDIO files.

So if 'PlayOutAudio' does not work on an output file (for example,
the player window appears but does not play any audio), try another player.


*****************
Execution Options:
*****************

This GUI utility makes it easy to use the 'ffmpeg' program
to do some 'non-interactive' audio file editing, including
operations such as
   - extracting a 'clip' from an audio file
   - changing the audio volume of an audio file
   - showing the properties of the input audio file
   - showing the properties of the output audio file
   - converting an audio file to a different encoding format
and more-to-come:
   - adding an audio channel to an audio file
   - extracting a channel of the audio file, into an 'mp3' file, say
   - removing an audio channel from an audio file
   - and maybe a few more audio editing deeds that can be done
     'semi-interactively'.
 
Some execution options that have not been implemented yet
may be seen in the listbox, preceded with the '#' character.

Comments in the code of the Tk script that makes this GUI utility describe how
each execution-option can be implemented by providing a pair of 'procs'.


***********************************************
SETTING UP THIS UTILITY FOR EASY ICON-CLICK USE:
***********************************************

The set of files for this utility consists of a Tk script
and 3 shell scripts (one to perform the PROPERTIES options
and two as 'wrappers' for the 'ffplay' and 'mplayer' commands):

- the main Tk script 'audioClipChgVolumeConvertEtc_ffmpeg_FrontEnd.tk'

- the auxiliary shell script 'audioFilePROPERTIES_ffmpeg-i.sh'

- the auxiliary shell script 'ffplay_inXterm.sh'

- the auxiliary shell script 'mplayer_inXterm.sh'

Those 4 scripts could be put in a sub-directory of the
user's home directory --- such as \$HOME/apps/tkEditAudio.

Then the user can use his/her desktop system (such as Gnome or KDE)
to set up the main Tk script as an icon on the desktop (or in a
desktop 'panel').

Then, whenever the user wants to edit an audio file,
the user can click on the icon to startup the Tk script.


********************************
Changing the Defaults on the GUI:
********************************

The audio-and-other default parameter values that appear in the GUI
are set in a 'proc' named 'set_defaults_for_encoding'. You can find
that proc in this Tk script and change the defaults as you wish.

If the radiobuttons do not include an audio output format that you
would prefer to use, you could change one of the radiobuttons (or add
a new radiobutton). You could search the code for a string like 'vorbis'
to find the other places you will need to make changes --- to
bindings, procs, etc.

The initial, default input directory for the input audio file and the
initial, default output directory for the output audio file are
set near the bottom of the script by the statements:
   set inDIR \"\$env(HOME)\"
   set outDIR \"/tmp\"
You can edit the Tk script to change those locations.

The '/tmp' directory is recommended for the output files because
audio files are generally fairly large files and:

1) If you decided to not use the output file and you did not delete it
   (say you forget about the file), the operating system will
   automatically delete it for you.

2) You may do several runs before you get the output that you wanted.
   When you get a file you want to keep, you can simply drag/move the
   file to a desired directory and give it a more meaningful name.
   And if you do not get a file you want to keep, you can just leave
   the last attempt in '/tmp' and it will be deleted.


**************************************
Sample output from an 'ffmpeg' command  (from a 'clip' edit run)
**************************************

If a user is having problems in getting a successful output audio file, the following
messages output from a successful 'ffmpeg' audio-edit run (a CLIP run) may be helpful.

Some 'ffmpeg' build info is at the top of the messages from 'ffmpeg' ---
up to the 'Input #0' line.

The lines between the 'Input #0' line and the 'Press ' line are the initial
messages that 'ffmpeg' puts out before starting the encoding of the output file.

The line after the 'size=' line is a 'summary' line that was output at
the end of the edit run. 

The string 'time=16.12' in the 'size=' line indicates that the output file
that was created is about 16 seconds in duration. (For this 35 second input file,
I specified a start-time of 00:00:05 and a duration of 00:00:16.)

The string 'bitrate= 106.9kbits/s' in the 'size=' line indicates that this variable-bit-rate
mp3 output file was created with an average bit rate of about 107 kbits/sec.

The string 'size=     210kB' in the 'size=' line corresponds to the fact that
the output file '/tmp/blaze_output_audio.mp3' was indeed 210 KiloBytes in size.
The 35-second input file was 543 KiloBytes in size.

-----------------------------------------------------------------------------------------------

FFmpeg version SVN-r19352-4:0.5+svn20090706-2ubuntu2.3, Copyright (c) 2000-2009 Fabrice Bellard, et al.
  configuration: --extra-version=4:0.5+svn20090706-2ubuntu2.3 --prefix=/usr --enable-avfilter
  --enable-avfilter-lavf --enable-vdpau --enable-bzlib --enable-libgsm --enable-libschroedinger
  --enable-libspeex --enable-libtheora --enable-libvorbis --enable-pthreads --enable-zlib
  --disable-stripping --disable-vhook --enable-gpl --enable-postproc --enable-swscale
  --enable-x11grab --enable-libdc1394 --extra-cflags=-I/build/buildd/ffmpeg-0.5+svn20090706/debian/include
  --enable-shared --disable-static
  libavutil     49.15. 0 / 49.15. 0
  libavcodec    52.20. 0 / 52.20. 0
  libavformat   52.31. 0 / 52.31. 0
  libavdevice   52. 1. 0 / 52. 1. 0
  libavfilter    0. 4. 0 /  0. 4. 0
  libswscale     0. 7. 1 /  0. 7. 1
  libpostproc   51. 2. 0 / 51. 2. 0
  built on Mar 31 2011 18:50:18, gcc: 4.4.1
Input #0, mp3, from '/home/blaze/TESTfilesAUDIO/test_35sec_44100Hz_128kbs_mono_543KB.mp3':
  Duration: 00:00:34.74, start: 0.000000, bitrate: 128 kb/s
    Stream #0.0: Audio: mp3, 44100 Hz, mono, s16, 128 kb/s
File '/tmp/blaze_output_audio.mp3' already exists. Overwrite ? \[y/N\] y
Output #0, mp3, to '/tmp/blaze_output_audio.mp3':
    Stream #0.0: Audio: libmp3lame, 44100 Hz, stereo, s16, 64 kb/s
Stream mapping:
  Stream #0.0 -> #0.0
Press \[q\] to stop encoding
size=     210kB time=16.12 bitrate= 106.9kbits/s    
video:0kB audio:210kB global headers:0kB muxing overhead 0.014865%

-----------------------------------------------------------------------------------------------

A 'PROPERTIES-OUT' query on the output file showed:

Input #0, mp3, from '/tmp/blaze_output_audio.mp3':
  Duration: 00:00:21.53, start: 0.000000, bitrate: 80 kb/s
    Stream #0.0: Audio: mp3, 44100 Hz, stereo, s16, 80 kb/s

while a 'PROPERTIES-IN' query on the input file showed:

Input #0, mp3, from '/home/blaze/TESTfilesAUDIO/test_35sec_44100Hz_128kbs_mono_543KB.mp3':
  Duration: 00:00:34.74, start: 0.000000, bitrate: 128 kb/s
    Stream #0.0: Audio: mp3, 44100 Hz, mono, s16, 128 kb/s

So the file was 'changed' from 'mono' (1 channel) to 'stereo' (2 channels)
--- as the default GUI settings requested.

Although the 'ffmpeg -i' command of the 'PROPERTIES-OUT' query shows 
'Duration: 00:00:21.53', on taking the output file into Audacity and
playing it, it turns out the audio lasts 16 seconds, as requested.

Reference: https://trac.ffmpeg.org/ticket/1645 - 'Duration calculation error'
\"...everything magically works when you use both -ss before and after -i option.\"

On putting the '-ss' parameter BOTH before and after the '-i' option,
this 'duration calculation error' was indeed fixed.

This information is put here to give a concrete example of how tricky
it is to get the formulation of the parameters to 'ffmpeg' just right.
There may be other 'glitches' like this still lurking in this GUI utility.

In fact, there are other cases in which people have found 'ffmpeg' to
set the duration 'meta-data' incorrectly:
http://xinabox.blogspot.com/2013/03/incorrect-duration-converting-wavs-to.html
This person ended up using the 'lame' command instead of 'ffmpeg' --- to
convert 'wav' files to 'mp3' files.

By the way,
the '-ss' parameter 'fix' resulted in some ffmpeg processing-message lines
appearing --- between the 'Press ' line and the size= ' lines above:

\[mp3 @ 0xa04a980\]mdb:466, lastbuf:0 skipping granule 0
\[mp3 @ 0xa04a980\]mdb:466, lastbuf:0 skipping granule 1
\[mp3 @ 0xa04a980\]mdb:456, lastbuf:397 skipping granule 0


******************
More 'ffmpeg' info
******************

For more information on 'ffmpeg', use the commands 'man ffmpeg' and 'ffmpeg -h'.
To see the supported input and output formats, use 'ffmpeg -formats'.
The main web site is at ffmpeg.org.

The 'ffmpeg -h' help points out the basic format in using the many 'ffmpeg'
options:

 ffmpeg \[\[infile options\] -i infile\]... \{\[outfile options\] outfile\}...

Even with this guideline, it can be quite challenging to formulate a non-trivial
'ffmpeg' command in such a way as to avoid terminating errors.

The output from 'ffmpeg -formats' can be rather overpowering. It is more than
400 lines --- with a lot of video and image formats in addition to audio formats
--- and no separation of audio and video codecs --- and no clear designation
of MOVIE 'container' formats. So I provide the following list of audio decoding
and encoding formats --- ones that are typically useful in making audio files.

In the following, 'D' indicates that 'ffmpeg' will decode the format and
'E' indicates that 'ffmpeg' will encode the format. (This utility is
concerned with 'E', encoding of the output file --- as well as 'D',
decoding the input audio file.)

The 'A' in the following list stands for Audio.

*****************
SOME AUDIO CODECS:  (encoders and/or decoders --- encoders first)
*****************

  EA    libfaac         libfaac AAC (Advanced Audio Codec)
 DEA    flac            FLAC (Free Lossless Audio Codec)
  EA    libmp3lame      libmp3lame MP3 (MPEG audio layer 3)
 DEA    mp2             MP2 (MPEG audio layer 2)
 DEA    pcm_s16le       PCM signed 16-bit little-endian
 DEA    vorbis          Vorbis
  EA    libvorbis       libvorbis Vorbis

 D A    libfaad         libfaad AAC (Advanced Audio Codec)
 D A    mp3             MP3 (MPEG audio layer 3)
 D A    mp1             MP1 (MPEG audio layer 1)

---

COMMENTS:

For the MP3 and AAC formats, 'ffmpeg' uses a decoder separate from
the encoder.

             Decoder       Encoder
             ------------  ---------------------

For MP3:     mp3           libmp3lame

For AAC:     libfaad       libfaac

For Vorbis:  vorbis        vorbis or libvorbis

---

FAAC = Freeware Advanced Audio Coder

There seem to be two Vorbis encoders: 'vorbis' and 'libvorbis'.
See comments on these two encoders at
   http://www.linuxquestions.org/questions/linux-software-2/ffmpeg-vorbis-vs-libvorbis-782346/
   http://ffmpeg-users.933282.n4.nabble.com/vorbis-vs-libvorbis-vs-oggenc-td1458244.html
Some people recommend 'libvorbis' even though it may be slower.
In fact, 'libvorbis' is recommended at the 'ffmpeg.org' web site.

FLAC and MP2 seem to have a single decoder-encoder.

---

For some discussion of VBR (variable bit rate) versus CBR (constant bit rate),
especially for MP3 files (and for Vorbis files), see
   http://ffmpeg.gusari.org/viewtopic.php?f=25&t=41
   https://trac.ffmpeg.org/wiki/Encode/MP3
   https://trac.ffmpeg.org/wiki/TheoraVorbisEncodingGuide
   https://trac.ffmpeg.org/wiki/GuidelinesHighQualityAudio
   https://www.ffmpeg.org/ffmpeg-codecs.html#libmp3lame-1
   http://unix.stackexchange.com/questions/7284/
          (ffmpeg-and-libmp3lame-produces-bad-audio-quality)

Note that there is at least one fork of 'ffmpeg', as indicated at these URL's:
   http://ffmpeg.gusari.org/viewtopic.php?f=11&t=1298
   http://stackoverflow.com/questions/13247038/
        (vbr-header-created-for-cbr-encoded-mp3-when-using-ffmpeg-with-lame-codec)
   http://stackoverflow.com/questions/9477115/
        (who-can-tell-me-the-difference-and-relation-between-ffmpeg-libav-and-avconv?lq=1)
   http://blog.pkh.me/p/13-the-ffmpeg-libav-situation.html

***********
PCM formats:
***********

There are many PCM formats --- signed/unsigned, big/little endian, floating,
8/16/24/32/64 bit. But the 'pcm_s16le' format is probably the most common.

PCM = Pulse Code Modulation   (It is used for media CD's, DVD's, and BlueRay.)

The many PCM formats that 'ffmpeg' supports can be seen in lists below.


*******************************
MANY MORE ffmpeg AUDIO 'CODECS':
*******************************

'ffmpeg -formats' shows MANY MORE audio decoders and encoders than the
'popular' ones listed above.

To separate the 'ffmpeg' audio decoders from the encoders (in other words,
to distinguish which audio-formats 'ffmpeg' will de-code/read from which audio
formats 'ffmpeg' will encode/write), I ran the two commands:

   - ffmpeg -formats | egrep 'DEA|D A'  (to get the decoders/readers)
and
   - ffmpeg -formats | egrep 'DEA| EA'  (to get the encoders/writers)

---------------------------------
COMMAND
   ffmpeg -formats | egrep 'DEA|D A'
GAVE DE-CODERS:

 D A    8svx_exp        8SVX exponential
 D A    8svx_fib        8SVX fibonacci
 D A    aac             Advanced Audio Coding
 DEA    ac3             ATSC A/52A (AC-3)
 D A    adpcm_4xm       ADPCM 4X Movie
 DEA    adpcm_adx       SEGA CRI ADX ADPCM
 D A    adpcm_ct        ADPCM Creative Technology
 D A    adpcm_ea        ADPCM Electronic Arts
 D A    adpcm_ea_maxis_xa ADPCM Electronic Arts Maxis CDROM XA
 D A    adpcm_ea_r1     ADPCM Electronic Arts R1
 D A    adpcm_ea_r2     ADPCM Electronic Arts R2
 D A    adpcm_ea_r3     ADPCM Electronic Arts R3
 D A    adpcm_ea_xas    ADPCM Electronic Arts XAS
 D A    adpcm_ima_amv   ADPCM IMA AMV
 D A    adpcm_ima_dk3   ADPCM IMA Duck DK3
 D A    adpcm_ima_dk4   ADPCM IMA Duck DK4
 D A    adpcm_ima_ea_eacs ADPCM IMA Electronic Arts EACS
 D A    adpcm_ima_ea_sead ADPCM IMA Electronic Arts SEAD
 D A    adpcm_ima_iss   ADPCM IMA Funcom ISS
 DEA    adpcm_ima_qt    ADPCM IMA QuickTime
 D A    adpcm_ima_smjpeg ADPCM IMA Loki SDL MJPEG
 DEA    adpcm_ima_wav   ADPCM IMA WAV
 D A    adpcm_ima_ws    ADPCM IMA Westwood
 DEA    adpcm_ms        ADPCM Microsoft
 D A    adpcm_sbpro_2   ADPCM Sound Blaster Pro 2-bit
 D A    adpcm_sbpro_3   ADPCM Sound Blaster Pro 2.6-bit
 D A    adpcm_sbpro_4   ADPCM Sound Blaster Pro 4-bit
 DEA    adpcm_swf       ADPCM Shockwave Flash
 D A    adpcm_thp       ADPCM Nintendo Gamecube THP
 D A    adpcm_xa        ADPCM CDROM XA
 DEA    adpcm_yamaha    ADPCM Yamaha
 DEA    alac            ALAC (Apple Lossless Audio Codec)
 D A    ape             Monkey's Audio
 D A    atrac3          Atrac 3 (Adaptive TRansform Acoustic Coding 3)
 D A    cook            COOK
 D A    dca             DCA (DTS Coherent Acoustics)
 D A    dsicinaudio     Delphine Software International CIN audio
 D A    eac3            ATSC A/52B (AC-3, E-AC-3)
 DEA    flac            FLAC (Free Lossless Audio Codec)
 DEA    g726            G.726 ADPCM
 D A    imc             IMC (Intel Music Coder)
 D A    interplay_dpcm  DPCM Interplay
 DEA    libamr_nb       libamr-nb Adaptive Multi-Rate (AMR) Narrow-Band
 DEA    libamr_wb       libamr-wb Adaptive Multi-Rate (AMR) Wide-Band
 D A    libfaad         libfaad AAC (Advanced Audio Codec)
 DEA    libgsm          libgsm GSM
 DEA    libgsm_ms       libgsm GSM Microsoft variant
 D A    libspeex        libspeex Speex
 D A    mace3           MACE (Macintosh Audio Compression/Expansion) 3:1
 D A    mace6           MACE (Macintosh Audio Compression/Expansion) 6:1
 D A    mlp             MLP (Meridian Lossless Packing)/TrueHD
 D A    mp1             MP1 (MPEG audio layer 1)
 DEA    mp2             MP2 (MPEG audio layer 2)
 D A    mp3             MP3 (MPEG audio layer 3)
 D A    mp3adu          ADU (Application Data Unit) MP3 (MPEG audio layer 3)
 D A    mp3on4          MP3onMP4
 D A    mpc7            Musepack SV7
 D A    mpc8            Musepack SV8
 DEA    nellymoser      Nellymoser Asao
 DEA    pcm_alaw        PCM A-law
 D A    pcm_dvd         PCM signed 20|24-bit big-endian
 DEA    pcm_f32be       PCM 32-bit floating point big-endian
 DEA    pcm_f32le       PCM 32-bit floating point little-endian
 DEA    pcm_f64be       PCM 64-bit floating point big-endian
 DEA    pcm_f64le       PCM 64-bit floating point little-endian
 DEA    pcm_mulaw       PCM mu-law
 DEA    pcm_s16be       PCM signed 16-bit big-endian
 DEA    pcm_s16le       PCM signed 16-bit little-endian
 D A    pcm_s16le_planar PCM 16-bit little-endian planar
 DEA    pcm_s24be       PCM signed 24-bit big-endian
 DEA    pcm_s24daud     PCM D-Cinema audio signed 24-bit
 DEA    pcm_s24le       PCM signed 24-bit little-endian
 DEA    pcm_s32be       PCM signed 32-bit big-endian
 DEA    pcm_s32le       PCM signed 32-bit little-endian
 DEA    pcm_s8          PCM signed 8-bit
 DEA    pcm_u16be       PCM unsigned 16-bit big-endian
 DEA    pcm_u16le       PCM unsigned 16-bit little-endian
 DEA    pcm_u24be       PCM unsigned 24-bit big-endian
 DEA    pcm_u24le       PCM unsigned 24-bit little-endian
 DEA    pcm_u32be       PCM unsigned 32-bit big-endian
 DEA    pcm_u32le       PCM unsigned 32-bit little-endian
 DEA    pcm_u8          PCM unsigned 8-bit
 DEA    pcm_zork        PCM Zork
 D A    qcelp           QCELP / PureVoice
 D A    qdm2            QDesign Music Codec 2
 D A    real_144        RealAudio 1.0 (14.4K)
 D A    real_288        RealAudio 2.0 (28.8K)
 DEA    roq_dpcm        id RoQ DPCM
 D A    shorten         Shorten
 D A    smackaud        Smacker audio
 D A    sol_dpcm        DPCM Sol
 DEA    sonic           Sonic
 D A    truespeech      DSP Group TrueSpeech
 D A    tta             True Audio (TTA)
 D A    vmdaudio        Sierra VMD audio
 DEA    vorbis          Vorbis
 D A    wavpack         WavPack
 DEA    wmav1           Windows Media Audio 1
 DEA    wmav2           Windows Media Audio 2
 D A    ws_snd1         Westwood Audio (SND1)
 D A    xan_dpcm        DPCM Xan

---------------------------------
COMMAND
   ffmpeg -formats | egrep 'DEA| EA'
GAVE EN-CODERS:

 DEA    ac3             ATSC A/52A (AC-3)
 DEA    adpcm_adx       SEGA CRI ADX ADPCM
 DEA    adpcm_ima_qt    ADPCM IMA QuickTime
 DEA    adpcm_ima_wav   ADPCM IMA WAV
 DEA    adpcm_ms        ADPCM Microsoft
 DEA    adpcm_swf       ADPCM Shockwave Flash
 DEA    adpcm_yamaha    ADPCM Yamaha
 DEA    alac            ALAC (Apple Lossless Audio Codec)
 DEA    flac            FLAC (Free Lossless Audio Codec)
 DEA    g726            G.726 ADPCM
 DEA    libamr_nb       libamr-nb Adaptive Multi-Rate (AMR) Narrow-Band
 DEA    libamr_wb       libamr-wb Adaptive Multi-Rate (AMR) Wide-Band
  EA    libfaac         libfaac AAC (Advanced Audio Codec)
 DEA    libgsm          libgsm GSM
 DEA    libgsm_ms       libgsm GSM Microsoft variant
  EA    libmp3lame      libmp3lame MP3 (MPEG audio layer 3)
  EA    libvorbis       libvorbis Vorbis
 DEA    mp2             MP2 (MPEG audio layer 2)
 DEA    nellymoser      Nellymoser Asao
 DEA    pcm_alaw        PCM A-law
 DEA    pcm_f32be       PCM 32-bit floating point big-endian
 DEA    pcm_f32le       PCM 32-bit floating point little-endian
 DEA    pcm_f64be       PCM 64-bit floating point big-endian
 DEA    pcm_f64le       PCM 64-bit floating point little-endian
 DEA    pcm_mulaw       PCM mu-law
 DEA    pcm_s16be       PCM signed 16-bit big-endian
 DEA    pcm_s16le       PCM signed 16-bit little-endian
 DEA    pcm_s24be       PCM signed 24-bit big-endian
 DEA    pcm_s24daud     PCM D-Cinema audio signed 24-bit
 DEA    pcm_s24le       PCM signed 24-bit little-endian
 DEA    pcm_s32be       PCM signed 32-bit big-endian
 DEA    pcm_s32le       PCM signed 32-bit little-endian
 DEA    pcm_s8          PCM signed 8-bit
 DEA    pcm_u16be       PCM unsigned 16-bit big-endian
 DEA    pcm_u16le       PCM unsigned 16-bit little-endian
 DEA    pcm_u24be       PCM unsigned 24-bit big-endian
 DEA    pcm_u24le       PCM unsigned 24-bit little-endian
 DEA    pcm_u32be       PCM unsigned 32-bit big-endian
 DEA    pcm_u32le       PCM unsigned 32-bit little-endian
 DEA    pcm_u8          PCM unsigned 8-bit
 DEA    pcm_zork        PCM Zork
 DEA    roq_dpcm        id RoQ DPCM
 DEA    sonic           Sonic
  EA    sonicls         Sonic lossless
 DEA    vorbis          Vorbis
 DEA    wmav1           Windows Media Audio 1
 DEA    wmav2           Windows Media Audio 2

You can see that 'ffmpeg' can decode more audio formats than it can encode.
This is not surprising.

NOTE: These results come from a 2009 version of 'ffmeg'.
A more recent version may provide a few more decoding or encoding formats.


************************************
Some Web References on Audio Formats:
************************************

http://en.wikipedia.org/wiki/Audio_file_format
http://en.wikipedia.org/wiki/Audio_codecs
http://en.wikipedia.org/wiki/Comparison_of_audio_formats
http://en.wikipedia.org/wiki/MP3
http://en.wikipedia.org/wiki/Vorbis
http://en.wikipedia.org/wiki/Ogg
http://en.wikipedia.org/wiki/Advanced_Audio_Coding
http://en.wikipedia.org/wiki/FLAC
http://en.wikipedia.org/wiki/Pulse-code_modulation
http://en.wikipedia.org/wiki/FFmpeg
http://hopewiki.socialhistoryportal.org/index.php/List_of_Audio_File_Formats
https://trac.ffmpeg.org/wiki/GuidelinesHighQualityAudio

http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=501521&av=724426
'How to convert between (almost) any audio formats in .NET' (slanted but informative)

https://trac.ffmpeg.org/wiki/Encode/MP3   (SEE info on Variable Bit Rate encoding)
https://trac.ffmpeg.org/wiki/TheoraVorbisEncodingGuide  (SEE info on VBR encoding)

Audio-overview links:
http://en.wikipedia.org/wiki/List_of_Linux_audio_software
http://en.wikipedia.org/wiki/List_of_free_software_for_audio


********************************************
Some Alternative Command-line Audio Encoders:
********************************************

Try 'man sox', 'man lame', 'man twolame', 'man oggenc'.

The 'sox' sound system has been used quite widely to remove quiet
sections from audio files, according to volume cut-off parameters
provided at the command line.

For 'fully interactive' audio editing, try 'audacity'.


*******************************************
Some Alternative Light-weight Audio Players:
*******************************************

Try 'man play' (of the 'sox' system), 'man splay', 'man decibel-audio-player',
'man potamus'.

These MAY play mp3 files with no command line parameters other than the filename.
However some of these seem to be quite 'buggy'.
"


##+######################################################
## ADDITIONAL GUI INITIALIZATION section.
##+######################################################

##+#############################################################
## Set an initial input directory for the INPUT audio file.
##+#############################################################

set inDIR "$env(HOME)"

##+#############################################################
## Set an initial full-name for the INPUT audio file.
##+#############################################################

set INfilename "$inDIR/input_audio.xyz"

##+#############################################################
## Set an initial output directory for the output audio file.
##+#############################################################

set outDIR "/tmp"

##+######################################################
## Use the variable of the 'encoding format' radiobuttons
## to set an initial choice of the encoding format.
##+######################################################

set ENCODERname "libmp3lame"
# set ENCODERname "libvorbis"
# set ENCODERname "libfaac"
# set ENCODERname "flac"
# set ENCODERname "mp2"
# set ENCODERname "pcm_s16le"

##+###########################################
## Set the GUI widgets according to an initial
## setting of the audio encoding format.
##+###########################################
## The initial setting of the 'player' program,
## in variable 'ENTRYplayer', is set in the
## proc 'set_defaults_for_encoding', according
## to the 'encoding' that the user chooses for
## the output file.
##+###########################################
 
set_defaults_for_encoding $ENCODERname

##+#############################################################
## Set the widths of the prompts (labels) on the left of the GUI
## --- in the 'output', 'audio', and 'other' sections.
##+#############################################################

set_width_of_labels

## For the 'output' section:

.fRright.fRoutfile.labelOUTFILE configure -width $lengthOUTPUTprompts
.fRright.fRplayer.labelPLAYER1  configure -width $lengthOUTPUTprompts

## For the 'audio' section:

.fRright.fRaudparms.fRacodec.labelACODEC1       configure -width $lengthAUDIOprompts
.fRright.fRaudparms.fRachannels.labelACHANNELS1 configure -width $lengthAUDIOprompts
.fRright.fRaudparms.fRasrate.labelASRATE1       configure -width $lengthAUDIOprompts
.fRright.fRaudparms.fRabrate.labelABRATE1       configure -width $lengthAUDIOprompts
.fRright.fRaudparms.fRaother.labelAOTHER        configure -width $lengthAUDIOprompts

## For the 'other' section:

.fRright.fRaudparms.fRthreads.labelTHREADS1 configure -width $lengthOTHERprompts

##+#############################################################
## Initialize the ExecOption variable.
##+#############################################################

set VARexecOption ""


##+#############################################################
## Get the directory that this Tk script is in. That will be the
## directory that any 'external' utility shell or Tk script
## should be in.
##+#############################################################

## FOR TESTING:
#  puts "argv0: $argv0"

# set DIRscripts "."
# set DIRscripts "[pwd]"
# set DIRscripts "$env(HOME)/apps/tkUtils"
  set DIRscripts "[file dirname $argv0]"


Shell script #1 (called by the Tk script) :

There is one 'external' shell script that is used to implement the 'PROPERTIES-IN' and the 'PROPERTIES-OUT' options.

It is needed because the 'ffmpeg' command has not been written to query the 'properties' of a media file in a 'smooth' way. This is explained more clearly in comments in the script, below.

You can put this script in the same directory with the Tk script. The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell scripts by extracting the name of the directory in which the Tk script lies.

 Code for shell-script 'audioFilePROPERTIES_ffmpeg-i.sh' :
#!/bin/sh
##
## SCRIPT: audioFilePROPERTIES_ffmpeg-i.sh
##
##+#######
## PURPOSE:
## This script runs the 'ffmpeg -i' command on a filename which is provided
## to this script as its only argument.
##
## This script is meant to return several lines selected from the output
## of 'ffmpeg -i'. The lines are to be sent to standard out.
##
## Those selected lines are to provide the 'properties' of an audio file.
## Example lines to be extracted:
##
## Input #0, mp3, from 'midname.mp3':
##   Duration: 00:00:34.74, start: 0.000000, bitrate: 128 kb/s
##     Stream #0.0: Audio: mp3, 44100 Hz, mono, s16, 128 kb/s
##
##+#########
## CALLED BY:
## This shell script is meant to be called from the Tk GUI 'wrapper'
## script --- 'audioClipChgVolumeConvertEtc_ffmpeg_FrontEnd.tk' --- when
## the user requests the PROPERTIES of an input or output audio file.
##
##+######
## METHOD:
## It would be nice to simply call 'ffmpeg -i' via a Tcl 'exec' command
## in the Tk script. However, the 'ffmpeg -i' command throws an error
## when output is not directed to a recognized media file type ---
## and all text output goes to 'stderr' not 'stdout'.
##
## Sample output follows:
##
## $ ffmpeg -i midname.mp3
## FFmpeg version SVN-r19352-4:0.5+svn20090706-2ubuntu2.3, Copyright (c) 2000-2009 Fabrice Bellard, et al.
##   configuration: --extra-version=4:0.5+svn20090706-2ubuntu2.3 --prefix=/usr --enable-avfilter --enable-avfilter-lavf --enable-vdpau --enable-bzlib --enable-libgsm --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-libvorbis --enable-pthreads --enable-zlib --disable-stripping --disable-vhook --enable-gpl --enable-postproc --enable-swscale --enable-x11grab --enable-libdc1394 --extra-cflags=-I/build/buildd/ffmpeg-0.5+svn20090706/debian/include --enable-shared --disable-static
##   libavutil     49.15. 0 / 49.15. 0
##   libavcodec    52.20. 0 / 52.20. 0
##   libavformat   52.31. 0 / 52.31. 0
##   libavdevice   52. 1. 0 / 52. 1. 0
##   libavfilter    0. 4. 0 /  0. 4. 0
##   libswscale     0. 7. 1 /  0. 7. 1
##   libpostproc   51. 2. 0 / 51. 2. 0
##   built on Mar 31 2011 18:50:18, gcc: 4.4.1
## Input #0, mp3, from 'midname.mp3':
##   Duration: 00:00:34.74, start: 0.000000, bitrate: 128 kb/s
##     Stream #0.0: Audio: mp3, 44100 Hz, mono, s16, 128 kb/s
## At least one output file must be specified 
##
## NOTE: The information we want is between the 'built on' line and the
## ending error message line: 'At least one output file must be specified'.
##
## There does not appear to be a way to direct these information messages and
## the ending error message to 'stdout' (even with '2>&1') in such a way that
## the Tk script does not detect an error. When Tk detects the error return code,
## there does not seem to be a way to pass 'stdout' to the Tk script.
##
## So we call on this 'external' shell script from the Tk script,
## to do the dirty work of extracting the desired lines from
## the stderr output and pass the lines back to the Tk script
## without throwing an error that would prevent the Tk script
## from accepting the lines sent to stdout.
##
## We use '2>&1' to pipe the output of 'ffmpeg -i' to a small
## 'awk' program that extracts the desired lines --- between
## the 'built on' line and the 'At least one ...' line.
##
## Since we let the output of 'awk' go to 'stdout', that becomes
## the output from this script that will be captured in the Tk script.
##
## NOTE: Piping the output of 'ffmpeg -i <filename> 2>&1' to
##          egrep 'Input|Duration|Stream'
## might work, but it may miss some output for some kinds of media/audio files.
##
##+#########
## REFERENCE:
## http://www.commandlinefu.com/commands/view/2207/get-video-information-with-ffmpeg
## 2009-05-18 
## TOPIC: Get video information with ffmpeg
##
## $ ffmpeg -i filename.flv
##
## I used an flv in my example, but it'll work on any file ffmpeg supports.
##
## It says it wants an output file [the 'At least one output' error message],
## but it tells what you want to know without one [without specifying an
## output file].
##
## Also see:
## http://stackoverflow.com/questions/11400248/using-ffmpeg-to-get-video-info-why-do-i-need-to-specify-an-output-file
## http://www.techanswerguy.com/2012/03/redirecting-ffmpeg-output-performing.html
## https://groups.google.com/forum/#!msg/nodejs/7KakLQR50_w/yEVW1-kA-boJ
## http://www.computerhope.com/forum/index.php?topic=110250.0
##########################################################################
## Started: 2014jun19 Based on a 'movieFilePROPERTIES_ffmpeg-i.sh' script
##                    which was based on a PROPERTIES query script from the
##                    'feNautilusScripts' system at www.freedomenv.com.
##                    But that script uses temporary files and the
##                    'grep' and 'tail' commands instead of 'awk'.
## Changed: 2014
###########################################################################

## FOR TESTING: (show statements as they execute)
# set -x

#########################################
## Get the filename passed to this script.
#########################################

FILENAME="$1"

## FOR TESTING:
#  FILENAME="$HOME/TESTfilesAUDIO/test_32sec.mp3"

#########################################
## Pass a heading to stdout.
#########################################

echo "\
'ffmpeg -i' output:
##################
"

########################################################################
## Pass the output of 'ffmpeg -i "$FILENAME"' to a small awk' program
## that extracts the properties of the audio file.
########################################################################
## CAUTION: Single-quotes in comment lines of an awk script cause syntax
##          errors --- like braces in comment lines cause errors in
##          Tcl-Tk scripts.
##          Use double-quotes instead.
########################################################################

ffmpeg -i "$FILENAME" 2>&1 | awk '
BEGIN {
   KEEP=0;
   ## KEEP is a flag. It will be set to 1 when we encounter the "built on" rec.
}
{
   ################################################
   ## Hold the first 12 characters of this record,
   ## whose contents are in $0.
   ################################################

   FIELD1=substr($0,1,12)

   #########################################################################
   ## If KEEP=0 and this rec does not contain the string "built on", skip
   ## this rec (read the next one). We want to read to the "built on" rec.
   #########################################################################

   if ( FIELD1 !~ "built on" && KEEP==0) next

   #########################################################################
   ## If this rec contains the string "built on", set KEEP=1 and
   ## read the next rec.
   #########################################################################

   if ( FIELD1 ~ "built on" && KEEP==0) {
      KEEP=1
      next
   }

   #########################################################################
   ## If this rec contains the string "At least one" (as in
   ## "At least one output file must be specified"), exit.
   #########################################################################

   if ( FIELD1 ~ "At least one") {exit}

   #########################################################################
   ## If we get here, this is a record we want. Print it.
   #########################################################################

   print $0
}'
## END OF the awk script.


Shell script #2 (called by the Tk script) :

There is another 'external' shell script that is used as a 'wrapper' to the 'ffplay' command --- to allow this command-line program to display its execution messages --- in particular, the current elapsed-time of the audio file being played.

The elapsed-time display is useful in finding the start and duration time parameters for use in the 'CLIP' option.

This script starts up the 'ffplay' command via the 'xterm' command, so that the execution messages being sent to 'standard out' are displayed in the 'xterm' window.

You can put this script in the same directory with the Tk script. The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell scripts by extracting the name of the directory in which the Tk script lies.

 Code for shell-script 'ffplay_inXterm.sh' :
#!/bin/sh
##
## SCRIPT: ffplay_inXterm.sh
##
##+#######
## PURPOSE:
## This script runs the 'ffplay' command in an xterm window --- on a
## filename which is provided to this script as its only argument.
##
##+#########
## CALLED BY:
## This shell script is meant to be called from the Tk GUI 'wrapper'
## script --- 'audioClipChgVolumeConvertEtc_ffmpeg_FrontEnd.tk' --- when
## the user requests the 'ffplay' program to play an input or output audio file.
##
##+######
## METHOD:
## We use the '-hold' and '-fg' and '-bg' parameters of the xterm command.
##
##+#######################################################################
## Started: 2014jun20 
## Changed: 2014
##+########################################################################

## FOR TESTING: (show statements as they execute)
# set -x

##+######################################
## Get the filename passed to this script.
##+######################################

FILENAME="$1"

## FOR TESTING:
#  FILENAME="$HOME/TESTfilesAUDIO/test_35sec_44100Hz_128kbs_mono_543KB.mp3"


##+#####################################################################
## Run 'ffplay' in an 'xterm' window.
##+#####################################################################

xterm -bg black -fg white -hold -geometry 90x25-10-10 -e \
   ffplay -stats "$FILENAME" 2> /dev/null


Shell script #3 (called by the Tk script) :

There is another 'external' shell script that is used as a 'wrapper' to the 'mplayer' command --- to allow this command-line program to display its execution messages --- in particular, the current elapsed-time of the audio file being played.

The elapsed-time display is useful in finding the start and duration time parameters for use in the 'CLIP' option.

This script starts up the 'mplayer' command via the 'xterm' command, so that the execution messages being sent to 'standard out' are displayed in the 'xterm' window.

You can put this script in the same directory with the Tk script. The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell scripts by extracting the name of the directory in which the Tk script lies.

 Code for shell-script 'mplayer_inXterm.sh' :
#!/bin/sh
##
## SCRIPT: mplayer_inXterm.sh
##
##+#######
## PURPOSE:
## This script runs the 'mplayer' command in an xterm window --- on a
## filename which is provided to this script as its only argument.
##
##+#########
## CALLED BY:
## This shell script is meant to be called from the Tk GUI 'wrapper'
## script --- 'audioClipChgVolumeConvertEtc_ffmpeg_FrontEnd.tk' --- when
## the user requests the 'mplayer' program to play an input or output audio file.
##
##+######
## METHOD:
## We use the '-hold' and '-fg' and '-bg' parameters of the xterm command.
##
##+#######################################################################
## Started: 2014jun20 
## Changed: 2014
##+########################################################################

## FOR TESTING: (show statements as they execute)
# set -x

##+######################################
## Get the filename passed to this script.
##+######################################

FILENAME="$1"

## FOR TESTING:
#  FILENAME="$HOME/TESTfilesAUDIO/test_35sec_44100Hz_128kbs_mono_543KB.mp3"


##+#####################################################################
## Run 'mplayer' in an 'xterm' window.
##+#####################################################################
## Found the '-msgcolor -msgmodule -nolirc' parms suggested at
## http://crunchbang.org/forums/viewtopic.php?id=20178
##+#####################################################################

xterm -bg black -fg white -hold -geometry 90x20-10-10 -e \
   mplayer -msgcolor -msgmodule -nolirc \
   "$FILENAME" 2> /dev/null


INSTALLING THE SCRIPTS:

The Tk script and the 3 shell scripts could be put in a sub-directory of the user's home directory, such as $HOME/apps/tkEditAudioFiles_ffmpeg.

Then the user can use their desktop system (such as Gnome or KDE) to set up the Tk script as an icon on the desktop.

Then, whenever the user wants to edit an audio file, the user can click on the icon to startup this 'front end' to the 'ffmpeg' command.


SOME AUDIO PLAYERS:

The following screenshot shows the execution messages that the 'mplayer' program displays in the 'xterm' window --- when the user enters 'xmplayer' in the 'Player' entry field of the GUI.

mplayer_inXterm_screenshot_488x291.jpg

See the elapsed-time and total-time display just below the 'Starting playback ...' line. The elapsed-time display is useful in determining start and duration times for a CLIP operation.

The 'ffplay' program displays similar messages in the 'xterm' window --- when the user enters 'xffplay' in the 'Player' entry field of the GUI.

However, the 'ffplay' command also starts up a 'playback' window that shows the waveform of the audio channel(s) of the audio file being played.

---

If you want a fancier player program, the following image shows that the 'totem' player program includes an 'audio visualizer' in its GUI.

totem_GUIscreenshot_615x413.jpg

See the elapsed time display on the lower left of the 'totem' GUI.

Unfortunately, the 'totem' player program has failed to play some MOVIE files created by 'ffmpeg' and it MAY also fail on some AUDIO files created by 'ffmpeg'.

If that happens, try one of the other players here.

---

The makers of the 'mplayer' program have provided a GUI wrapper for the Mplayer program --- called 'gmplayer'. At least they provided 'gmplayer' back in 2009. It is not certain that they will continue to do so in the future. In any case, here is a screenshot of its simple GUI.

gmplayer_GUIscreenshot_384x138.jpg

The display of the elapsed time in the lower left corner of this GUI can be used to help determine start and duration time parameters for a CLIP operation on an audio input file.

---

Another popular media player program is 'VLC'. Here is a screenshot of its GUI.

vlc_GUIscreenshot_351x163.jpg

Like with 'gmplayer', the display of the elapsed time in the lower part of this GUI (on the lower right) can be used to help determine start and duration time parameters for a CLIP operation on an audio input file.

Unfortunately, like with the 'totem' player, the 'vlc' program has failed to play some MOVIE files created by 'ffmpeg' and it MAY also fail on some AUDIO files created by 'ffmpeg'.

If that happens, try one of the other players here.


SOME POSSIBLE ENHANCEMENTS

As you can see in the listbox in the images above, I have implemented the following 'exec-options':

  • CLIP
  • CHG-VOLUME
  • PROPERTIES-IN
  • PROPERTIES-OUT
  • CONVERT

But there are several more options that I may implement in the future:

  • ADD-CHANNEL
  • EXTRACT-CHANNEL
  • REMOVE-CHANNEL

---

Also, I may return someday to the 'tkMovieEdit' utility at

Movie Edit Utility - Clip, Crop, Convert, etc. - a front-end for the 'ffmpeg' command

to incorporate the two shell scripts (above) that provide the 'xffplay' and 'xmplayer' options to play the movie files in that utility --- instead of using the 'raw' 'ffplay' and 'mplayer' commands.

---

There are many Tk scripts on my 'to do' list in the categories of

  • 3D tools
  • Math proofs/demos/animations
  • Ordinary differential equation (ODE) simulations (animations)

I need to start on these projects --- but first I may create another 'ffmpeg'-based utility -- 'tkKaraoke' --- to enable the user to record audio from both the speakers and the microphone of a computer system simultaneously --- in an easy-to-use way that makes it easy to do even if one does such a recording only once in a blue moon.

Thus the user could sing (or talk) along to an audio file being played through the speakers, and both the voice input to a microphone attached to the computer and the audio from speaker channels will be recorded in an audio file.

And this utility could be used in other ways. For example, play a movie (a YouTube movie, for example) and talk along with the movie. The movie soundtrack and the voice input to a microphone could be recorded in an audio file.


IN CONCLUSION

As I have said on several other code-donation pages on this wiki ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.


uniquename 2014jun30 - UPDATE - 'ffmpeg' or 'avconv'

See a 2014jun30-'UPDATE' note near the bottom of page

Movie Capture from Computer Monitor-and-Audio - a front-end for the 'ffmpeg' command

for some info on using 'avconv' instead of 'ffmpeg'.