@@ -322,11 +322,18 @@ def _position_to_staff_no(self, symbol: EncodedSymbol) -> int:
322322 return 1
323323 return 0
324324
325- def extract_measures (self , count : int ) -> list [EncodedSymbol ]:
325+ def extract_measures (
326+ self , count : int , always_include_time : bool = False
327+ ) -> list [EncodedSymbol ]:
326328 clefs = self .clefs .copy ()
327329 key = self .key
328330 time = self .time
329- has_time = False
331+ # Lieder pages are crops of one continuously rendered score, so a courtesy time
332+ # signature is only visible where the source XML actually redeclares it. pdmx and
333+ # musetrainer windows are each re-rendered standalone (see generate_xml), and that
334+ # renderer always draws a time signature on a fresh score - so those callers pass
335+ # always_include_time=True to keep the label in sync with the image.
336+ has_time = always_include_time
330337 result : list [EncodedSymbol ] = []
331338 for i in range (count ):
332339 selected_measure = self .voice .pop (0 )
@@ -457,31 +464,32 @@ def _split_file_into_staffs(
457464 return result
458465
459466
467+ def _leading_clefs (measure : Measure ) -> list [EncodedSymbol ]:
468+ # The clefs of a measure always precede its notes/rests, but other preamble symbols
469+ # (e.g. repeatStart on the very first measure) can come before them, so scan rather
470+ # than assume fixed indices.
471+ clefs = []
472+ for symbol in measure :
473+ if symbol .rhythm .startswith (("note" , "rest" )):
474+ break
475+ if symbol .rhythm .startswith ("clef" ):
476+ clefs .append (symbol )
477+ return clefs
478+
479+
460480def _count_staffs (voice : list [Measure ]) -> int :
461481 if len (voice ) == 0 :
462482 return 0
463- first_measure = voice [0 ]
464- if len (first_measure ) == 0 :
483+ clefs = _leading_clefs ( voice [0 ])
484+ if len (clefs ) == 0 :
465485 return 0
466- if len (first_measure ) < 3 :
467- return 0
468- third_symbol = first_measure [2 ]
469- if third_symbol .rhythm .startswith ("clef" ):
470- return 2
471- return 1
486+ return 2 if len (clefs ) >= 2 else 1
472487
473488
474489def is_grandstaff (voice : list [Measure ]) -> bool :
475490 if len (voice ) == 0 :
476491 return False
477- first_measure = voice [0 ]
478- if len (first_measure ) < 3 :
479- return False
480- return (
481- first_measure [0 ].rhythm .startswith ("clef" )
482- and first_measure [1 ].rhythm == "chord"
483- and first_measure [2 ].rhythm .startswith ("clef" )
484- )
492+ return len (_leading_clefs (voice [0 ])) >= 2
485493
486494
487495def get_svg_voice_count (voice : list [Measure ]) -> int :
0 commit comments