]>
git.immae.eu Git - perso/Immae/Projets/Python/MusicSampler.git/blob - helpers.py
9eb1a950ca50fb8028e7b52dd1d601f0d2a908f7
1 # -*- coding: utf-8 -*-
6 import sounddevice
as sd
10 gettext
.install('music_sampler')
11 Logger
= logging
.getLogger("kivy")
18 def find_font(name
, style
=sysfont
.STYLE_NONE
):
19 if getattr(sys
, 'frozen', False):
20 font
= sys
._MEIPASS
+ "/fonts/{}_{}.ttf".format(name
, style
)
22 font
= sysfont
.get_font(name
, style
=style
)
28 from kivy
.core
.text
import LabelBase
30 ubuntu_regular
= find_font("Ubuntu", style
=sysfont
.STYLE_NORMAL
)
31 ubuntu_bold
= find_font("Ubuntu", style
=sysfont
.STYLE_BOLD
)
32 symbola
= find_font("Symbola")
34 if ubuntu_regular
is None:
35 error_print("Font Ubuntu regular could not be found, "
36 "please install it.", exit
=True)
38 error_print("Font Symbola could not be found, please install it.",
40 if ubuntu_bold
is None:
41 warn_print("Font Ubuntu Bold could not be found.")
43 LabelBase
.register(name
="Ubuntu",
44 fn_regular
=ubuntu_regular
,
46 LabelBase
.register(name
="Symbola",
51 if getattr(sys
, 'frozen', False):
52 return sys
._MEIPASS
+ "/"
54 return os
.path
.dirname(os
.path
.realpath(__file__
))
61 'help': _("Folder in which to find the music files"),
67 'help': _("Latency: low, high or number of seconds"),
73 'help': _("Select another language"),
79 'help': _("Select this sound device"),
85 'help': _("Blocksize: If not 0, the number of frames to take\
86 at each step for the mixer"),
92 'help': _("Frame rate to play the musics"),
98 'help': _("Number of channels to use"),
104 'help': _("Sample width (number of bytes for each frame)"),
109 'help_yes': _("Make the mixing of sounds manually\
110 (do it if the system cannot handle it correctly)"),
111 'help_no': _("Don't make the mixing of sounds manually (default)"),
117 'help_yes': _("Print messages in console"),
118 'help_no': _("Don't print messages in console (default)"),
123 'help_yes': _("Show a warning when focus is lost (default)"),
124 'help_no': _("Don't show warning when focus is lost"),
129 'help_yes': _("Load all the musics at launch time (default)"),
130 'help_no': _("Don't load all the musics at launch time (use it if you \
131 have memory problems)"),
135 'help': _("List available sound devices"),
156 sys
.argv
= sys
.argv
[: 1]
158 index
= argv
.index("--")
159 kivy_args
= argv
[index
+1 :]
162 sys
.argv
.extend(kivy_args
)
164 os
.environ
["KIVY_NO_CONFIG"] = 'true'
165 sys
.argv
.extend(["-c", "kivy:log_level:warning"])
166 sys
.argv
.extend(["-c", "kivy:log_dir:/tmp"])
167 sys
.argv
.extend(["-c", "kivy:log_name:/tmp/music_sampler_%_.txt"])
169 parser
= argparse
.ArgumentParser(
170 argument_default
=argparse
.SUPPRESS
,
171 description
=_("A Music Sampler application."))
172 parser
.add_argument("-V", "--version",
174 help=_("Displays the current version and exits. Only use\
175 in bundled package"),
176 version
=show_version())
177 parser
.add_argument("-c", "--config",
178 default
="config.yml",
180 help=_("Config file to load (default: config.yml)"))
181 for argument
in Configs_order
:
182 arg
= Configs
[argument
]
183 if arg
['type'] != 'boolean' and arg
['type'] != 'action':
184 parser
.add_argument(arg
['abbr'], '--' + argument
.replace('_', '-'),
186 help=arg
['help']+_(" (default: {})").format(arg
['default']))
187 elif arg
['type'] == 'boolean':
188 parser
.add_argument('--' + argument
.replace('_', '-'),
189 action
='store_const', const
=True,
190 help=arg
['help_yes'])
191 parser
.add_argument('--no-' + argument
.replace('_', '-'),
192 action
='store_const', const
=True,
195 parser
.add_argument('--' + argument
.replace('_', '-'),
196 action
='store_const', const
=True,
198 parser
.add_argument('--',
200 help=_("Kivy arguments. All arguments after this are interpreted\
201 by Kivy. Pass \"-- --help\" to get Kivy's usage."))
203 args
= parser
.parse_args(argv
)
205 Config
.yml_file
= args
.config
208 if Config
.device
is not None:
209 sd
.default
.device
= Config
.device
211 if Config
.list_devices
:
212 print(sd
.query_devices())
216 sys
.argv
.extend(["-c", "kivy:log_level:debug"])
218 if Config
.language
!= 'en':
219 gettext
.translation("music_sampler",
220 localedir
=path() + '/locales',
221 languages
=[Config
.language
]).install()
222 if not Config
.music_path
.endswith("/"):
223 Config
.music_path
= Config
.music_path
+ "/"
226 max_size
= max(max(map(len, Configs_order
)), len('config'))
227 info_print("{:<{}} : {}".format(
228 "config", max_size
, Config
.yml_file
))
229 for item
in Config
.__dict
__:
230 if item
in Configs_order
:
231 info_print("{:<{}} : {}".format(
232 item
, max_size
, getattr(Config
, item
)))
234 def build_config(args
):
235 stream
= open(Config
.yml_file
, "r", encoding
='utf8')
237 config
= yaml
.safe_load(stream
)
238 except Exception as e
:
239 error_print("Error while loading config file: {}".format(e
))
242 if 'config' in config
:
243 config
= config
['config']
247 for config_item
in Configs_order
:
248 if Configs
[config_item
]['type'] != 'boolean' and \
249 Configs
[config_item
]['type'] != 'action':
250 t
= Configs
[config_item
]['type'] or str
251 if hasattr(args
, config_item
):
252 setattr(Config
, config_item
, getattr(args
, config_item
))
253 elif config_item
in config
:
254 setattr(Config
, config_item
, t(config
[config_item
]))
256 setattr(Config
, config_item
, Configs
[config_item
]['default'])
257 elif Configs
[config_item
]['type'] == 'boolean':
258 if hasattr(args
, 'no_' + config_item
) or hasattr(args
, config_item
):
259 setattr(Config
, config_item
, hasattr(args
, config_item
))
260 elif config_item
in config
:
261 setattr(Config
, config_item
, config
[config_item
])
263 setattr(Config
, config_item
, Configs
[config_item
]['default'])
265 setattr(Config
, config_item
, hasattr(args
, config_item
))
269 if getattr(sys
, 'frozen', False):
270 with open(path() + ".pyinstaller_commit", "r") as f
:
273 return _("option '-V' can only be used in bundled package")
275 def duration_to_min_sec(duration
):
276 minutes
= int(duration
/ 60)
277 seconds
= int(duration
) % 60
279 return "{:2}:{:0>2}".format(minutes
, seconds
)
281 return "{}:{:0>2}".format(minutes
, seconds
)
283 def gain(volume
, old_volume
=None):
284 if old_volume
is None:
285 return 20 * math
.log10(max(volume
, 0.1) / 100)
288 20 * math
.log10(max(volume
, 0.1) / max(old_volume
, 0.1)),
291 def debug_print(message
, with_trace
=None):
292 if with_trace
is None:
293 with_trace
= (Logger
.getEffectiveLevel() < logging
.WARN
)
294 with_trace
&= (sys
.exc_info()[0] is not None)
296 Logger
.debug('MusicSampler: ' + message
, exc_info
=with_trace
)
298 def error_print(message
, exit
=False, with_trace
=None):
299 if with_trace
is None:
300 with_trace
= (Logger
.getEffectiveLevel() < logging
.WARN
)
301 with_trace
&= (sys
.exc_info()[0] is not None)
303 # FIXME: handle it correctly when in a thread
305 Logger
.critical('MusicSampler: ' + message
, exc_info
=with_trace
)
308 Logger
.error('MusicSampler: ' + message
, exc_info
=with_trace
)
310 def warn_print(message
, with_trace
=None):
311 if with_trace
is None:
312 with_trace
= (Logger
.getEffectiveLevel() < logging
.WARN
)
313 with_trace
&= (sys
.exc_info()[0] is not None)
315 Logger
.warn('MusicSampler: ' + message
, exc_info
=with_trace
)
317 def info_print(message
, with_trace
=None):
318 if with_trace
is None:
319 with_trace
= (Logger
.getEffectiveLevel() < logging
.WARN
)
320 with_trace
&= (sys
.exc_info()[0] is not None)
322 Logger
.info('MusicSampler: ' + message
, exc_info
=with_trace
)