Selecting and playing part of a multi-voice tune
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.