]> git.immae.eu Git - perso/Immae/Projets/Python/MusicSampler.git/commitdiff
Add config key to config.yml to store command line arguments
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Fri, 12 Aug 2016 10:22:01 +0000 (12:22 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Fri, 12 Aug 2016 10:22:01 +0000 (12:22 +0200)
config.yml
documentation_en.md
documentation_fr.md
music_sampler/app.py
music_sampler/helpers.py

index e543b041312146aa83ab366a4245932f94ce46c3..8802dcff7f76c0f965c1e848071d0496f8989d16 100644 (file)
@@ -1,3 +1,31 @@
+#################################
+##### General configuration #####
+## Keep in mind that in-line option override these
+
+#option listed here are the default options.
+config:
+# debug info
+  debug: false
+# languages. Available: fr, en
+  language: fr
+# path to the musics.
+  music_path: .
+# The awful red message that shows up when you lose the focus
+  focus_warning: true
+# built-in mixing
+  builtin_mixing: true
+# Device used for playing musics. Default value depends on your system
+#  device: 
+# Advanced parameters: use at your own risk! (your computer probably won't explode, though)
+  latency: high
+  blocksize: 0
+  frame_rate: 44100
+  sample_width: 2
+  channels: 2
+
+
+
+
 ###################
 ##### Aliases #####
 
@@ -41,8 +69,8 @@ music_properties:
     name: Crocodile noise
     gain: 1.2
 
-####################################################
-##### Key properties: how do the key look like #####
+###############################################################################
+##### Key properties: how do the key look like, and some other properties #####
 
 key_properties:
   'a':
index 87b9bd723a05784e7f5e7e5efe46bfb72b6a4292..1cf5cfdc2e587e4c6476134a255acd681b329e7d 100644 (file)
@@ -39,7 +39,7 @@ must be available on your system, as well as the `portaudio` library:
 
     sudo apt-get install ttf-ancient-fonts ttf-ubuntu-font-family portaudio
 
-Pour compiler kivy avec la librairie SDL2, il faut certains paquets installés:
+To compile Kivy with the SDL2 library, you need some packages:
 
     sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
 
@@ -96,26 +96,29 @@ understand just by looking at it.
 ### Options available at launch
 
 All the options below are optional; usually, running the program in the correct
-folder is enough
+folder is enough. Most of the parameters can be defined also in the config file.
+The command line parameters always take precedence.
 
   * `-h, --help`: shows a list of available options
   * `-c CONFIG, --config CONFIG`: gives the configuration file to load (by
     default, `config.yml` in the current folder).
   * `-p MUSIC_PATH, --music-path MUSIC_PATH`: gives the path to find the musics
     (by default, the current folder)
-  * `-d, --debug`: show debug informations in the terminal (disabled by default)
+  * `--no-debug, --debug`: show debug informations in the terminal (disabled by
+    default)
   * `-V, --version`: show current version and exit (only for the compiled
     version)
   * `-L, --language`: change application language. Current languages: fr, en
     (default 'fr')
-  * `--no-focus-warning`: don't show warning when focus gets lost.
+  * `--focus-warning, --no-focus-warning`: show / don't show warning when focus gets
+    lost (default is to show it)
 
 The following options are reserved for a more advanced use of Music Sampler, or
 in case of problem with the standard configuration:
 
-  * `-m, --builtin-mixing`: make the sound mixing locally. By default, Music
-    Sampler will let the system do it and open one channel per music loaded. Use
-    it only if the system cannot handle it.
+  * `--no-builtin-mixing, --builtin-mixing`: make the sound mixing locally. By
+    default, Music Sampler will let the system do it and open one channel per
+    music loaded. Use it only if the system cannot handle it.
   * `-l LATENCY, --latency LATENCY`: "low", "high" or a number of seconds
     (default "high")
   * `-b BLOCKSIZE, --blocksize BLOCKSIZE`: Number of frames for each mixing
@@ -144,6 +147,9 @@ corresponding problems) or abort.
 The file contains several sections:
 
     :::yaml
+    config:
+      ...
+
     aliases:
       ...
 
@@ -156,6 +162,14 @@ The file contains several sections:
     keys:
       ...
 
+### `config`
+
+The config section lets you store configuration parameters that you would
+normally use in the command line parameters. The '-' in the long parameter name
+should be replaced by '_' (e.g. '--music-path' -> 'music_path'). For toggles
+(`debug`, `focus_warning`, `builtin_mixing`) use the version without 'no-' and
+specify `true` or `false` as value. Note that command line arguments always take
+precedence.
 
 ### `music_properties`
 
