class Register(Enum): HIGH = GridUnit(0) MEDIUM = GridUnit(1) LOW = GridUnit(2) H = HIGH M = MEDIUM L = LOW
def calculate_occupied_measures(event_data): occupied_measures = set() for event in event_data: start_measure_num = int(Measure(event.pos_x).display_value) end_measure_num = int( Measure(event.pos_x + GridUnit(event.length) - GridUnit(1)).display_value) occupied_measures.update( range(start_measure_num, end_measure_num + 1)) return occupied_measures
def draw_bar_lines(self): for measure_num in range(self.measure_count + 1): current_path = Path( (Measure(measure_num), GridUnit(0)), pen=Score._bar_line_pen, parent=self, ) drawing = False for divider_num in range(len(self.instruments) + 1): if self._bar_line_extends_below(measure_num, divider_num): if not drawing: current_path.move_to( GridUnit(0), Score._instrument_pos_y(divider_num)) drawing = True else: if drawing: current_path.line_to( GridUnit(0), Score._instrument_pos_y(divider_num)) drawing = False
def draw_instrument_dividers(self): for divider in range(len(self.instruments) + 1): current_path = Path( (Measure(0), Score._divider_pos_y(divider)), pen=Score._instrument_divider_pen, parent=self, ) instrument_above = self.instruments[divider - 1] if divider > 0 else None instrument_below = (self.instruments[divider] if divider < len(self.instruments) else None) drawing = False for measure_num in range(self.measure_count + 1): if Score._divider_visible(instrument_above, instrument_below, measure_num): if not drawing: current_path.move_to(Measure(measure_num), GridUnit(0)) drawing = True else: if drawing: current_path.line_to(Measure(measure_num), GridUnit(0)) drawing = False
class _EventBox(Path, Spanner): box_pen = Pen(thickness=GridUnit(0.07), join_style=PenJoinStyle.MITER) def __init__(self, parent, length): Path.__init__( self, (GridUnit(0), GridUnit(0)), pen=_EventBox.box_pen, parent=parent ) Spanner.__init__(self, length, self) self._construct_path() def _construct_path(self): self.line_to(self.end_x, GridUnit(0)) self.line_to(self.end_x, GridUnit(1)) self.line_to(GridUnit(0), GridUnit(1)) self.line_to(GridUnit(0), GridUnit(0)) self.close_subpath()
def _divider_pos_y(divider_index): return GridUnit(3 * divider_index)
def _instrument_pos_y(instrument_index): return GridUnit(3 * instrument_index)
class Score(ObjectGroup): _TEXT_FONT_SIZE = GridUnit(0.6).base_value _MUSIC_FONT_SIZE = Staff._make_unit_class(GridUnit(0.5)) _bar_line_pen = Pen(thickness=GridUnit(0.05), pattern=PenPattern.DOT) _instrument_divider_pen = Pen(thickness=GridUnit(0.05)) def __init__(self, pos, instruments, parent): super().__init__(pos, parent) self.events = [] self.text_font = neoscore.default_font.modified( size=Score._TEXT_FONT_SIZE, weight=60) self.music_font = MusicFont(constants.DEFAULT_MUSIC_FONT_NAME, Score._MUSIC_FONT_SIZE) self.instruments = instruments for i, instrument in enumerate(instruments): for event_data in instrument.event_data: self.events.append(self._create_event(i, event_data)) self.draw_instrument_dividers() self.draw_bar_lines() def _create_event(self, instrument_index, event_data): if isinstance(event_data.text, GlyphName): return self._create_music_text_event(instrument_index, event_data) return self._create_text_event(instrument_index, event_data) def _create_text_event(self, instrument_index, event_data): return TextEvent( ( event_data.pos_x, (Score._instrument_pos_y(instrument_index) + event_data.register.value), ), self, event_data.length, event_data.text, self.text_font, ) def _create_music_text_event(self, instrument_index, event_data): return MusicTextEvent( ( event_data.pos_x, (Score._instrument_pos_y(instrument_index) + event_data.register.value), ), self, event_data.length, event_data.text, self.music_font, ) @property def measure_count(self): return (max( max(int(Measure(e.pos_x).display_value) for e in i.event_data) for i in self.instruments) + 1) @staticmethod def _instrument_pos_y(instrument_index): return GridUnit(3 * instrument_index) @staticmethod def _divider_pos_y(divider_index): return GridUnit(3 * divider_index) @staticmethod def _divider_visible( instrument_above: Union[InstrumentData, None], instrument_below: Union[InstrumentData, None], measure_num: int, ) -> bool: return (instrument_above is not None and instrument_above.measure_has_events(measure_num)) or ( instrument_below is not None and instrument_below.measure_has_events(measure_num)) def _bar_line_extends_below(self, measure_num: int, divider_num: int) -> bool: if divider_num >= len(self.instruments): return False instrument = self.instruments[divider_num] return instrument.measure_has_events( measure_num - 1) or instrument.measure_has_events(measure_num) def draw_instrument_dividers(self): for divider in range(len(self.instruments) + 1): current_path = Path( (Measure(0), Score._divider_pos_y(divider)), pen=Score._instrument_divider_pen, parent=self, ) instrument_above = self.instruments[divider - 1] if divider > 0 else None instrument_below = (self.instruments[divider] if divider < len(self.instruments) else None) drawing = False for measure_num in range(self.measure_count + 1): if Score._divider_visible(instrument_above, instrument_below, measure_num): if not drawing: current_path.move_to(Measure(measure_num), GridUnit(0)) drawing = True else: if drawing: current_path.line_to(Measure(measure_num), GridUnit(0)) drawing = False def draw_bar_lines(self): for measure_num in range(self.measure_count + 1): current_path = Path( (Measure(measure_num), GridUnit(0)), pen=Score._bar_line_pen, parent=self, ) drawing = False for divider_num in range(len(self.instruments) + 1): if self._bar_line_extends_below(measure_num, divider_num): if not drawing: current_path.move_to( GridUnit(0), Score._instrument_pos_y(divider_num)) drawing = True else: if drawing: current_path.line_to( GridUnit(0), Score._instrument_pos_y(divider_num)) drawing = False
def _center_music_text(music_text): text_rect = music_text.bounding_rect x = (GridUnit(1 - MusicTextEvent._STEM_OFFSET_GRID_UNITS) - text_rect.width) / 2 y = GridUnit(0.5) music_text.pos = Point(x, y)
def test_calculate_occupied_measures_one_grid_unit_event(self): data = [EventData("", Measure(0) + GridUnit(3), Register.M, "", GridUnit(1))] assert InstrumentData.calculate_occupied_measures(data) == {0}
def _calculate_text_pos(text, font): text_rect = font.bounding_rect_of(text) x = (GridUnit(1) - text_rect.width) / 2 y = GridUnit(1) - ((GridUnit(1) - text_rect.height) / 2) return Point(x, y)
def _construct_path(self): self.line_to(self.end_x, GridUnit(0)) self.line_to(self.end_x, GridUnit(1)) self.line_to(GridUnit(0), GridUnit(1)) self.line_to(GridUnit(0), GridUnit(0)) self.close_subpath()
def __init__(self, parent, length): Path.__init__( self, (GridUnit(0), GridUnit(0)), pen=_EventBox.box_pen, parent=parent ) Spanner.__init__(self, length, self) self._construct_path()
from neoscore.core import neoscore from examples.feldman_projections_2.content import instruments from examples.feldman_projections_2.grid_unit import GridUnit from examples.feldman_projections_2.score import Score neoscore.setup() # flowable = Flowable((GridUnit(0), GridUnit(0)), Measure(100), GridUnit(10)) score = Score((GridUnit(0), GridUnit(0)), instruments, None) neoscore.show()