diff options
-rw-r--r-- | helpers/__init__.py | 26 | ||||
-rw-r--r-- | helpers/action.py | 101 | ||||
-rw-r--r-- | helpers/key.py | 12 | ||||
-rw-r--r-- | helpers/mapping.py | 23 | ||||
-rw-r--r-- | helpers/mixer.py | 15 | ||||
-rw-r--r-- | helpers/music_file.py | 109 | ||||
-rw-r--r-- | music_sampler.py | 3 | ||||
-rw-r--r-- | music_sampler.spec | 34 |
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 | ||
19 | def parse_args(): | 19 | def 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 | ||
128 | def gain(volume, old_volume = None): | 132 | def 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 | ||
134 | def debug_print(message): | 140 | def 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 @@ | |||
1 | from kivy.uix.widget import Widget | 1 | from kivy.uix.widget import Widget |
2 | from kivy.properties import AliasProperty, BooleanProperty, ListProperty, StringProperty | 2 | from kivy.properties import AliasProperty, BooleanProperty, \ |
3 | ListProperty, StringProperty | ||
3 | from kivy.clock import Clock | 4 | from kivy.clock import Clock |
4 | from kivy.uix.behaviors import ButtonBehavior | 5 | from 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 | |||
5 | from . import Config | 5 | from . import Config |
6 | 6 | ||
7 | sample_width = Config.sample_width | 7 | sample_width = Config.sample_width |
8 | |||
8 | def sample_width_to_dtype(sample_width): | 9 | def 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 | ||
20 | class Mixer: | 21 | class 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 | |||
14 | file_lock = Lock("file") | 14 | file_lock = Lock("file") |
15 | 15 | ||
16 | class MusicFile(Machine): | 16 | class 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 -*- |
2 | import os | 2 | import os |
3 | from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal, hookspath, runtime_hooks | 3 | from kivy.tools.packaging.pyinstaller_hooks import get_deps_minimal,\ |
4 | hookspath, runtime_hooks | ||
4 | 5 | ||
5 | excluded_and_hidden_modules = get_deps_minimal(video=None, camera=None, audio=None, clipboard=None, spelling=None) | 6 | excluded_and_hidden_modules = get_deps_minimal( |
6 | excluded_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 | |||
13 | excluded_and_hidden_modules['hiddenimports'] += [ | ||
14 | 'six', | ||
15 | 'packaging', | ||
16 | 'packaging.version', | ||
17 | 'packaging.specifiers', | ||
18 | 'packaging.requirements' ] | ||
7 | 19 | ||
8 | commit_message = os.popen('git log -1 --format="%h %ci"').read() | 20 | commit_message = os.popen('git log -1 --format="%h %ci"').read() |
9 | pyinstaller_file = open(".pyinstaller_commit", "w") | 21 | pyinstaller_file = open(".pyinstaller_commit", "w") |
@@ -23,8 +35,18 @@ a = Analysis(['music_sampler.py'], | |||
23 | pyz = PYZ(a.pure, a.zipped_data) | 35 | pyz = PYZ(a.pure, a.zipped_data) |
24 | 36 | ||
25 | # Single file | 37 | # Single file |
26 | exe = EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, name='music_sampler') | 38 | exe = 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') | ||