index a55ae73de4873ff80174c157bca7d2e9a811b39f..b739aa2c752cddb5e75c62472da717b7073ec336 100644 (file)
@@ -103,7 +103,9 @@ gardées d'une fois sur l'autre.
 ### Options disponibles au lancement
 
 Toutes les options au lancement sont facultatives ; la plupart du temps lancer
-le programme dans le bon dossier suffit.
+le programme dans le bon dossier suffit. La plupart d'entre elles peuvent être
+définies également dans le fichier de config (à part `--config` bien sûr). Les
+arguments en ligne de commande ont toujours la priorité.
 
   * `-h, --help` : affiche une liste des options disponibles.
   * `-c CONFIG, --config CONFIG` : précise le fichier de configuration à charger
@@ -111,20 +113,21 @@ le programme dans le bon dossier suffit.
     music_sampler).
   * `-p MUSIC_PATH, --music-path MUSIC_PATH` : précise le chemin des musiques
     (par défaut, le dossier courant).
-  * `-d, --debug` : Affiche les informations de déboggage (désactivé par défaut)
+  * `--no-debug, --debug` : Affiche les informations de déboggage (désactivé par
+    défaut)
   * `-V, --version` : affiche la version courante et quitte (utilisable
     uniquement pour la version compilée).
   * `-L, --language` : change la langue de l'application. Actuellement: fr, en
     (par défaut 'fr')
-  * `--no-focus-warning`: Ne pas afficher d'avertissement lorsque l'application
-    perd le focus.
+  * `--focus-warning, --no-focus-warning`: Afficher / Ne pas afficher
+    d'avertissement lorsque l'application perd le focus (activé par défaut).
 
 Les options suivantes sont plutôt réservées à un usage avancé de music_sampler,
 ou en cas de problème avec la configuration standard :
 
-  * `-m, --builtin-mixing` Effectue en interne le mixage des sons. Par défaut,
-    music_sampler confie le mixage au système : n'activer cette option que si le
-    système n'y parvient pas.
+  * `--no-builtin-mixing, --builtin-mixing` Effectue en interne le mixage des
+    sons. Par défaut, music_sampler confie le mixage au système : n'activer
+    cette option que si le système n'y parvient pas.
   * `-l LATENCY, --latency LATENCY` : latence. Préciser "low", "high" ou un
     nombre de secondes (par défaut, "high")
   * `-b BLOCKSIZE, --blocksize BLOCKSIZE` : taille des blocs. Nombre de frames
@@ -158,6 +161,9 @@ ne se lance pas du tout.
 Le fichier contient plusieurs sections :
 
     :::yaml
+    config:
+      ...
+
     aliases:
       ...
 
@@ -171,6 +177,15 @@ Le fichier contient plusieurs sections :
       ...
 
 
+### `config`
+
+La section config permet d'enregistrer les paramètres habituellement donnés en
+ligne de commande. Les '-' dans le nom du paramètre long doivent être remplacés
+par des '_' (par exemple '--music-path' -> 'music_path'). Pour les switches
+(`debug`, `focus_warning`, `builtin_mixing`), utilisez la version sans le 'no-'
+et spécifiez `true` / `false` en valeur. Notez que les arguments donnés en ligne
+de commande sont toujours prioritaires sur les valeurs du fichier.
+
 ### `music_properties` : propriétés des musiques
 
 Cette section sert à définir des propriétés globales des musiques.
index e7c90dbd8967da9a4cadda1a8068ef7c2223da54..ce842358240d0e6cbb56206513ab539ba7b94bc7 100644 (file)
@@ -50,7 +50,7 @@ class Screen(FloatLayout):
         Window.on_request_close = self.on_request_close
 
     def focus_changed(self, instance, focus):
-        if Config.no_focus_warning:
+        if not Config.focus_warning:
             return
         if not focus:
             self.add_widget(self.unfocused_widget)
index 2199058cf58555b9ce2a3aec67d2da94340d1fb7..943e5a197465143dc2f47e193bfbcc0f3bdf94e2 100644 (file)
@@ -6,6 +6,7 @@ import math
 import sounddevice as sd
 import logging
 import gettext
+import yaml
 gettext.install('music_sampler')
 Logger = logging.getLogger("kivy")
 
@@ -52,6 +53,96 @@ def path():
     else:
         return os.path.dirname(os.path.realpath(__file__))
 
