EasyABC icon indicating copy to clipboard operation
EasyABC copied to clipboard

Selecting and playing part of a multi-voice tune

Open revad opened this issue 5 months ago • 0 comments

This issue supersedes #77 Incorrect selection of notes when playing part of a multi-voice tune [8/2023] #91 Control-drag on the score to add to a previous selections of notes [3/2024]

Those two issues proposed changes to allow you to play part of a multi-voice tune. Other pre-requisite changes have been made since then and the remaining changes now only affect two files: music_score_panel.py svgrenderer.py

This is what currently happens if you select and play bars 3 and 4 of this 3-voice tune: https://github.com/user-attachments/assets/b05aaeaa-35eb-48c8-b503-8b7aa2ac9377 (Apologies for the poor sound in the recording: I don't know why it's doing that.) The tune is here: http://www.rudemex.co.uk/library/ABC/Albert%20Farmer's%20bonfire%20tune.abc

The one-line change below to svgrenderer.py makes it play like this: https://github.com/user-attachments/assets/523f593f-0469-4ed0-8ace-d1d964316638

The changes to music_score_panel.py allows you to ADD a selection to the previous one by holding down the control key on the second drag. This allows you to select a section that goes over the end of the staff, like this: https://github.com/user-attachments/assets/e1d5841f-d795-4ed6-85b2-5aa31937504b

And also to select, say, voice 1 and 3 but not voice 2, like this: https://github.com/user-attachments/assets/98baf8dd-51c0-4639-9a8b-e2e36ce438b0

Change to svgrenderer.py:

In function select_notes, delete two lines:

        selected_indices = set().union(*list_of_sets)
        # DR  if selected_indices:
        # DR      selected_indices = set(range(min(selected_indices), max(selected_indices) + 1))
        self.selected_indices = selected_indices
        return selected_indices

Change to music_score_panel.py:

At the end of function __init__ add one line: self.previous_selection = set() # DR

In function OnLeftButtonDown add one line:

            old_selection = page.selected_indices.copy()
            self.previous_selection = old_selection  # DR
            page.clear_note_selection()

In function OnMouseMotion add one line:

            if self.drag_start_x is not None and self.drag_start_y is not None:
                add_selection = event.ControlDown() or event.CmdDown()  # DR
                x, y = self.get_xy_of_mouse_event(event)

Lower down add this conditional statement:

                if (
                    old_selection != page.selected_indices
                    and self.OnNoteSelectionChangedDesc
                ):
                    if add_selection:  # DR
                        page.selected_indices = self.previous_selection.union(page.selected_indices)  # DR
                    self.OnNoteSelectionChangedDesc(page.selected_indices)
                self.redraw()

Discussion:

In #77 I speculated that the purpose of the statement I deleted in svgrenderer.py was to make it easier to select a rectangular area of the score without accidentally omitting notes. I'll call this 'sloppy selection'. It may be useful with single-voice tunes but breaks multi-voice selection badly. It might be advantageous to enable sloppy selection with single voice tunes so that behaviour is unchanged.

Currently, playing a selection suppresses repeats (as does control-play). It plays both/all endings. Follow score becomes unsynchonised with the sound when that happens.

revad avatar Nov 19 '25 12:11 revad