]> git.immae.eu Git - perso/Immae/Projets/Python/MusicSampler.git/blobdiff - helpers/music_file.py
Add possibility to reload YML config file
[perso/Immae/Projets/Python/MusicSampler.git] / helpers / music_file.py
index ccf60ce5eb8874f5b68dc81d48a89b9e86fd8626..ba8614204e030423c2aa71baca8b3f084143e759 100644 (file)
@@ -32,7 +32,8 @@ class MusicFile:
         {
             'trigger': 'load',
             'source': 'initial',
-            'dest': 'loading'
+            'dest': 'loading',
+            'after': 'poll_loaded'
         },
         {
             'trigger': 'fail',
@@ -47,7 +48,10 @@ class MusicFile:
         {
             'trigger': 'start_playing',
             'source': 'loaded',
-            'dest': 'loaded_playing'
+            'dest': 'loaded_playing',
+            # if a child has no transitions, then it is bubbled to the parent,
+            # and we don't want that. Not useful in that machine precisely.
+            'conditions': ['is_loaded']
         },
         {
             'trigger': 'pause',
@@ -68,7 +72,8 @@ class MusicFile:
             'trigger': 'stopped',
             'source': '*',
             'dest': 'loaded',
-            'before': 'trigger_stopped_events'
+            'before': 'trigger_stopped_events',
+            'conditions': ['is_in_use']
         }
     ]
 
@@ -77,6 +82,7 @@ class MusicFile:
                 transitions=self.TRANSITIONS, initial='initial',
                 ignore_invalid_triggers=True)
 
+        self.loaded_callbacks = []
         self.mapping = mapping
         self.filename = filename
         self.name = name or filename
@@ -86,6 +92,31 @@ class MusicFile:
 
         threading.Thread(name="MSMusicLoad", target=self.load).start()
 
+    def reload_properties(self, name=None, gain=1):
+        self.name = name or self.filename
+        if gain != self.initial_volume_factor:
+            self.initial_volume_factor = gain
+            self.reload_music_file()
+
+    def reload_music_file(self):
+        with file_lock:
+            try:
+                debug_print("Reloading « {} »".format(self.name))
+                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)
+            except Exception as e:
+                error_print("failed to reload « {} »: {}"\
+                        .format(self.name, e))
+                self.loading_error = e
+                self.to_failed()
+            else:
+                debug_print("Reloaded « {} »".format(self.name))
+
     # Machine related events
     def on_enter_loading(self):
         with file_lock:
@@ -109,6 +140,9 @@ class MusicFile:
                 debug_print("Loaded « {} »".format(self.name))
 
     def on_enter_loaded(self):
+        self.cleanup()
+
+    def cleanup(self):
         self.gain_effects = []
         self.set_gain(0, absolute=True)
         self.current_audio_segment = None
@@ -130,6 +164,7 @@ class MusicFile:
     def trigger_stopped_events(self):
         self.mixer.remove_file(self)
         self.wait_event.set()
+        self.cleanup()
 
     # Actions and properties called externally
     @property
@@ -230,6 +265,22 @@ class MusicFile:
         self.wait_event.clear()
         self.wait_event.wait()
 
+    # Let other subscribe for an event when they are ready
+    def subscribe_loaded(self, callback):
+        # FIXME: should lock to be sure we have no race, but it makes the
+        # initialization screen not showing until everything is loaded
+        if self.is_loaded(allow_substates=True):
+            callback(True)
+        elif self.is_failed():
+            callback(False)
+        else:
+            self.loaded_callbacks.append(callback)
+
+    def poll_loaded(self):
+        for callback in self.loaded_callbacks:
+            callback(self.is_loaded())
+        self.loaded_callbacks = []
+
     # Callbacks
     def finished_callback(self):
         self.stopped()