+
+Configs = {
+    'music_path': {
+        'abbr': '-p',
+        'default': '.',
+        'help': _("Folder in which to find the music files"),
+        'type': None
+    },
+    'latency': {
+        'abbr': '-l',
+        'default': 'high',
+        'help': _("Latency: low, high or number of seconds"),
+        'type': None
+    },
+    'language': {
+        'abbr': '-L',
+        'default': "fr",
+        'help': _("Select another language"),
+        'type': None
+    },
+    'device': {
+        'abbr': '-d',
+        'default': None,
+        'help': _("Select this sound device"),
+        'type': None
+    },
+    'blocksize': {
+        'abbr': '-b',
+        'default': 0,
+        'help': _("Blocksize: If not 0, the number of frames to take\
+                    at each step for the mixer"),
+        'type': int
+    },
+    'frame_rate': {
+        'abbr': '-f',
+        'default': 44100,
+        'help': _("Frame rate to play the musics"),
+        'type': int
+    },
+    'channels': {
+        'abbr': '-x',
+        'default': 2,
+        'help': _("Number of channels to use"),
+        'type': int
+    },
+    'sample_width': {
+        'abbr': '-s',
+        'default': 2,
+        'help': _("Sample width (number of bytes for each frame)"),
+        'type': int
+    },
+    'builtin_mixing': {
+        'default': False,
+        'help_yes': _("Make the mixing of sounds manually\
+                    (do it if the system cannot handle it correctly)"),
+        'help_no': _("Don't make the mixing of sounds manually (default)"),
+        'type': 'boolean'
+    },
+    'debug': {
+        'abbr': '-d',
+        'default': False,
+        'help_yes': _("Print messages in console"),
+        'help_no': _("Don't print messages in console (default)"),
+        'type': 'boolean'
+    },
+    'focus_warning': {
+        'default': True,
+        'help_yes': _("Show a warning when focus is lost (default)"),
+        'help_no': _("Don't show warning when focus is lost"),
+        'type': 'boolean'
+    },
+    'list_devices': {
+        'help': _("List available sound devices"),
+        'type': 'action'
+    },
+}
+Configs_order = [
+    'debug',
+    'music_path',
+    'builtin_mixing',
+    'latency',
+    'blocksize',
+    'frame_rate',
+    'channels',
+    'sample_width',
+    'focus_warning',
+    'language',
+    'list_devices',
+    'device',
+]
 def parse_args():
     argv = sys.argv[1 :]
     sys.argv = sys.argv[: 1]
@@ -68,72 +159,34 @@ def parse_args():
     sys.argv.extend(["-c", "kivy:log_name:/tmp/music_sampler_%_.txt"])
 
     parser = argparse.ArgumentParser(
-            description=_("A Music Sampler application."),
-            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
-    parser.add_argument("-c", "--config",
-            default="config.yml",
-            required=False,
-            help=_("Config file to load"))
-    parser.add_argument("-p", "--music-path",
-            default=".",
-            required=False,
-            help=_("Folder in which to find the music files"))
-    parser.add_argument("-d", "--debug",
-            nargs=0,
-            action=DebugModeAction,
-            help=_("Print messages in console"))
-    parser.add_argument("-m", "--builtin-mixing",
-            action="store_true",
-            help=_("Make the mixing of sounds manually\
-                    (do it if the system cannot handle it correctly)"))
-    parser.add_argument("-l", "--latency",
-            default="high",
-            required=False,
-            help=_("Latency: low, high or number of seconds"))
-    parser.add_argument("-b", "--blocksize",
-            default=0,
-            type=int,
-            required=False,
-            help=_("Blocksize: If not 0, the number of frames to take\
-                    at each step for the mixer"))
-    parser.add_argument("-f", "--frame-rate",
-            default=44100,
-            type=int,
-            required=False,
-            help=_("Frame rate to play the musics"))
-    parser.add_argument("-x", "--channels",
-            default=2,
-            type=int,
-            required=False,
-            help=_("Number of channels to use"))
-    parser.add_argument("-s", "--sample-width",
-            default=2,
-            type=int,
-            required=False,
-            help=_("Sample width (number of bytes for each frame)"))
+            argument_default=argparse.SUPPRESS,
+            description=_("A Music Sampler application."))
     parser.add_argument("-V", "--version",
             action="version",
             help=_("Displays the current version and exits. Only use\
                     in bundled package"),
             version=show_version())
