aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helpers/__init__.py26
-rw-r--r--helpers/action.py101
-rw-r--r--helpers/key.py12
-rw-r--r--helpers/mapping.py23
-rw-r--r--helpers/mixer.py15
-rw-r--r--helpers/music_file.py109
-rw-r--r--music_sampler.py3
-rw-r--r--music_sampler.spec34
8 files changed, 216 insertions, 107 deletions
diff --git a/helpers/__init__.py b/helpers/__init__.py
index da447d8..9d66638 100644
--- a/helpers/__init__.py
+++ b/helpers/__init__.py
@@ -17,12 +17,12 @@ def path():
17 return path + "/../" 17 return path + "/../"
18 18
19def parse_args(): 19def parse_args():
20 argv = sys.argv[1:] 20 argv = sys.argv[1 :]
21 sys.argv = sys.argv[:1] 21 sys.argv = sys.argv[: 1]
22 if "--" in argv: 22 if "--" in argv:
23 index = argv.index("--") 23 index = argv.index("--")
24 kivy_args = argv[index+1:] 24 kivy_args = argv[index+1 :]
25 argv = argv[:index] 25 argv = argv[: index]
26 26
27 sys.argv.extend(kivy_args) 27 sys.argv.extend(kivy_args)
28 28
@@ -39,7 +39,8 @@ def parse_args():
39 help="Print messages in console") 39 help="Print messages in console")
40 parser.add_argument("-m", "--builtin-mixing", 40 parser.add_argument("-m", "--builtin-mixing",
41 action="store_true", 41 action="store_true",
42 help="Make the mixing of sounds manually (do it if the system cannot handle it correctly)") 42 help="Make the mixing of sounds manually\
43 (do it if the system cannot handle it correctly)")
43 parser.add_argument("-l", "--latency", 44 parser.add_argument("-l", "--latency",
44 default="high", 45 default="high",
45 required=False, 46 required=False,
@@ -48,7 +49,8 @@ def parse_args():
48 default=0, 49 default=0,
49 type=int, 50 type=int,
50 required=False, 51 required=False,
51 help="Blocksize: If not 0, the numbe of frames to take at each step for the mixer") 52 help="Blocksize: If not 0, the number of frames to take\
53 at each step for the mixer")
52 parser.add_argument("-f", "--frame-rate", 54 parser.add_argument("-f", "--frame-rate",
53 default=44100, 55 default=44100,
54 type=int, 56 type=int,
@@ -66,7 +68,8 @@ def parse_args():
66 help="Sample width (number of bytes for each frame)") 68 help="Sample width (number of bytes for each frame)")
67 parser.add_argument("-V", "--version", 69 parser.add_argument("-V", "--version",
68 action="version", 70 action="version",
69 help="Displays the current version and exits. Only use in bundled package", 71 help="Displays the current version and exits. Only use\
72 in bundled package",
70 version=show_version()) 73 version=show_version())
71 parser.add_argument("--device", 74 parser.add_argument("--device",
72 action=SelectDeviceAction, 75 action=SelectDeviceAction,
@@ -79,7 +82,8 @@ def parse_args():
79 ) 82 )
80 parser.add_argument('--', 83 parser.add_argument('--',
81 dest="args", 84 dest="args",
82 help="Kivy arguments. All arguments after this are interpreted by Kivy. Pass \"-- --help\" to get Kivy's usage.") 85 help="Kivy arguments. All arguments after this are interpreted\
86 by Kivy. Pass \"-- --help\" to get Kivy's usage.")
83 87
84 from kivy.logger import Logger 88 from kivy.logger import Logger
85 Logger.setLevel(logging.ERROR) 89 Logger.setLevel(logging.ERROR)
@@ -125,11 +129,13 @@ def duration_to_min_sec(duration):
125 else: 129 else:
126 return "{}:{:0>2}".format(minutes, seconds) 130 return "{}:{:0>2}".format(minutes, seconds)
127 131
128def gain(volume, old_volume = None): 132def gain(volume, old_volume=None):
129 if old_volume is None: 133 if old_volume is None:
130 return 20 * math.log10(volume / 100) 134 return 20 * math.log10(volume / 100)
131 else: 135 else:
132 return [20 * math.log10(max(volume, 0.1) / max(old_volume, 0.1)), max(volume, 0)] 136 return [
137 20 * math.log10(max(volume, 0.1) / max(old_volume, 0.1)),
138 max(volume, 0)]
133 139
134def debug_print(message): 140def debug_print(message):
135 from kivy.logger import Logger 141 from kivy.logger import Logger
diff --git a/helpers/action.py b/helpers/action.py
index 1a2abe2..218c316 100644
--- a/helpers/action.py
+++ b/helpers/action.py
@@ -51,58 +51,64 @@ class Action:
51 return self.mapping.open_files.values() 51 return self.mapping.open_files.values()
52 52
53 # Actions 53 # Actions
54 def command(self, command = "", **kwargs): 54 def command(self, command="", **kwargs):
55 # FIXME: todo 55 # FIXME: todo
56 pass 56 pass
57 57
58 def pause(self, music = None, **kwargs): 58 def pause(self, music=None, **kwargs):
59 for music in self.music_list(music): 59 for music in self.music_list(music):
60 if music.is_loaded_playing(): 60 if music.is_loaded_playing():
61 music.pause() 61 music.pause()
62 62
63 def unpause(self, music = None, **kwargs): 63 def unpause(self, music=None, **kwargs):
64 for music in self.music_list(music): 64 for music in self.music_list(music):
65 if music.is_loaded_paused(): 65 if music.is_loaded_paused():
66 music.unpause() 66 music.unpause()
67 67
68 def play(self, music = None, fade_in = 0, start_at = 0, 68 def play(self, music=None, fade_in=0, start_at=0,
69 restart_if_running = False, volume = 100, 69 restart_if_running=False, volume=100,
70 loop = 0, 70 loop=0, **kwargs):
71 **kwargs):
72 for music in self.music_list(music): 71 for music in self.music_list(music):
73 if restart_if_running: 72 if restart_if_running:
74 if music.is_not_stopped(): 73 if music.is_not_stopped():
75 music.stop() 74 music.stop()
76 music.play(volume = volume, fade_in = fade_in, start_at = start_at, loop = loop) 75 music.play(
77 else: 76 volume=volume,
78 if not music.is_not_stopped(): 77 fade_in=fade_in,
79 music.play(volume = volume, fade_in = fade_in, start_at = start_at, loop = loop) 78 start_at=start_at,
80 79 loop=loop)
81 def seek(self, music = None, value = 0, delta = False, **kwargs): 80 elif not music.is_not_stopped():
81 music.play(
82 volume=volume,
83 fade_in=fade_in,
84 start_at=start_at,
85 loop=loop)
86
87 def seek(self, music=None, value=0, delta=False, **kwargs):
82 for music in self.music_list(music): 88 for music in self.music_list(music):
83 music.seek(value = value, delta = delta) 89 music.seek(value=value, delta=delta)
84 90
85 def stop(self, music = None, fade_out = 0, wait = False, **kwargs): 91 def stop(self, music=None, fade_out=0, wait=False, **kwargs):
86 previous = None 92 previous = None
87 for music in self.music_list(music): 93 for music in self.music_list(music):
88 if music.is_loaded_paused() or music.is_loaded_playing(): 94 if music.is_loaded_paused() or music.is_loaded_playing():
89 if previous is not None: 95 if previous is not None:
90 previous.stop(fade_out = fade_out) 96 previous.stop(fade_out=fade_out)
91 previous = music 97 previous = music
92 98
93 if previous is not None: 99 if previous is not None:
94 previous.stop(fade_out = fade_out, wait = wait) 100 previous.stop(fade_out=fade_out, wait=wait)
95 101
96 def stop_all_actions(self, **kwargs): 102 def stop_all_actions(self, **kwargs):
97 self.mapping.stop_all_running() 103 self.mapping.stop_all_running()
98 104
99 def volume(self, music = None, value = 100, delta = False, **kwargs): 105 def volume(self, music=None, value=100, delta=False, **kwargs):
100 if music is not None: 106 if music is not None:
101 music.set_volume(value, delta = delta) 107 music.set_volume(value, delta=delta)
102 else: 108 else:
103 self.mapping.set_master_volume(value, delta = delta) 109 self.mapping.set_master_volume(value, delta=delta)
104 110
105 def wait(self, duration = 0, music = None, **kwargs): 111 def wait(self, duration=0, music=None, **kwargs):
106 self.sleep_event = threading.Event() 112 self.sleep_event = threading.Event()
107 113
108 if music is not None: 114 if music is not None:
@@ -112,23 +118,23 @@ class Action:
112 self.sleep_event.wait() 118 self.sleep_event.wait()
113 119
114 # Action messages 120 # Action messages
115 def command_print(self, command = "", **kwargs): 121 def command_print(self, command="", **kwargs):
116 return "running command {}".format(command) 122 return "running command {}".format(command)
117 123
118 def pause_print(self, music = None, **kwargs): 124 def pause_print(self, music=None, **kwargs):
119 if music is not None: 125 if music is not None:
120 return "pausing « {} »".format(music.name) 126 return "pausing « {} »".format(music.name)
121 else: 127 else:
122 return "pausing all musics" 128 return "pausing all musics"
123 129
124 def unpause_print(self, music = None, **kwargs): 130 def unpause_print(self, music=None, **kwargs):
125 if music is not None: 131 if music is not None:
126 return "unpausing « {} »".format(music.name) 132 return "unpausing « {} »".format(music.name)
127 else: 133 else:
128 return "unpausing all musics" 134 return "unpausing all musics"
129 135
130 def play_print(self, music = None, fade_in = 0, start_at = 0, 136 def play_print(self, music=None, fade_in=0, start_at=0,
131 restart_if_running = False, volume = 100, loop = 0, **kwargs): 137 restart_if_running=False, volume=100, loop=0, **kwargs):
132 message = "starting " 138 message = "starting "
133 if music is not None: 139 if music is not None:
134 message += "« {} »".format(music.name) 140 message += "« {} »".format(music.name)
@@ -153,7 +159,7 @@ class Action:
153 159
154 return message 160 return message
155 161
156 def stop_print(self, music = None, fade_out = 0, wait = False, **kwargs): 162 def stop_print(self, music=None, fade_out=0, wait=False, **kwargs):
157 message = "stopping " 163 message = "stopping "
158 if music is not None: 164 if music is not None:
159 message += "music « {} »".format(music.name) 165 message += "music « {} »".format(music.name)
@@ -170,41 +176,52 @@ class Action:
170 def stop_all_actions_print(self, **kwargs): 176 def stop_all_actions_print(self, **kwargs):
171 return "stopping all actions" 177 return "stopping all actions"
172 178
173 def seek_print(self, music = None, value = 0, delta = False, **kwargs): 179 def seek_print(self, music=None, value=0, delta=False, **kwargs):
174 if delta: 180 if delta:
175 if music is not None: 181 if music is not None:
176 return "moving music « {} » by {:+d}s".format(music.name, value) 182 return "moving music « {} » by {:+d}s" \
183 .format(music.name, value)
177 else: 184 else:
178 return "moving all musics by {:+d}s".format(value) 185 return "moving all musics by {:+d}s" \
186 .format(value)
179 else: 187 else:
180 if music is not None: 188 if music is not None:
181 return "moving music « {} » to position {}s".format(music.name, value) 189 return "moving music « {} » to position {}s" \
190 .format(music.name, value)
182 else: 191 else:
183 return "moving all musics to position {}s".format(value) 192 return "moving all musics to position {}s" \
193 .format(value)
184 194
185 def volume_print(self, music = None, value = 100, delta = False, **kwargs): 195 def volume_print(self, music=None, value=100, delta=False, **kwargs):
186 if delta: 196 if delta:
187 if music is not None: 197 if music is not None:
188 return "{:+d}% to volume of « {} »".format(value, music.name) 198 return "{:+d}% to volume of « {} »" \
199 .format(value, music.name)
189 else: 200 else:
190 return "{:+d}% to volume".format(value) 201 return "{:+d}% to volume" \
202 .format(value)
191 else: 203 else:
192 if music is not None: 204 if music is not None:
193 return "setting volume of « {} » to {}%".format(music.name, value) 205 return "setting volume of « {} » to {}%" \
206 .format(music.name, value)
194 else: 207 else:
195 return "setting volume to {}%".format(value) 208 return "setting volume to {}%" \
209 .format(value)
196 210
197 def wait_print(self, duration = 0, music = None, **kwargs): 211 def wait_print(self, duration=0, music=None, **kwargs):
198 if music is None: 212 if music is None:
199 return "waiting {}s".format(duration) 213 return "waiting {}s" \
214 .format(duration)
200 elif duration == 0: 215 elif duration == 0:
201 return "waiting the end of « {} »".format(music.name) 216 return "waiting the end of « {} »" \
217 .format(music.name)
202 else: 218 else:
203 return "waiting the end of « {} » + {}s".format(music.name, duration) 219 return "waiting the end of « {} » + {}s" \
220 .format(music.name, duration)
204 221
205 222
206 # Interruptions 223 # Interruptions
207 def wait_interrupt(self, duration = 0, music = None, **kwargs): 224 def wait_interrupt(self, duration=0, music=None, **kwargs):
208 if self.sleep_event is not None: 225 if self.sleep_event is not None:
209 self.sleep_event.set() 226 self.sleep_event.set()
210 if music is not None: 227 if music is not None:
diff --git a/helpers/key.py b/helpers/key.py
index fe82d5b..34c5140 100644
--- a/helpers/key.py
+++ b/helpers/key.py
@@ -1,5 +1,6 @@
1from kivy.uix.widget import Widget 1from kivy.uix.widget import Widget
2from kivy.properties import AliasProperty, BooleanProperty, ListProperty, StringProperty 2from kivy.properties import AliasProperty, BooleanProperty, \
3 ListProperty, StringProperty
3from kivy.clock import Clock 4from kivy.clock import Clock
4from kivy.uix.behaviors import ButtonBehavior 5from kivy.uix.behaviors import ButtonBehavior
5 6
@@ -56,7 +57,7 @@ class Key(ButtonBehavior, Widget):
56 def set_description(self, description): 57 def set_description(self, description):
57 if description[0] is not None: 58 if description[0] is not None:
58 self.description_title = str(description[0]) 59 self.description_title = str(description[0])
59 for desc in description[1:]: 60 for desc in description[1 :]:
60 if desc is None: 61 if desc is None:
61 self.description.append("") 62 self.description.append("")
62 else: 63 else:
@@ -94,16 +95,15 @@ class Key(ButtonBehavior, Widget):
94 action_number = 0 95 action_number = 0
95 for self.current_action in self.actions: 96 for self.current_action in self.actions:
96 if self.parent.keep_running(self, start_time): 97 if self.parent.keep_running(self, start_time):
97 self.list_actions(action_number = action_number + 0.5) 98 self.list_actions(action_number=action_number + 0.5)
98 self.current_action.run() 99 self.current_action.run()
99 action_number += 1 100 action_number += 1
100 self.list_actions(action_number = action_number) 101 self.list_actions(action_number=action_number)
101 102
102 self.parent.finished_running(self, start_time) 103 self.parent.finished_running(self, start_time)
103 104
104 def list_actions(self, action_number = 0): 105 def list_actions(self, action_number=0):
105 self.parent.parent.ids['ActionList'].update_list(self, action_number) 106 self.parent.parent.ids['ActionList'].update_list(self, action_number)
106 107
107 def on_press(self): 108 def on_press(self):
108 self.list_actions() 109 self.list_actions()
109 pass
diff --git a/helpers/mapping.py b/helpers/mapping.py
index bc8ccba..858fe77 100644
--- a/helpers/mapping.py
+++ b/helpers/mapping.py
@@ -32,8 +32,11 @@ class Mapping(RelativeLayout):
32 def master_gain(self): 32 def master_gain(self):
33 return gain(self.master_volume) 33 return gain(self.master_volume)
34 34
35 def set_master_volume(self, value, delta = False): 35 def set_master_volume(self, value, delta=False):
36 [db_gain, self.master_volume] = gain(value + int(delta) * self.master_volume, self.master_volume) 36 [db_gain, self.master_volume] = gain(
37 value + int(delta) * self.master_volume,
38 self.master_volume)
39
37 for music in self.open_files.values(): 40 for music in self.open_files.values():
38 music.set_gain(db_gain) 41 music.set_gain(db_gain)
39 42
@@ -44,7 +47,7 @@ class Mapping(RelativeLayout):
44 def _on_keyboard_down(self, keyboard, keycode, text, modifiers): 47 def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
45 key = self.find_by_key_code(keycode) 48 key = self.find_by_key_code(keycode)
46 if len(modifiers) == 0 and key is not None: 49 if len(modifiers) == 0 and key is not None:
47 threading.Thread(name = "MSKeyAction", target=key.do_actions).start() 50 threading.Thread(name="MSKeyAction", target=key.do_actions).start()
48 elif 'ctrl' in modifiers and (keycode[0] == 113 or keycode[0] == '99'): 51 elif 'ctrl' in modifiers and (keycode[0] == 113 or keycode[0] == '99'):
49 for thread in threading.enumerate(): 52 for thread in threading.enumerate():
50 if thread.getName()[0:2] != "MS": 53 if thread.getName()[0:2] != "MS":
@@ -131,10 +134,14 @@ class Mapping(RelativeLayout):
131 del(action[action_name]['include']) 134 del(action[action_name]['include'])
132 135
133 if isinstance(included, str): 136 if isinstance(included, str):
134 action[action_name].update(aliases[included], **action[action_name]) 137 action[action_name].update(
138 aliases[included],
139 **action[action_name])
135 else: 140 else:
136 for included_ in included: 141 for included_ in included:
137 action[action_name].update(aliases[included_], **action[action_name]) 142 action[action_name].update(
143 aliases[included_],
144 **action[action_name])
138 145
139 for argument in action[action_name]: 146 for argument in action[action_name]:
140 if argument == 'file': 147 if argument == 'file':
@@ -151,14 +158,16 @@ class Mapping(RelativeLayout):
151 filename) 158 filename)
152 159
153 if filename not in key_properties[mapped_key]['files']: 160 if filename not in key_properties[mapped_key]['files']:
154 key_properties[mapped_key]['files'].append(seen_files[filename]) 161 key_properties[mapped_key]['files'] \
162 .append(seen_files[filename])
155 163
156 action_args['music'] = seen_files[filename] 164 action_args['music'] = seen_files[filename]
157 165
158 else: 166 else:
159 action_args[argument] = action[action_name][argument] 167 action_args[argument] = action[action_name][argument]
160 168
161 key_properties[mapped_key]['actions'].append([action_name, action_args]) 169 key_properties[mapped_key]['actions'] \
170 .append([action_name, action_args])
162 171
163 return (key_properties, seen_files) 172 return (key_properties, seen_files)
164 173
diff --git a/helpers/mixer.py b/helpers/mixer.py
index d08520a..1d3f28f 100644
--- a/helpers/mixer.py
+++ b/helpers/mixer.py
@@ -5,6 +5,7 @@ import time
5from . import Config 5from . import Config
6 6
7sample_width = Config.sample_width 7sample_width = Config.sample_width
8
8def sample_width_to_dtype(sample_width): 9def sample_width_to_dtype(sample_width):
9 if sample_width == 1 or sample_width == 2 or sample_width == 4: 10 if sample_width == 1 or sample_width == 2 or sample_width == 4:
10 return 'int' + str(8*sample_width) 11 return 'int' + str(8*sample_width)
@@ -19,13 +20,13 @@ def _latency(latency):
19 20
20class Mixer: 21class Mixer:
21 def __init__(self): 22 def __init__(self):
22 self.stream = sd.RawOutputStream(samplerate=Config.frame_rate, 23 self.stream = sd.RawOutputStream(
23 channels=Config.channels, 24 samplerate=Config.frame_rate,
24 dtype=sample_width_to_dtype(Config.sample_width), 25 channels=Config.channels,
25 latency=_latency(Config.latency), 26 dtype=sample_width_to_dtype(Config.sample_width),
26 blocksize=Config.blocksize, 27 latency=_latency(Config.latency),
27 callback=self.play_callback, 28 blocksize=Config.blocksize,
28 ) 29 callback=self.play_callback)
29 self.open_files = [] 30 self.open_files = []
30 31
31 def add_file(self, music_file): 32 def add_file(self, music_file):
diff --git a/helpers/music_file.py b/helpers/music_file.py
index 56060bd..54a3fdc 100644
--- a/helpers/music_file.py
+++ b/helpers/music_file.py
@@ -14,25 +14,62 @@ from .mixer import Mixer
14file_lock = Lock("file") 14file_lock = Lock("file")
15 15
16class MusicFile(Machine): 16class MusicFile(Machine):
17 def __init__(self, filename, mapping, name = None, gain = 1): 17 def __init__(self, filename, mapping, name=None, gain=1):
18 states = [ 18 states = [
19 'initial', 19 'initial',
20 'loading', 20 'loading',
21 'failed', 21 'failed',
22 { 'name': 'loaded', 'children': ['stopped', 'playing', 'paused', 'stopping'] } 22 {
23 'name': 'loaded',
24 'children': ['stopped', 'playing', 'paused', 'stopping']
25 }
23 ] 26 ]
24 transitions = [ 27 transitions = [
25 { 'trigger': 'load', 'source': 'initial', 'dest': 'loading'}, 28 {
26 { 'trigger': 'fail', 'source': 'loading', 'dest': 'failed'}, 29 'trigger': 'load',
27 { 'trigger': 'success', 'source': 'loading', 'dest': 'loaded_stopped'}, 30 'source': 'initial',
28 { 'trigger': 'start_playing', 'source': 'loaded_stopped', 'dest': 'loaded_playing'}, 31 'dest': 'loading'
29 { 'trigger': 'pause', 'source': 'loaded_playing', 'dest': 'loaded_paused'}, 32 },
30 { 'trigger': 'unpause', 'source': 'loaded_paused', 'dest': 'loaded_playing'}, 33 {
31 { 'trigger': 'stop_playing', 'source': ['loaded_playing','loaded_paused'], 'dest': 'loaded_stopping'}, 34 'trigger': 'fail',
32 { 'trigger': 'stopped', 'source': 'loaded_stopping', 'dest': 'loaded_stopped', 'after': 'trigger_stopped_events'} 35 'source': 'loading',
36 'dest': 'failed'
37 },
38 {
39 'trigger': 'success',
40 'source': 'loading',
41 'dest': 'loaded_stopped'
42 },
43 {
44 'trigger': 'start_playing',
45 'source': 'loaded_stopped',
46 'dest': 'loaded_playing'
47 },
48 {
49 'trigger': 'pause',
50 'source': 'loaded_playing',
51 'dest': 'loaded_paused'
52 },
53 {
54 'trigger': 'unpause',
55 'source': 'loaded_paused',
56 'dest': 'loaded_playing'
57 },
58 {
59 'trigger': 'stop_playing',
60 'source': ['loaded_playing','loaded_paused'],
61 'dest': 'loaded_stopping'
62 },
63 {
64 'trigger': 'stopped',
65 'source': 'loaded_stopping',
66 'dest': 'loaded_stopped',
67 'after': 'trigger_stopped_events'
68 }
33 ] 69 ]
34 70
35 Machine.__init__(self, states=states, transitions=transitions, initial='initial') 71 Machine.__init__(self, states=states,
72 transitions=transitions, initial='initial')
36 73
37 self.volume = 100 74 self.volume = 100
38 self.mapping = mapping 75 self.mapping = mapping
@@ -45,7 +82,7 @@ class MusicFile(Machine):
45 self.wait_event = threading.Event() 82 self.wait_event = threading.Event()
46 self.db_gain = 0 83 self.db_gain = 0
47 84
48 threading.Thread(name = "MSMusicLoad", target = self.load).start() 85 threading.Thread(name="MSMusicLoad", target=self.load).start()
49 86
50 def on_enter_loading(self): 87 def on_enter_loading(self):
51 with file_lock: 88 with file_lock:
@@ -53,7 +90,12 @@ class MusicFile(Machine):
53 debug_print("Loading « {} »".format(self.name)) 90 debug_print("Loading « {} »".format(self.name))
54 self.mixer = self.mapping.mixer or Mixer() 91 self.mixer = self.mapping.mixer or Mixer()
55 initial_db_gain = gain(self.initial_volume_factor * 100) 92 initial_db_gain = gain(self.initial_volume_factor * 100)
56 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) 93 self.audio_segment = pydub.AudioSegment \
94 .from_file(self.filename) \
95 .set_frame_rate(Config.frame_rate) \
96 .set_channels(Config.channels) \
97 .set_sample_width(Config.sample_width) \
98 .apply_gain(initial_db_gain)
57 self.audio_segment_frame_width = self.audio_segment.frame_width 99 self.audio_segment_frame_width = self.audio_segment.frame_width
58 self.sound_duration = self.audio_segment.duration_seconds 100 self.sound_duration = self.audio_segment.duration_seconds
59 except Exception as e: 101 except Exception as e:
@@ -80,7 +122,7 @@ class MusicFile(Machine):
80 else: 122 else:
81 return 0 123 return 0
82 124
83 def play(self, fade_in = 0, volume = 100, loop = 0, start_at = 0): 125 def play(self, fade_in=0, volume=100, loop=0, start_at=0):
84 self.db_gain = gain(volume) + self.mapping.master_gain 126 self.db_gain = gain(volume) + self.mapping.master_gain
85 self.volume = volume 127 self.volume = volume
86 self.loop = loop 128 self.loop = loop
@@ -92,7 +134,9 @@ class MusicFile(Machine):
92 self.current_frame = int(start_at * self.audio_segment.frame_rate) 134 self.current_frame = int(start_at * self.audio_segment.frame_rate)
93 if ms_fi > 0: 135 if ms_fi > 0:
94 # FIXME: apply it to repeated when looping? 136 # FIXME: apply it to repeated when looping?
95 self.a_s_with_effect = self.current_audio_segment[ms:ms+ms_fi].fade_in(ms_fi) 137 self.a_s_with_effect = self \
138 .current_audio_segment[ms : ms+ms_fi] \
139 .fade_in(ms_fi)
96 self.current_frame_with_effect = 0 140 self.current_frame_with_effect = 0
97 else: 141 else:
98 self.a_s_with_effect = None 142 self.a_s_with_effect = None
@@ -122,12 +166,15 @@ class MusicFile(Machine):
122 if self.is_loaded_playing() and self.loop != 0: 166 if self.is_loaded_playing() and self.loop != 0:
123 self.loop -= 1 167 self.loop -= 1
124 self.current_frame = 0 168 self.current_frame = 0
125 [new_data, new_nb_frames] = self.get_next_sample(frame_count - nb_frames) 169 [new_data, new_nb_frames] = self.get_next_sample(
170 frame_count - nb_frames)
126 data += new_data 171 data += new_data
127 nb_frames += new_nb_frames 172 nb_frames += new_nb_frames
128 elif nb_frames == 0: 173 elif nb_frames == 0:
129 # FIXME: too slow 174 # FIXME: too slow
130 threading.Thread(name = "MSFinishedCallback", target=self.finished_callback).start() 175 threading.Thread(
176 name="MSFinishedCallback",
177 target=self.finished_callback).start()
131 178
132 return data.ljust(out_data_length, b'\0') 179 return data.ljust(out_data_length, b'\0')
133 180
@@ -141,11 +188,13 @@ class MusicFile(Machine):
141 max_val = int(segment.frame_count()) 188 max_val = int(segment.frame_count())
142 189
143 start_i = max(self.current_frame_with_effect, 0) 190 start_i = max(self.current_frame_with_effect, 0)
144 end_i = min(self.current_frame_with_effect + frame_count, max_val) 191 end_i = min(self.current_frame_with_effect + frame_count, max_val)
145 192
146 data += segment._data[(start_i * fw):(end_i * fw)] 193 data += segment._data[start_i*fw : end_i*fw]
147 194
148 frame_count = max(0, self.current_frame_with_effect + frame_count - max_val) 195 frame_count = max(
196 0,
197 self.current_frame_with_effect + frame_count - max_val)
149 198
150 self.current_frame_with_effect += end_i - start_i 199 self.current_frame_with_effect += end_i - start_i
151 self.current_frame += end_i - start_i 200 self.current_frame += end_i - start_i
@@ -159,7 +208,7 @@ class MusicFile(Machine):
159 208
160 start_i = max(self.current_frame, 0) 209 start_i = max(self.current_frame, 0)
161 end_i = min(self.current_frame + frame_count, max_val) 210 end_i = min(self.current_frame + frame_count, max_val)
162 data += segment._data[(start_i * fw):(end_i * fw)] 211 data += segment._data[start_i*fw : end_i*fw]
163 nb_frames += end_i - start_i 212 nb_frames += end_i - start_i
164 self.current_frame += end_i - start_i 213 self.current_frame += end_i - start_i
165 214
@@ -167,21 +216,25 @@ class MusicFile(Machine):
167 216
168 return [data, nb_frames] 217 return [data, nb_frames]
169 218
170 def seek(self, value = 0, delta = False): 219 def seek(self, value=0, delta=False):
171 # We don't want to do that while stopping 220 # We don't want to do that while stopping
172 if not (self.is_loaded_playing() or self.is_loaded_paused()): 221 if not (self.is_loaded_playing() or self.is_loaded_paused()):
173 return 222 return
174 with self.music_lock: 223 with self.music_lock:
175 self.a_s_with_effect = None 224 self.a_s_with_effect = None
176 self.current_frame = max(0, int(delta) * self.current_frame + int(value * self.audio_segment.frame_rate)) 225 self.current_frame = max(
226 0,
227 int(delta) * self.current_frame
228 + int(value * self.audio_segment.frame_rate))
177 # FIXME: si on fait un seek + delta, adapter le "loop" 229 # FIXME: si on fait un seek + delta, adapter le "loop"
178 230
179 def stop(self, fade_out = 0, wait = False): 231 def stop(self, fade_out=0, wait=False):
180 if self.is_loaded_playing(): 232 if self.is_loaded_playing():
181 ms = int(self.sound_position * 1000) 233 ms = int(self.sound_position * 1000)
182 ms_fo = max(1, int(fade_out * 1000)) 234 ms_fo = max(1, int(fade_out * 1000))
183 235
184 new_audio_segment = self.current_audio_segment[:ms + ms_fo].fade_out(ms_fo) 236 new_audio_segment = self.current_audio_segment[: ms+ms_fo] \
237 .fade_out(ms_fo)
185 with self.music_lock: 238 with self.music_lock:
186 self.current_audio_segment = new_audio_segment 239 self.current_audio_segment = new_audio_segment
187 self.stop_playing() 240 self.stop_playing()
@@ -195,8 +248,10 @@ class MusicFile(Machine):
195 self.db_gain += db_gain 248 self.db_gain += db_gain
196 self.volume_factor = 10 ** (self.db_gain / 20) 249 self.volume_factor = 10 ** (self.db_gain / 20)
197 250
198 def set_volume(self, value, delta = False): 251 def set_volume(self, value, delta=False):
199 [db_gain, self.volume] = gain(value + int(delta) * self.volume, self.volume) 252 [db_gain, self.volume] = gain(
253 value + int(delta) * self.volume,
254 self.volume)
200 255
201 self.set_gain(db_gain) 256 self.set_gain(db_gain)
202 257
diff --git a/music_sampler.py b/music_sampler.py
index 5613fdf..d91e150 100644
--- a/music_sampler.py
+++ b/music_sampler.py
@@ -50,8 +50,7 @@ class PlayList(RelativeLayout):
50 50
51 text = "{}/{}".format( 51 text = "{}/{}".format(
52 helpers.duration_to_min_sec(music_file.sound_position), 52 helpers.duration_to_min_sec(music_file.sound_position),
53 helpers.duration_to_min_sec(music_file.sound_duration) 53 helpers.duration_to_min_sec(music_file.sound_duration))
54 )
55 54
56 if music_file.is_paused(): 55 if music_file.is_paused():
57 self.playlist.append(["⏸", music_file.name, text, False]) 56 self.playlist.append(["⏸", music_file.name, text, False])
diff --git a/music_sampler.spec b/music_sampler.spec
index 5bae714..591a6cf 100644
--- a/music_sampler.spec
+++ b/music_sampler.spec
@@ -1,9 +1,21 @@
1# -*- mode: python -*- 1# -*- mode: python -*-
2import os 2import os
3from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal, hookspath, runtime_hooks 3from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal,\
4 hookspath, runtime_hooks
4 5
5excluded_and_hidden_modules = get_deps_minimal(video=None, camera=None, audio=None, clipboard=None, spelling=None) 6excluded_and_hidden_modules = get_deps_minimal(
6excluded_and_hidden_modules['hiddenimports'] += [ 'six', 'packaging', 'packaging.version', 'packaging.specifiers', 'packaging.requirements'] 7 video=None,
8 camera=None,
9 audio=None,
10 clipboard=None,
11 spelling=None)
12
13excluded_and_hidden_modules['hiddenimports'] += [
14 'six',
15 'packaging',
16 'packaging.version',
17 'packaging.specifiers',
18 'packaging.requirements' ]
7 19
8commit_message = os.popen('git log -1 --format="%h %ci"').read() 20commit_message = os.popen('git log -1 --format="%h %ci"').read()
9pyinstaller_file = open(".pyinstaller_commit", "w") 21pyinstaller_file = open(".pyinstaller_commit", "w")
@@ -23,8 +35,18 @@ a = Analysis(['music_sampler.py'],
23pyz = PYZ(a.pure, a.zipped_data) 35pyz = PYZ(a.pure, a.zipped_data)
24 36
25# Single file 37# Single file
26exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name='music_sampler') 38exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas,
39 name='music_sampler')
27 40
28# Directory 41# Directory
29# exe = EXE(pyz, a.scripts, exclude_binaries=True, name='music_sampler_dir', debug=False, strip=False, upx=True, console=True ) 42# exe = EXE(pyz, a.scripts,
30# coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name='music_sampler_dir') 43# exclude_binaries=True,
44# name='music_sampler_dir',
45# debug=False,
46# strip=False,
47# upx=True,
48# console=True)
49# coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas,
50# strip=False,
51# upx=True,
52# name='music_sampler_dir')