return path + "/../"
def parse_args():
- argv = sys.argv[1:]
- sys.argv = sys.argv[:1]
+ argv = sys.argv[1 :]
+ sys.argv = sys.argv[: 1]
if "--" in argv:
index = argv.index("--")
- kivy_args = argv[index+1:]
- argv = argv[:index]
+ kivy_args = argv[index+1 :]
+ argv = argv[: index]
sys.argv.extend(kivy_args)
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)")
+ 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,
default=0,
type=int,
required=False,
- help="Blocksize: If not 0, the numbe of frames to take at each step for the mixer")
+ 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,
help="Sample width (number of bytes for each frame)")
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,
)
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.")
from kivy.logger import Logger
Logger.setLevel(logging.ERROR)
else:
return "{}:{:0>2}".format(minutes, seconds)
-def gain(volume, old_volume = None):
+def gain(volume, old_volume=None):
if old_volume is None:
return 20 * math.log10(volume / 100)
else:
- return [20 * math.log10(max(volume, 0.1) / max(old_volume, 0.1)), max(volume, 0)]
+ return [
+ 20 * math.log10(max(volume, 0.1) / max(old_volume, 0.1)),
+ max(volume, 0)]
def debug_print(message):
from kivy.logger import Logger
return self.mapping.open_files.values()
# Actions
- def command(self, command = "", **kwargs):
+ def command(self, command="", **kwargs):
# FIXME: todo
pass
- def pause(self, music = None, **kwargs):
+ def pause(self, music=None, **kwargs):
for music in self.music_list(music):
if music.is_loaded_playing():
music.pause()
- def unpause(self, music = None, **kwargs):
+ def unpause(self, music=None, **kwargs):
for music in self.music_list(music):
if music.is_loaded_paused():
music.unpause()
- def play(self, music = None, fade_in = 0, start_at = 0,
- restart_if_running = False, volume = 100,
- loop = 0,
- **kwargs):
+ def play(self, music=None, fade_in=0, start_at=0,
+ restart_if_running=False, volume=100,
+ loop=0, **kwargs):
for music in self.music_list(music):
if restart_if_running:
if music.is_not_stopped():
music.stop()
- music.play(volume = volume, fade_in = fade_in, start_at = start_at, loop = loop)
- else:
- if not music.is_not_stopped():
- music.play(volume = volume, fade_in = fade_in, start_at = start_at, loop = loop)
-
- def seek(self, music = None, value = 0, delta = False, **kwargs):
+ music.play(
+ volume=volume,
+ fade_in=fade_in,
+ start_at=start_at,
+ loop=loop)
+ elif not music.is_not_stopped():
+ music.play(
+ volume=volume,
+ fade_in=fade_in,
+ start_at=start_at,
+ loop=loop)
+
+ def seek(self, music=None, value=0, delta=False, **kwargs):
for music in self.music_list(music):
- music.seek(value = value, delta = delta)
+ music.seek(value=value, delta=delta)
- def stop(self, music = None, fade_out = 0, wait = False, **kwargs):
+ def stop(self, music=None, fade_out=0, wait=False, **kwargs):
previous = None
for music in self.music_list(music):
if music.is_loaded_paused() or music.is_loaded_playing():
if previous is not None:
- previous.stop(fade_out = fade_out)
+ previous.stop(fade_out=fade_out)
previous = music
if previous is not None:
- previous.stop(fade_out = fade_out, wait = wait)
+ previous.stop(fade_out=fade_out, wait=wait)
def stop_all_actions(self, **kwargs):
self.mapping.stop_all_running()
- def volume(self, music = None, value = 100, delta = False, **kwargs):
+ def volume(self, music=None, value=100, delta=False, **kwargs):
if music is not None:
- music.set_volume(value, delta = delta)
+ music.set_volume(value, delta=delta)
else:
- self.mapping.set_master_volume(value, delta = delta)
+ self.mapping.set_master_volume(value, delta=delta)
- def wait(self, duration = 0, music = None, **kwargs):
+ def wait(self, duration=0, music=None, **kwargs):
self.sleep_event = threading.Event()
if music is not None:
self.sleep_event.wait()
# Action messages
- def command_print(self, command = "", **kwargs):
+ def command_print(self, command="", **kwargs):
return "running command {}".format(command)
- def pause_print(self, music = None, **kwargs):
+ def pause_print(self, music=None, **kwargs):
if music is not None:
return "pausing « {} »".format(music.name)
else:
return "pausing all musics"
- def unpause_print(self, music = None, **kwargs):
+ def unpause_print(self, music=None, **kwargs):
if music is not None:
return "unpausing « {} »".format(music.name)
else:
return "unpausing all musics"
- def play_print(self, music = None, fade_in = 0, start_at = 0,
- restart_if_running = False, volume = 100, loop = 0, **kwargs):
+ def play_print(self, music=None, fade_in=0, start_at=0,
+ restart_if_running=False, volume=100, loop=0, **kwargs):
message = "starting "
if music is not None:
message += "« {} »".format(music.name)
return message
- def stop_print(self, music = None, fade_out = 0, wait = False, **kwargs):
+ def stop_print(self, music=None, fade_out=0, wait=False, **kwargs):
message = "stopping "
if music is not None:
message += "music « {} »".format(music.name)
def stop_all_actions_print(self, **kwargs):
return "stopping all actions"
- def seek_print(self, music = None, value = 0, delta = False, **kwargs):
+ def seek_print(self, music=None, value=0, delta=False, **kwargs):
if delta:
if music is not None:
- return "moving music « {} » by {:+d}s".format(music.name, value)
+ return "moving music « {} » by {:+d}s" \
+ .format(music.name, value)
else:
- return "moving all musics by {:+d}s".format(value)
+ return "moving all musics by {:+d}s" \
+ .format(value)
else:
if music is not None:
- return "moving music « {} » to position {}s".format(music.name, value)
+ return "moving music « {} » to position {}s" \
+ .format(music.name, value)
else:
- return "moving all musics to position {}s".format(value)
+ return "moving all musics to position {}s" \
+ .format(value)
- def volume_print(self, music = None, value = 100, delta = False, **kwargs):
+ def volume_print(self, music=None, value=100, delta=False, **kwargs):
if delta:
if music is not None:
- return "{:+d}% to volume of « {} »".format(value, music.name)
+ return "{:+d}% to volume of « {} »" \
+ .format(value, music.name)
else:
- return "{:+d}% to volume".format(value)
+ return "{:+d}% to volume" \
+ .format(value)
else:
if music is not None:
- return "setting volume of « {} » to {}%".format(music.name, value)
+ return "setting volume of « {} » to {}%" \
+ .format(music.name, value)
else:
- return "setting volume to {}%".format(value)
+ return "setting volume to {}%" \
+ .format(value)
- def wait_print(self, duration = 0, music = None, **kwargs):
+ def wait_print(self, duration=0, music=None, **kwargs):
if music is None:
- return "waiting {}s".format(duration)
+ return "waiting {}s" \
+ .format(duration)
elif duration == 0:
- return "waiting the end of « {} »".format(music.name)
+ return "waiting the end of « {} »" \
+ .format(music.name)
else:
- return "waiting the end of « {} » + {}s".format(music.name, duration)
+ return "waiting the end of « {} » + {}s" \
+ .format(music.name, duration)
# Interruptions
- def wait_interrupt(self, duration = 0, music = None, **kwargs):
+ def wait_interrupt(self, duration=0, music=None, **kwargs):
if self.sleep_event is not None:
self.sleep_event.set()
if music is not None:
from kivy.uix.widget import Widget
-from kivy.properties import AliasProperty, BooleanProperty, ListProperty, StringProperty
+from kivy.properties import AliasProperty, BooleanProperty, \
+ ListProperty, StringProperty
from kivy.clock import Clock
from kivy.uix.behaviors import ButtonBehavior
def set_description(self, description):
if description[0] is not None:
self.description_title = str(description[0])
- for desc in description[1:]:
+ for desc in description[1 :]:
if desc is None:
self.description.append("")
else:
action_number = 0
for self.current_action in self.actions:
if self.parent.keep_running(self, start_time):
- self.list_actions(action_number = action_number + 0.5)
+ self.list_actions(action_number=action_number + 0.5)
self.current_action.run()
action_number += 1
- self.list_actions(action_number = action_number)
+ self.list_actions(action_number=action_number)
self.parent.finished_running(self, start_time)
- def list_actions(self, action_number = 0):
+ def list_actions(self, action_number=0):
self.parent.parent.ids['ActionList'].update_list(self, action_number)
def on_press(self):
self.list_actions()
- pass
def master_gain(self):
return gain(self.master_volume)
- def set_master_volume(self, value, delta = False):
- [db_gain, self.master_volume] = gain(value + int(delta) * self.master_volume, self.master_volume)
+ def set_master_volume(self, value, delta=False):
+ [db_gain, self.master_volume] = gain(
+ value + int(delta) * self.master_volume,
+ self.master_volume)
+
for music in self.open_files.values():
music.set_gain(db_gain)
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
key = self.find_by_key_code(keycode)
if len(modifiers) == 0 and key is not None:
- threading.Thread(name = "MSKeyAction", target=key.do_actions).start()
+ threading.Thread(name="MSKeyAction", target=key.do_actions).start()
elif 'ctrl' in modifiers and (keycode[0] == 113 or keycode[0] == '99'):
for thread in threading.enumerate():
if thread.getName()[0:2] != "MS":
del(action[action_name]['include'])
if isinstance(included, str):
- action[action_name].update(aliases[included], **action[action_name])
+ action[action_name].update(
+ aliases[included],
+ **action[action_name])
else:
for included_ in included:
- action[action_name].update(aliases[included_], **action[action_name])
+ action[action_name].update(
+ aliases[included_],
+ **action[action_name])
for argument in action[action_name]:
if argument == 'file':
filename)
if filename not in key_properties[mapped_key]['files']:
- key_properties[mapped_key]['files'].append(seen_files[filename])
+ key_properties[mapped_key]['files'] \
+ .append(seen_files[filename])
action_args['music'] = seen_files[filename]
else:
action_args[argument] = action[action_name][argument]
- key_properties[mapped_key]['actions'].append([action_name, action_args])
+ key_properties[mapped_key]['actions'] \
+ .append([action_name, action_args])
return (key_properties, seen_files)
from . import Config
sample_width = Config.sample_width
+
def sample_width_to_dtype(sample_width):
if sample_width == 1 or sample_width == 2 or sample_width == 4:
return 'int' + str(8*sample_width)
class Mixer:
def __init__(self):
- self.stream = sd.RawOutputStream(samplerate=Config.frame_rate,
- channels=Config.channels,
- dtype=sample_width_to_dtype(Config.sample_width),
- latency=_latency(Config.latency),
- blocksize=Config.blocksize,
- callback=self.play_callback,
- )
+ self.stream = sd.RawOutputStream(
+ samplerate=Config.frame_rate,
+ channels=Config.channels,
+ dtype=sample_width_to_dtype(Config.sample_width),
+ latency=_latency(Config.latency),
+ blocksize=Config.blocksize,
+ callback=self.play_callback)
self.open_files = []
def add_file(self, music_file):
file_lock = Lock("file")
class MusicFile(Machine):
- def __init__(self, filename, mapping, name = None, gain = 1):
+ def __init__(self, filename, mapping, name=None, gain=1):
states = [
'initial',
'loading',
'failed',
- { 'name': 'loaded', 'children': ['stopped', 'playing', 'paused', 'stopping'] }
+ {
+ 'name': 'loaded',
+ 'children': ['stopped', 'playing', 'paused', 'stopping']
+ }
]
transitions = [
- { 'trigger': 'load', 'source': 'initial', 'dest': 'loading'},
- { 'trigger': 'fail', 'source': 'loading', 'dest': 'failed'},
- { 'trigger': 'success', 'source': 'loading', 'dest': 'loaded_stopped'},
- { 'trigger': 'start_playing', 'source': 'loaded_stopped', 'dest': 'loaded_playing'},
- { 'trigger': 'pause', 'source': 'loaded_playing', 'dest': 'loaded_paused'},
- { 'trigger': 'unpause', 'source': 'loaded_paused', 'dest': 'loaded_playing'},
- { 'trigger': 'stop_playing', 'source': ['loaded_playing','loaded_paused'], 'dest': 'loaded_stopping'},
- { 'trigger': 'stopped', 'source': 'loaded_stopping', 'dest': 'loaded_stopped', 'after': 'trigger_stopped_events'}
+ {
+ 'trigger': 'load',
+ 'source': 'initial',
+ 'dest': 'loading'
+ },
+ {
+ 'trigger': 'fail',
+ 'source': 'loading',
+ 'dest': 'failed'
+ },
+ {
+ 'trigger': 'success',
+ 'source': 'loading',
+ 'dest': 'loaded_stopped'
+ },
+ {
+ 'trigger': 'start_playing',
+ 'source': 'loaded_stopped',
+ 'dest': 'loaded_playing'
+ },
+ {
+ 'trigger': 'pause',
+ 'source': 'loaded_playing',
+ 'dest': 'loaded_paused'
+ },
+ {
+ 'trigger': 'unpause',
+ 'source': 'loaded_paused',
+ 'dest': 'loaded_playing'
+ },
+ {
+ 'trigger': 'stop_playing',
+ 'source': ['loaded_playing','loaded_paused'],
+ 'dest': 'loaded_stopping'
+ },
+ {
+ 'trigger': 'stopped',
+ 'source': 'loaded_stopping',
+ 'dest': 'loaded_stopped',
+ 'after': 'trigger_stopped_events'
+ }
]
- Machine.__init__(self, states=states, transitions=transitions, initial='initial')
+ Machine.__init__(self, states=states,
+ transitions=transitions, initial='initial')
self.volume = 100
self.mapping = mapping
self.wait_event = threading.Event()
self.db_gain = 0
- threading.Thread(name = "MSMusicLoad", target = self.load).start()
+ threading.Thread(name="MSMusicLoad", target=self.load).start()
def on_enter_loading(self):
with file_lock:
debug_print("Loading « {} »".format(self.name))
self.mixer = self.mapping.mixer or Mixer()
initial_db_gain = gain(self.initial_volume_factor * 100)
- self.audio_segment = pydub.AudioSegment.from_file(self.filename).set_frame_rate(Config.frame_rate).set_channels(Config.channels).set_sample_width(Config.sample_width).apply_gain(initial_db_gain)
+ self.audio_segment = pydub.AudioSegment \
+ .from_file(self.filename) \
+ .set_frame_rate(Config.frame_rate) \
+ .set_channels(Config.channels) \
+ .set_sample_width(Config.sample_width) \
+ .apply_gain(initial_db_gain)
self.audio_segment_frame_width = self.audio_segment.frame_width
self.sound_duration = self.audio_segment.duration_seconds
except Exception as e:
else:
return 0
- def play(self, fade_in = 0, volume = 100, loop = 0, start_at = 0):
+ def play(self, fade_in=0, volume=100, loop=0, start_at=0):
self.db_gain = gain(volume) + self.mapping.master_gain
self.volume = volume
self.loop = loop
self.current_frame = int(start_at * self.audio_segment.frame_rate)
if ms_fi > 0:
# FIXME: apply it to repeated when looping?
- self.a_s_with_effect = self.current_audio_segment[ms:ms+ms_fi].fade_in(ms_fi)
+ self.a_s_with_effect = self \
+ .current_audio_segment[ms : ms+ms_fi] \
+ .fade_in(ms_fi)
self.current_frame_with_effect = 0
else:
self.a_s_with_effect = None
if self.is_loaded_playing() and self.loop != 0:
self.loop -= 1
self.current_frame = 0
- [new_data, new_nb_frames] = self.get_next_sample(frame_count - nb_frames)
+ [new_data, new_nb_frames] = self.get_next_sample(
+ frame_count - nb_frames)
data += new_data
nb_frames += new_nb_frames
elif nb_frames == 0:
# FIXME: too slow
- threading.Thread(name = "MSFinishedCallback", target=self.finished_callback).start()
+ threading.Thread(
+ name="MSFinishedCallback",
+ target=self.finished_callback).start()
return data.ljust(out_data_length, b'\0')
max_val = int(segment.frame_count())
start_i = max(self.current_frame_with_effect, 0)
- end_i = min(self.current_frame_with_effect + frame_count, max_val)
+ end_i = min(self.current_frame_with_effect + frame_count, max_val)
- data += segment._data[(start_i * fw):(end_i * fw)]
+ data += segment._data[start_i*fw : end_i*fw]
- frame_count = max(0, self.current_frame_with_effect + frame_count - max_val)
+ frame_count = max(
+ 0,
+ self.current_frame_with_effect + frame_count - max_val)
self.current_frame_with_effect += end_i - start_i
self.current_frame += end_i - start_i
start_i = max(self.current_frame, 0)
end_i = min(self.current_frame + frame_count, max_val)
- data += segment._data[(start_i * fw):(end_i * fw)]
+ data += segment._data[start_i*fw : end_i*fw]
nb_frames += end_i - start_i
self.current_frame += end_i - start_i
return [data, nb_frames]
- def seek(self, value = 0, delta = False):
+ def seek(self, value=0, delta=False):
# We don't want to do that while stopping
if not (self.is_loaded_playing() or self.is_loaded_paused()):
return
with self.music_lock:
self.a_s_with_effect = None
- self.current_frame = max(0, int(delta) * self.current_frame + int(value * self.audio_segment.frame_rate))
+ self.current_frame = max(
+ 0,
+ int(delta) * self.current_frame
+ + int(value * self.audio_segment.frame_rate))
# FIXME: si on fait un seek + delta, adapter le "loop"
- def stop(self, fade_out = 0, wait = False):
+ def stop(self, fade_out=0, wait=False):
if self.is_loaded_playing():
ms = int(self.sound_position * 1000)
ms_fo = max(1, int(fade_out * 1000))
- new_audio_segment = self.current_audio_segment[:ms + ms_fo].fade_out(ms_fo)
+ new_audio_segment = self.current_audio_segment[: ms+ms_fo] \
+ .fade_out(ms_fo)
with self.music_lock:
self.current_audio_segment = new_audio_segment
self.stop_playing()
self.db_gain += db_gain
self.volume_factor = 10 ** (self.db_gain / 20)
- def set_volume(self, value, delta = False):
- [db_gain, self.volume] = gain(value + int(delta) * self.volume, self.volume)
+ def set_volume(self, value, delta=False):
+ [db_gain, self.volume] = gain(
+ value + int(delta) * self.volume,
+ self.volume)
self.set_gain(db_gain)
text = "{}/{}".format(
helpers.duration_to_min_sec(music_file.sound_position),
- helpers.duration_to_min_sec(music_file.sound_duration)
- )
+ helpers.duration_to_min_sec(music_file.sound_duration))
if music_file.is_paused():
self.playlist.append(["⏸", music_file.name, text, False])
# -*- mode: python -*-
import os
-from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal, hookspath, runtime_hooks
+from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal,\
+ hookspath, runtime_hooks
-excluded_and_hidden_modules = get_deps_minimal(video=None, camera=None, audio=None, clipboard=None, spelling=None)
-excluded_and_hidden_modules['hiddenimports'] += [ 'six', 'packaging', 'packaging.version', 'packaging.specifiers', 'packaging.requirements']
+excluded_and_hidden_modules = get_deps_minimal(
+ video=None,
+ camera=None,
+ audio=None,
+ clipboard=None,
+ spelling=None)
+
+excluded_and_hidden_modules['hiddenimports'] += [
+ 'six',
+ 'packaging',
+ 'packaging.version',
+ 'packaging.specifiers',
+ 'packaging.requirements' ]
commit_message = os.popen('git log -1 --format="%h %ci"').read()
pyinstaller_file = open(".pyinstaller_commit", "w")
pyz = PYZ(a.pure, a.zipped_data)
# Single file
-exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name='music_sampler')
+exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas,
+ name='music_sampler')
# Directory
-# exe = EXE(pyz, a.scripts, exclude_binaries=True, name='music_sampler_dir', debug=False, strip=False, upx=True, console=True )
-# coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name='music_sampler_dir')
+# exe = EXE(pyz, a.scripts,
+# exclude_binaries=True,
+# name='music_sampler_dir',
+# debug=False,
+# strip=False,
+# upx=True,
+# console=True)
+# coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas,
+# strip=False,
+# upx=True,
+# name='music_sampler_dir')