-    parser.add_argument("--device",
-            action=SelectDeviceAction,
-            help=_("Select this sound device")
-            )
-    parser.add_argument("--list-devices",
-            nargs=0,
-            action=ListDevicesAction,
-            help=_("List available sound devices")
-            )
-    parser.add_argument("--no-focus-warning",
-            action='store_true',
-            help=_("Don't show warning when focus is lost")
-            )
-    parser.add_argument("-L", "--language",
+    parser.add_argument("-c", "--config",
+            default="config.yml",
             required=False,
-            default="fr",
-            help=_("Select another language")
-            )
+            help=_("Config file to load (default: config.yml)"))
+    for argument in Configs_order:
+        arg = Configs[argument]
+        if arg['type'] != 'boolean' and arg['type'] != 'action':
+            parser.add_argument(arg['abbr'], '--' + argument.replace('_', '-'),
+                    type=arg['type'],
+                    help=arg['help']+_(" (default: {})").format(arg['default']))
+        elif arg['type'] == 'boolean':
+            parser.add_argument('--' + argument.replace('_', '-'),
+                    action='store_const', const=True,
+                    help=arg['help_yes'])
+            parser.add_argument('--no-' + argument.replace('_', '-'),
+                    action='store_const', const=True,
+                    help=arg['help_no'])
+        else:
+            parser.add_argument('--' + argument.replace('_', '-'),
+                    action='store_const', const=True,
+                    help=arg['help'])
     parser.add_argument('--',
             dest="args",
             help=_("Kivy arguments. All arguments after this are interpreted\
@@ -142,36 +195,58 @@ def parse_args():
     args = parser.parse_args(argv)
 
     Config.yml_file = args.config
+    build_config(args)
 
-    Config.latency = args.latency
-    Config.blocksize = args.blocksize
-    Config.frame_rate = args.frame_rate
-    Config.channels = args.channels
-    Config.sample_width = args.sample_width
-    Config.builtin_mixing = args.builtin_mixing
-    Config.no_focus_warning = args.no_focus_warning
-    if args.language != 'en':
+    if Config.device is not None:
+        sd.default.device = Config.device
+
+    if Config.list_devices:
+        print(sd.query_devices())
+        sys.exit()
+
+    if Config.debug:
+        sys.argv.extend(["-c", "kivy:log_level:debug"])
+
+    if Config.language != 'en':
         gettext.translation("music_sampler",
                 localedir=path() + '/locales',
-                languages=[args.language]).install()
-    if args.music_path.endswith("/"):
-        Config.music_path = args.music_path
-    else:
-        Config.music_path = args.music_path + "/"
+                languages=[Config.language]).install()
+    if not Config.music_path.endswith("/"):
+        Config.music_path = Config.music_path + "/"
 
-class DebugModeAction(argparse.Action):
-    def __call__(self, parser, namespace, values, option_string=None):
-        sys.argv.extend(["-c", "kivy:log_level:debug"])
+def build_config(args):
+    stream = open(Config.yml_file, "r")
+    try:
+        config = yaml.safe_load(stream)
+    except Exception as e:
+        error_print("Error while loading config file: {}".format(e))
+        config = {}
+    stream.close()
+    if 'config' in config:
+        config = config['config']
+    else:
+        config = {}
 
-class SelectDeviceAction(argparse.Action):
-    def __call__(self, parser, namespace, values, option_string=None):
-        sd.default.device = values
+    for config_item in Configs_order:
+        if Configs[config_item]['type'] != 'boolean' and \
+                Configs[config_item]['type'] != 'action':
+            t = Configs[config_item]['type'] or str
+            if hasattr(args, config_item):
+                setattr(Config, config_item, getattr(args, config_item))
+            elif config_item in config:
+                setattr(Config, config_item, t(config[config_item]))
+            else:
+                setattr(Config, config_item, Configs[config_item]['default'])
+        elif Configs[config_item]['type'] == 'boolean':
+            if hasattr(args, 'no_' + config_item) or hasattr(args, config_item):
+                setattr(Config, config_item, hasattr(args, config_item))
+            elif config_item in config:
+                setattr(Config, config_item, config[config_item])
+            else:
+                setattr(Config, config_item, Configs[config_item]['default'])
+        else:
+            setattr(Config, config_item, hasattr(args, config_item))
 
-class ListDevicesAction(argparse.Action):
-    nargs = 0
-    def __call__(self, parser, namespace, values, option_string=None):
-        print(sd.query_devices())
-        sys.exit()
 
 def show_version():
     if getattr(sys, 'frozen', False):