]> git.immae.eu Git - perso/Immae/Projets/Python/MusicSampler.git/blame - music_sampler/helpers.py
Improve error message and handling
[perso/Immae/Projets/Python/MusicSampler.git] / music_sampler / helpers.py
CommitLineData
6ebe6247
IB
1# -*- coding: utf-8 -*-
2import argparse
3import sys
4import os
5import math
6import sounddevice as sd
7import logging
023d9381 8Logger = logging.getLogger("kivy")
6ebe6247
IB
9
10from . import sysfont
11
12class Config:
13 pass
14
15def find_font(name, style=sysfont.STYLE_NONE):
16 if getattr(sys, 'frozen', False):
17 font = sys._MEIPASS + "/fonts/{}_{}.ttf".format(name, style)
18 else:
19 font = sysfont.get_font(name, style=style)
20 if font is not None:
21 font = font[4]
22 return font
23
24def register_fonts():
25 from kivy.core.text import LabelBase
26
27 ubuntu_regular = find_font("Ubuntu", style=sysfont.STYLE_NORMAL)
28 ubuntu_bold = find_font("Ubuntu", style=sysfont.STYLE_BOLD)
29 symbola = find_font("Symbola")
30
31 if ubuntu_regular is None:
2010311b
IB
32 error_print("Font Ubuntu regular could not be found, "
33 "please install it.", exit=True)
6ebe6247 34 if symbola is None:
2010311b
IB
35 error_print("Font Symbola could not be found, please install it.",
36 exit=True)
6ebe6247
IB
37 if ubuntu_bold is None:
38 warn_print("Font Ubuntu Bold could not be found.")
39
40 LabelBase.register(name="Ubuntu",
41 fn_regular=ubuntu_regular,
42 fn_bold=ubuntu_bold)
43 LabelBase.register(name="Symbola",
44 fn_regular=symbola)
45
46
47def path():
48 if getattr(sys, 'frozen', False):
49 return sys._MEIPASS + "/"
50 else:
51 return os.path.dirname(os.path.realpath(__file__))
52
53def parse_args():
54 argv = sys.argv[1 :]
55 sys.argv = sys.argv[: 1]
56 if "--" in argv:
57 index = argv.index("--")
58 kivy_args = argv[index+1 :]
59 argv = argv[: index]
60
61 sys.argv.extend(kivy_args)
62
023d9381
IB
63 os.environ["KIVY_NO_CONFIG"] = 'true'
64 sys.argv.extend(["-c", "kivy:log_level:warning"])
65 sys.argv.extend(["-c", "kivy:log_dir:/tmp"])
66 sys.argv.extend(["-c", "kivy:log_name:/tmp/music_sampler_%_.txt"])
67
6ebe6247
IB
68 parser = argparse.ArgumentParser(
69 description="A Music Sampler application.",
70 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
71 parser.add_argument("-c", "--config",
72 default="config.yml",
73 required=False,
74 help="Config file to load")
75 parser.add_argument("-p", "--music-path",
76 default=".",
77 required=False,
78 help="Folder in which to find the music files")
79 parser.add_argument("-d", "--debug",
80 nargs=0,
81 action=DebugModeAction,
82 help="Print messages in console")
83 parser.add_argument("-m", "--builtin-mixing",
84 action="store_true",
85 help="Make the mixing of sounds manually\
86 (do it if the system cannot handle it correctly)")
87 parser.add_argument("-l", "--latency",
88 default="high",
89 required=False,
90 help="Latency: low, high or number of seconds")
91 parser.add_argument("-b", "--blocksize",
92 default=0,
93 type=int,
94 required=False,
95 help="Blocksize: If not 0, the number of frames to take\
96 at each step for the mixer")
97 parser.add_argument("-f", "--frame-rate",
98 default=44100,
99 type=int,
100 required=False,
101 help="Frame rate to play the musics")
102 parser.add_argument("-x", "--channels",
103 default=2,
104 type=int,
105 required=False,
106 help="Number of channels to use")
107 parser.add_argument("-s", "--sample-width",
108 default=2,
109 type=int,
110 required=False,
111 help="Sample width (number of bytes for each frame)")
112 parser.add_argument("-V", "--version",
113 action="version",
114 help="Displays the current version and exits. Only use\
115 in bundled package",
116 version=show_version())
117 parser.add_argument("--device",
118 action=SelectDeviceAction,
119 help="Select this sound device"
120 )
121 parser.add_argument("--list-devices",
122 nargs=0,
123 action=ListDevicesAction,
124 help="List available sound devices"
125 )
126 parser.add_argument('--',
127 dest="args",
128 help="Kivy arguments. All arguments after this are interpreted\
129 by Kivy. Pass \"-- --help\" to get Kivy's usage.")
130
6ebe6247
IB
131 args = parser.parse_args(argv)
132
133 Config.yml_file = args.config
134
135 Config.latency = args.latency
136 Config.blocksize = args.blocksize
137 Config.frame_rate = args.frame_rate
138 Config.channels = args.channels
139 Config.sample_width = args.sample_width
140 Config.builtin_mixing = args.builtin_mixing
141 if args.music_path.endswith("/"):
142 Config.music_path = args.music_path
143 else:
144 Config.music_path = args.music_path + "/"
145
146class DebugModeAction(argparse.Action):
147 def __call__(self, parser, namespace, values, option_string=None):
023d9381 148 sys.argv.extend(["-c", "kivy:log_level:debug"])
6ebe6247
IB
149
150class SelectDeviceAction(argparse.Action):
151 def __call__(self, parser, namespace, values, option_string=None):
152 sd.default.device = values
153
154class ListDevicesAction(argparse.Action):
155 nargs = 0
156 def __call__(self, parser, namespace, values, option_string=None):
157 print(sd.query_devices())
158 sys.exit()
159
160def show_version():
161 if getattr(sys, 'frozen', False):
162 with open(path() + ".pyinstaller_commit", "r") as f:
163 return f.read()
164 else:
165 return "option '-v' can only be used in bundled package"
166
167def duration_to_min_sec(duration):
168 minutes = int(duration / 60)
169 seconds = int(duration) % 60
170 if minutes < 100:
171 return "{:2}:{:0>2}".format(minutes, seconds)
172 else:
173 return "{}:{:0>2}".format(minutes, seconds)
174
175def gain(volume, old_volume=None):
176 if old_volume is None:
177 return 20 * math.log10(max(volume, 0.1) / 100)
178 else:
179 return [
180 20 * math.log10(max(volume, 0.1) / max(old_volume, 0.1)),
181 max(volume, 0)]
182
2010311b
IB
183def debug_print(message, with_trace=None):
184 if with_trace is None:
185 with_trace = (Logger.getEffectiveLevel() < logging.WARN)
186 with_trace &= (sys.exc_info()[0] is not None)
187
6ebe6247
IB
188 Logger.debug('MusicSampler: ' + message, exc_info=with_trace)
189
2010311b
IB
190def error_print(message, exit=False, with_trace=None):
191 if with_trace is None:
192 with_trace = (Logger.getEffectiveLevel() < logging.WARN)
193 with_trace &= (sys.exc_info()[0] is not None)
194
195 # FIXME: handle it correctly when in a thread
196 if exit:
197 Logger.critical('MusicSampler: ' + message, exc_info=with_trace)
198 sys.exit(1)
199 else:
200 Logger.error('MusicSampler: ' + message, exc_info=with_trace)
201
202def warn_print(message, with_trace=None):
203 if with_trace is None:
204 with_trace = (Logger.getEffectiveLevel() < logging.WARN)
205 with_trace &= (sys.exc_info()[0] is not None)
6ebe6247 206
6ebe6247
IB
207 Logger.warn('MusicSampler: ' + message, exc_info=with_trace)
208