+ db_gain = gain(volume) + self.mapping.master_gain
+ self.volume = volume
+
+ ms = int(start_at * 1000)
+ ms_fi = max(1, int(fade_in * 1000))
+ with self.music_lock:
+ self.current_audio_segment = (self.audio_segment + db_gain).fade(from_gain=-120, duration=ms_fi, start=ms)
+ self.before_loaded_playing(initial_frame = int(start_at * self.audio_segment.frame_rate))
+ self.start_playing()
+
+ def before_loaded_playing(self, initial_frame = 0):
+ self.current_frame = initial_frame
+ with self.music_lock:
+ segment = self.current_audio_segment
+
+ self.stream = sd.RawOutputStream(samplerate=segment.frame_rate,
+ channels=segment.channels,
+ dtype='int' + str(8*segment.sample_width), # FIXME: ?
+ latency=1.,
+ callback=self.play_callback,
+ finished_callback=self.finished_callback
+ )
+
+ def on_enter_loaded_playing(self):
+ self.stream.start()
+
+ def on_enter_loaded_paused(self):
+ self.stream.stop()
+
+ def finished_callback(self):
+ if self.is_loaded_playing():
+ self.stop_playing()
+ if self.is_loaded_stopping():
+ self.stopped()
+
+ def on_enter_loaded_stopped(self):
+ self.wait_event.set()
+
+ def play_callback(self, out_data, frame_count, time_info, status_flags):
+ with self.music_lock:
+ audio_segment = self.current_audio_segment.get_sample_slice_data(
+ start_sample=self.current_frame,
+ end_sample=self.current_frame + frame_count
+ )
+ self.current_frame += frame_count
+ if len(audio_segment) == 0:
+ raise sd.CallbackStop
+
+ out_data[:] = audio_segment.ljust(len(out_data), b'\0')
+
+ 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))
+
+ with self.music_lock:
+ self.current_audio_segment = self.current_audio_segment[:ms + ms_fo].fade_out(ms_fo)
+ self.stop_playing()
+ if wait:
+ self.wait_end()