X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=music_sampler%2Fhelpers.py;h=9eb1a950ca50fb8028e7b52dd1d601f0d2a908f7;hb=de71c01cd5c6dca3b33201a9effafc6c422fa239;hp=2249746a5a928cf2c416915a0b587c6b10b704d8;hpb=7d6df771f603e9642047264f967525422ef09e99;p=perso%2FImmae%2FProjets%2FPython%2FMusicSampler.git diff --git a/music_sampler/helpers.py b/music_sampler/helpers.py index 2249746..9eb1a95 100644 --- a/music_sampler/helpers.py +++ b/music_sampler/helpers.py @@ -5,6 +5,9 @@ import os import math import sounddevice as sd import logging +import gettext +import yaml +gettext.install('music_sampler') Logger = logging.getLogger("kivy") from . import sysfont @@ -50,6 +53,104 @@ 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' + }, + 'load_all_musics': { + 'default': True, + 'help_yes': _("Load all the musics at launch time (default)"), + 'help_no': _("Don't load all the musics at launch time (use it if you \ + have memory problems)"), + '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', + 'load_all_musics', +] def parse_args(): argv = sys.argv[1 :] sys.argv = sys.argv[: 1] @@ -66,108 +167,110 @@ 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", + 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("-c", "--config", + default="config.yml", + required=False, + 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\ - by Kivy. Pass \"-- --help\" to get Kivy's usage.") + help=_("Kivy arguments. All arguments after this are interpreted\ + by Kivy. Pass \"-- --help\" to get Kivy's usage.")) 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.music_path.endswith("/"): - Config.music_path = args.music_path - else: - Config.music_path = args.music_path + "/" + if Config.device is not None: + sd.default.device = Config.device -class DebugModeAction(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): + if Config.list_devices: + print(sd.query_devices()) + sys.exit() + + if Config.debug: sys.argv.extend(["-c", "kivy:log_level:debug"]) -class SelectDeviceAction(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): - sd.default.device = values + if Config.language != 'en': + gettext.translation("music_sampler", + localedir=path() + '/locales', + languages=[Config.language]).install() + if not Config.music_path.endswith("/"): + Config.music_path = Config.music_path + "/" + +def dump_config(): + max_size = max(max(map(len, Configs_order)), len('config')) + info_print("{:<{}} : {}".format( + "config", max_size, Config.yml_file)) + for item in Config.__dict__: + if item in Configs_order: + info_print("{:<{}} : {}".format( + item, max_size, getattr(Config, item))) + +def build_config(args): + stream = open(Config.yml_file, "r", encoding='utf8') + 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 = {} + + 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): with open(path() + ".pyinstaller_commit", "r") as f: return f.read() else: - return "option '-v' can only be used in bundled package" + return _("option '-V' can only be used in bundled package") def duration_to_min_sec(duration): minutes = int(duration / 60) @@ -211,3 +314,10 @@ def warn_print(message, with_trace=None): Logger.warn('MusicSampler: ' + message, exc_info=with_trace) +def info_print(message, with_trace=None): + if with_trace is None: + with_trace = (Logger.getEffectiveLevel() < logging.WARN) + with_trace &= (sys.exc_info()[0] is not None) + + Logger.info('MusicSampler: ' + message, exc_info=with_trace) +