class MusicEditor(Editor): def __init__(self, parent): super().__init__(parent) self._is_playing = False self._play_pos = [0 for _ in range(pyxel.MUSIC_CHANNEL_COUNT)] self.field_cursor = FieldCursor( self.get_data, self.add_pre_history, self.add_post_history, MAX_MUSIC_LENGTH, 16, pyxel.MUSIC_CHANNEL_COUNT, ) self._music_picker = NumberPicker(self, 45, 17, 0, pyxel.MUSIC_BANK_COUNT - 1, 0) self._play_button = ImageButton( self, 185, 17, pyxel.IMAGE_BANK_FOR_SYSTEM, EDITOR_IMAGE_X + 126, EDITOR_IMAGE_Y, ) self._stop_button = ImageButton( self, 195, 17, pyxel.IMAGE_BANK_FOR_SYSTEM, EDITOR_IMAGE_X + 135, EDITOR_IMAGE_Y, ) self._loop_button = ImageToggleButton( self, 205, 17, pyxel.IMAGE_BANK_FOR_SYSTEM, EDITOR_IMAGE_X + 144, EDITOR_IMAGE_Y, ) self._music_field = [ MusicField(self, 11, 29 + i * 25, i) for i in range(4) ] self._sound_selector = SoundSelector(self) self.add_event_handler("undo", self.__on_undo) self.add_event_handler("redo", self.__on_redo) self.add_event_handler("hide", self.__on_hide) self.add_event_handler("update", self.__on_update) self.add_event_handler("draw", self.__on_draw) self._play_button.add_event_handler("press", self.__on_play_button_press) self._stop_button.add_event_handler("press", self.__on_stop_button_press) self._play_button.add_event_handler("mouse_hover", self.__on_play_button_mouse_hover) self._stop_button.add_event_handler("mouse_hover", self.__on_stop_button_mouse_hover) self._loop_button.add_event_handler("mouse_hover", self.__on_loop_button_mouse_hover) self.add_number_picker_help(self._music_picker) @property def music(self): return self._music_picker.value @property def is_playing(self): return self._is_playing def play_pos(self, ch): return self._play_pos[ch] def get_data(self, value): music = pyxel.music(self._music_picker.value) if value == 0: data = music.ch0 elif value == 1: data = music.ch1 elif value == 2: data = music.ch2 elif value == 3: data = music.ch3 return data def add_pre_history(self, x, y): self._history_data = data = {} data["music"] = self._music_picker.value data["cursor_before"] = (x, y) data["before"] = self.field_cursor.data[:] def add_post_history(self, x, y): data = self._history_data data["cursor_after"] = (x, y) data["after"] = self.field_cursor.data[:] if data["before"] != data["after"]: self.add_history(self._history_data) def _play(self): self._is_playing = True for i in range(pyxel.MUSIC_CHANNEL_COUNT): self._play_pos[i] = 0 self._music_picker.is_enabled = False self._play_button.is_enabled = False self._stop_button.is_enabled = True self._loop_button.is_enabled = False pyxel.playm(self._music_picker.value, loop=self._loop_button.value) def _stop(self): self._is_playing = False for i in range(pyxel.MUSIC_CHANNEL_COUNT): self._play_pos[i] = -1 self._music_picker.is_enabled = True self._play_button.is_enabled = True self._stop_button.is_enabled = False self._loop_button.is_enabled = True pyxel.stop() def __on_undo(self, data): self._music_picker.value = data["music"] self.field_cursor.move(*data["cursor_before"]) self.field_cursor.data[:] = data["before"] def __on_redo(self, data): dat = data["after"] dat_len = len(dat) self._music_picker.value = data["music"] self.field_cursor.move(*data["cursor_after"]) self.field_cursor.data[:dat_len] = dat self.field_cursor.data_lengh = dat_len def __on_hide(self): self._stop() def __on_update(self): if self._is_playing: self._is_playing = False for i in range(pyxel.MUSIC_CHANNEL_COUNT): if pyxel.play_pos(i) >= 0: self._is_playing = True play_pos = pyxel.play_pos(i) self._play_pos[ i] = play_pos // 100 if play_pos >= 0 else -1 else: self._play_pos[i] = -1 if pyxel.btnp(pyxel.KEY_SPACE): if self._is_playing: self._stop_button.press() else: self._play_button.press() if self._is_playing: return if not self._play_button.is_enabled: self._stop() if self._loop_button.is_enabled and pyxel.btnp(pyxel.KEY_L): self._loop_button.press() self.field_cursor.process_input() def __on_draw(self): self.draw_panel(11, 16, 218, 9) pyxel.text(23, 18, "MUSIC", 6) def __on_play_button_press(self): self._play() def __on_stop_button_press(self): self._stop() def __on_play_button_mouse_hover(self, x, y): self.parent.help_message = "PLAY:SPACE" def __on_stop_button_mouse_hover(self, x, y): self.parent.help_message = "STOP:SPACE" def __on_loop_button_mouse_hover(self, x, y): self.parent.help_message = "LOOP:L"
class SoundEditor(Editor): def __init__(self, parent): super().__init__(parent) self.field_cursor = FieldCursor( self.get_data, self.add_pre_history, self.add_post_history, SOUND_MAX_LENGTH, SOUND_MAX_LENGTH, 4, ) self.octave = 2 self._is_playing = False self._play_pos = None self._history_data = None self._sound_picker = NumberPicker(self, 45, 17, 0, AUDIO_SOUND_COUNT - 2, 0) self._speed_picker = NumberPicker(self, 105, 17, 1, 99, pyxel.sound(0).speed) self._play_button = ImageButton( self, 185, 17, 3, EDITOR_IMAGE_X + 126, EDITOR_IMAGE_Y ) self._stop_button = ImageButton( self, 195, 17, 3, EDITOR_IMAGE_X + 135, EDITOR_IMAGE_Y, is_enabled=False ) self._loop_button = ImageToggleButton( self, 205, 17, 3, EDITOR_IMAGE_X + 144, EDITOR_IMAGE_Y ) self._piano_keyboard = PianoKeyboard(self) self._piano_roll = PianoRoll(self) self._sound_field = SoundField(self) self._left_octave_bar = OctaveBar(self, 12, 25) self._right_octave_bar = OctaveBar(self, 224, 25) self.add_event_handler("undo", self.__on_undo) self.add_event_handler("redo", self.__on_redo) self.add_event_handler("hide", self.__on_hide) self.add_event_handler("update", self.__on_update) self.add_event_handler("draw", self.__on_draw) self._sound_picker.add_event_handler("change", self.__on_sound_picker_change) self._speed_picker.add_event_handler("change", self.__on_speed_picker_change) self._play_button.add_event_handler("press", self.__on_play_button_press) self._stop_button.add_event_handler("press", self.__on_stop_button_press) self._play_button.add_event_handler( "mouse_hover", self.__on_play_button_mouse_hover ) self._stop_button.add_event_handler( "mouse_hover", self.__on_stop_button_mouse_hover ) self._loop_button.add_event_handler( "mouse_hover", self.__on_loop_button_mouse_hover ) self.add_number_picker_help(self._sound_picker) self.add_number_picker_help(self._speed_picker) @property def keyboard_note(self): return self._piano_keyboard.note @property def is_playing(self): return self._is_playing @property def play_pos(self): return self._play_pos def get_data(self, index): sound = pyxel.sound(self._sound_picker.value) if index == 0: data = sound.note elif index == 1: data = sound.tone elif index == 2: data = sound.volume elif index == 3: data = sound.effect return data def add_pre_history(self, x, y): self._history_data = data = {} data["sound"] = self._sound_picker.value data["cursor_before"] = (x, y) data["before"] = self.field_cursor.data.copy() def add_post_history(self, x, y): data = self._history_data data["cursor_after"] = (x, y) data["after"] = self.field_cursor.data.copy() if data["before"] != data["after"]: self.add_history(self._history_data) def _play(self): self._is_playing = True self._play_pos = 0 self._sound_picker.is_enabled = False self._speed_picker.is_enabled = False self._play_button.is_enabled = False self._stop_button.is_enabled = True self._loop_button.is_enabled = False pyxel.play(0, self._sound_picker.value, loop=self._loop_button.value) def _stop(self): self._is_playing = None self._play_pos = None self._sound_picker.is_enabled = True self._speed_picker.is_enabled = True self._play_button.is_enabled = True self._stop_button.is_enabled = False self._loop_button.is_enabled = True pyxel.stop(0) def __on_undo(self, data): self._sound_picker.value = data["sound"] self.field_cursor.move(*data["cursor_before"]) self.field_cursor.data[:] = data["before"] def __on_redo(self, data): self._sound_picker.value = data["sound"] self.field_cursor.move(*data["cursor_after"]) self.field_cursor.data[:] = data["after"] def __on_hide(self): self._stop() def __on_update(self): channel = pyxel._app._audio_player._channel_list[0] self._is_playing = channel._is_playing self._play_pos = ( int(channel._time / channel._one_note_time) if channel._is_playing else None ) if pyxel.btnp(pyxel.KEY_SPACE): if self._is_playing: self._stop_button.press() else: self._play_button.press() if self._is_playing: return if not self._play_button.is_enabled: self._stop() if self._loop_button.is_enabled and pyxel.btnp(pyxel.KEY_L): self._loop_button.press() if pyxel.btnp(pyxel.KEY_PAGE_UP): self.octave = min(self.octave + 1, 3) if pyxel.btnp(pyxel.KEY_PAGE_DOWN): self.octave = max(self.octave - 1, 0) self.field_cursor.process_input() def __on_draw(self): self.draw_panel(11, 16, 218, 157) pyxel.text(23, 18, "SOUND", 6) pyxel.text(83, 18, "SPEED", 6) def __on_sound_picker_change(self, value): sound = pyxel.sound(value) self._speed_picker.value = sound.speed def __on_speed_picker_change(self, value): sound = pyxel.sound(self._sound_picker.value) sound.speed = value def __on_play_button_press(self): self._play() def __on_stop_button_press(self): self._stop() def __on_play_button_mouse_hover(self, x, y): self.parent.help_message = "PLAY:SPACE" def __on_stop_button_mouse_hover(self, x, y): self.parent.help_message = "STOP:SPACE" def __on_loop_button_mouse_hover(self, x, y): self.parent.help_message = "LOOP:L"
class SoundEditor(Editor): class PlayInfo: is_playing = False is_looping = False start_time = 0 speed = 0 length = 0 def __init__(self, parent): super().__init__(parent) self.cursor_x = 0 self.cursor_y = 0 self.octave = 2 self._play_info = SoundEditor.PlayInfo() self._history_data = None self._sound_picker = NumberPicker(self, 45, 17, 0, AUDIO_SOUND_COUNT - 1, 0) self._speed_picker = NumberPicker(self, 105, 17, 1, 99, pyxel.sound(0).speed) self._play_button = ImageButton(self, 185, 17, 3, EDITOR_IMAGE_X + 126, EDITOR_IMAGE_Y) self._stop_button = ImageButton(self, 195, 17, 3, EDITOR_IMAGE_X + 135, EDITOR_IMAGE_Y, is_enabled=False) self._loop_button = ImageToggleButton(self, 205, 17, 3, EDITOR_IMAGE_X + 144, EDITOR_IMAGE_Y) self._piano_keyboard = PianoKeyboard(self) self._piano_roll = PianoRoll(self) self._sound_input = SoundInput(self) self._left_octave_bar = OctaveBar(self, 12, 25) self._right_octave_bar = OctaveBar(self, 224, 25) self.add_event_handler("undo", self.__on_undo) self.add_event_handler("redo", self.__on_redo) self.add_event_handler("update", self.__on_update) self.add_event_handler("draw", self.__on_draw) self._sound_picker.add_event_handler("change", self.__on_sound_picker_change) self._speed_picker.add_event_handler("change", self.__on_speed_picker_change) self._play_button.add_event_handler("press", self.__on_play_button_press) self._stop_button.add_event_handler("press", self.__on_stop_button_press) self._play_button.add_event_handler("mouse_hover", self.__on_play_button_mouse_hover) self._stop_button.add_event_handler("mouse_hover", self.__on_stop_button_mouse_hover) self._loop_button.add_event_handler("mouse_hover", self.__on_loop_button_mouse_hover) self.add_number_picker_help(self._sound_picker) self.add_number_picker_help(self._speed_picker) @property def sound(self): return self._sound_picker.value @property def speed(self): return self._speed_picker.value @property def sound_data(self): sound = pyxel.sound(self._sound_picker.value) if self.cursor_y == 0: data = sound.note elif self.cursor_y == 1: data = sound.tone elif self.cursor_y == 2: data = sound.volume elif self.cursor_y == 3: data = sound.effect return data @property def max_edit_x(self): return min(len(self.sound_data), SOUND_MAX_LENGTH - 1) @property def edit_x(self): return min(self.cursor_x, self.max_edit_x) @property def keyboard_note(self): return self._piano_keyboard.note @property def play_pos(self): play_info = self._play_info if not play_info.is_playing: return -1 pos = int((time.time() - play_info.start_time) * 120 / play_info.speed) if play_info.is_looping: pos = pos % play_info.length elif pos >= play_info.length: pos = -1 return pos def add_edit_history_before(self): self._history_data = data = {} data["sound"] = self._sound_picker.value data["cursor_before"] = (self.cursor_x, self.cursor_y) data["before"] = self.sound_data.copy() def add_edit_history_after(self): data = self._history_data data["cursor_after"] = (self.cursor_x, self.cursor_y) data["after"] = self.sound_data.copy() self.add_edit_history(self._history_data) def _play(self): sound = pyxel.sound(self._sound_picker.value) play_info = self._play_info play_info.is_playing = True play_info.is_looping = self._loop_button.value play_info.start_time = time.time() play_info.speed = sound.speed play_info.length = len(sound.note) self._play_button.is_enabled = False self._stop_button.is_enabled = True self._loop_button.is_enabled = False pyxel.play(0, self._sound_picker.value, loop=play_info.is_looping) def _stop(self): play_info = self._play_info play_info.is_playing = False self._play_button.is_enabled = True self._stop_button.is_enabled = False self._loop_button.is_enabled = True pyxel.stop(0) def __on_undo(self, data): self._sound_picker.value = data["sound"] self.cursor_x, self.cursor_y = data["cursor_before"] self.sound_data[:] = data["before"] def __on_redo(self, data): self._sound_picker.value = data["sound"] self.cursor_x, self.cursor_y = data["cursor_after"] self.sound_data[:] = data["after"] def __on_update(self): if pyxel.btnp(pyxel.KEY_SPACE): if self._play_info.is_playing: self._stop_button.press() else: self._play_button.press() if self._loop_button.is_enabled and pyxel.btnp(pyxel.KEY_L): self._loop_button.press() if self._play_info.is_playing and self.play_pos < 0: self._stop() if pyxel.btnp(pyxel.KEY_PAGE_UP): self.octave = min(self.octave + 1, 3) if pyxel.btnp(pyxel.KEY_PAGE_DOWN): self.octave = max(self.octave - 1, 0) if self._play_info.is_playing: return if self.cursor_x > 0 and pyxel.btnp(pyxel.KEY_LEFT, WIDGET_HOLD_TIME, WIDGET_REPEAT_TIME): self.cursor_x = self.edit_x - 1 if self.cursor_x < self.max_edit_x and pyxel.btnp( pyxel.KEY_RIGHT, WIDGET_HOLD_TIME, WIDGET_REPEAT_TIME): self.cursor_x += 1 if self.cursor_y > 0 and pyxel.btnp(pyxel.KEY_UP, WIDGET_HOLD_TIME, WIDGET_REPEAT_TIME): self.cursor_y -= 1 if self.cursor_y < 3 and pyxel.btnp(pyxel.KEY_DOWN, WIDGET_HOLD_TIME, WIDGET_REPEAT_TIME): self.cursor_y += 1 def __on_draw(self): self.draw_frame(11, 16, 218, 157) pyxel.text(23, 18, "SOUND", 6) pyxel.text(83, 18, "SPEED", 6) pyxel.text(17, 150, "TON", 6) pyxel.text(17, 158, "VOL", 6) pyxel.text(17, 166, "EFX", 6) def __on_sound_picker_change(self, value): sound = pyxel.sound(value) self._speed_picker.value = sound.speed def __on_speed_picker_change(self, value): sound = pyxel.sound(self._sound_picker.value) sound.speed = value def __on_play_button_press(self): self._play() def __on_stop_button_press(self): self._stop() def __on_play_button_mouse_hover(self, x, y): self.parent.help_message = "PLAY:SPACE" def __on_stop_button_mouse_hover(self, x, y): self.parent.help_message = "STOP:SPACE" def __on_loop_button_mouse_hover(self, x, y): self.parent.help_message = "LOOP:L"