class AudioPlayerProcess(mp.Process): def __init__(self): super().__init__() self.daemon = True self.command_queue = mp.Queue() self.signal_queue = mp.Queue() self.audio_player: 'AudioPlayer' = None self.command_map: dict = None def process_init(self): """ Called when the child process is starting up. Executed inside the child process. """ from audio_player import AudioPlayer self.audio_player = AudioPlayer() def pipe_to_queue(signal_name): return lambda *args, **kwargs: self.signal_queue.put_nowait( (signal_name, args, kwargs) ) for signal in self.audio_player.signals: signal.connect(pipe_to_queue(signal.name)) for setting in self.audio_player.settings: setting.changed.emit = lambda *args, **kwargs: None self.command_map = { 'play': self.audio_player.play, 'toggle': self.audio_player.toggle, 'stop': self.audio_player.stop, 'resume': self.audio_player.resume, 'pause': self.audio_player.pause, 'rewind': self.audio_player.rewind, 'seek_time': self.audio_player.seek_time, 'set_volume': self.audio_player.settings.volume.set, 'set_pan': self.audio_player.settings.pan.set, 'set_balance': self.audio_player.settings.balance.set, 'set_playback_rate': self.audio_player.settings.playback_rate.set, 'set_looping': self.audio_player.settings.looping.set, } self.audio_player.resume() def run(self) -> None: self.process_init() while True: command, args = self.command_queue.get() command = self.command_map.get( command, lambda *args, **kwargs: None ) command(*args)
class NightstandApp(App): def __init__(self): super(NightstandApp, self).__init__() with open('configuration.yaml', 'r') as config: data = config.read() self.configuration = yaml.load(data) self.player = AudioPlayer() self.current_uid = None self.reader = RfidReader() def _keyboard_closed(self): self._keyboard.unbind(on_key_down=self._on_keyboard_down) self._keyboard = None def _on_keyboard_down(self, keyboard, keycode, text, modifiers): if keycode[1] == 'a': self.message_received('1234', 'figurine_added') elif keycode[1] == 'r': self.message_received('1234', 'figurine_removed') return True def build(self): self.main = Main() self.main.manager.state = 'main' self.main.manager.transition = NoTransition() self.main.ids.volume_slider.bind(value=self.on_volume_slider_change) self.main.ids.audio_list.data_directory = self.configuration[ 'data_directory'] self.main.ids.audio_list.audio_directory = os.path.join( self.configuration['data_directory'], 'audio') self.main.ids.audio_list.show_all() start_new_thread(self.update_seek_slider, ()) self.initialize_debug_keyboard() return self.main def initialize_debug_keyboard(self): if not sys.platform.startswith('linux'): self._keyboard = Window.request_keyboard(self._keyboard_closed, self) self._keyboard.bind(on_key_down=self._on_keyboard_down) def on_volume_slider_change(self, instance, value): self.player.set_volume(value) def seek_to_user(self): new_position = self.main.ids.seek_slider.value self.player.seek(new_position) def show_playing_screen(self, restart_playback=True): self.root.manager.current = 'playing' self.root.manager.state = 'playing' if restart_playback: self.player.play(self.figurine.get_audio_path()) def show_create_figurine_screen(self): self.root.manager.current = 'create_figurine' def show_main_screen(self): self.root.manager.current = 'main' self.root.manager.state = 'main' self.current_uid = None def update_seek_slider(self): while True: (position, length) = self.player.seek_information() self.main.ids.seek_slider.range = (0, length) self.main.ids.seek_slider.value = position self.main.ids.seek_time.text = str(self.player.remaining()) if self.player.is_playing(): self.main.ids.play_pause_button.text = 'Pause' self.main.ids.playing_label.text = 'Playing..' self.main.ids.audio_name.text = os.path.basename( self.figurine.get_audio_path()) self.main.ids.seek_slider.opacity = 100 self.main.ids.seek_time.opacity = 100 else: if position >= 0.99 * length: self.main.ids.play_pause_button.text = 'Replay' self.main.ids.playing_label.text = '' self.main.ids.seek_slider.opacity = 0 self.main.ids.seek_time.opacity = 0 else: self.main.ids.play_pause_button.text = 'Play' self.main.ids.playing_label.text = '' self.main.ids.seek_slider.opacity = 100 self.main.ids.seek_time.opacity = 100 time.sleep(1) def toggle_pause(self): if self.player is not None: if self.player.is_playing(): self.player.pause() else: (position, length) = self.player.seek_information() if position >= 0.99 * length: self.player.replay() else: self.player.resume() def save_figurine(self): data = self.main.ids.audio_list.selection selected_audio_path = os.path.join(data['directory'], data['name']) self.figurine = Figurine(self.current_uid or self.requested_uid, self.configuration['data_directory']) self.figurine.save(selected_audio_path) self.show_playing_screen() self.initialize_debug_keyboard() def delete_figurine(self): if self.player is not None and self.player.is_playing(): self.player.pause() self.figurine.delete() self.show_main_screen() def message_received(self, uid, action): print uid + ' / ' + action if action == 'figurine_added': if self.current_uid == uid: self.show_playing_screen(False) self.player.resume() else: self.figurine = Figurine(uid, self.configuration['data_directory']) if self.figurine.exists(): self.show_playing_screen() else: self.show_create_figurine_screen() self.requested_uid = uid # We must not set the current_uid here, as otherwise the cancel button on the 'Add figurine' screen does not work return self.current_uid = uid elif action == 'figurine_removed': self.player.pause() self.show_main_screen() def check_rfid_reader(self, delta_time): self.reader.read_rfid(self.message_received) def shutdown(self): os.system('sudo poweroff') App.get_running_app().stop()