Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import xml.etree.ElementTree as ET
- from PIL import Image, ImageDraw
- import os
- # -------------------------------
- # 1. Parse the MusicXML file
- # -------------------------------
- xml_path = '.../b1_01.xml'
- tree = ET.parse(xml_path)
- root = tree.getroot()
- # -------------------------------
- # 3. Initialize Variables
- # -------------------------------
- systems = [] # List of lists: measures per system
- current_system = []
- ySystems = [] # From new-system measures
- measures_widths = [] # [m1_width, m2_width, ...]
- xMargins = [] # [left_margin, ...] per measure
- all_x_positions = [] # Note X positions (px), by measure
- all_y_positions = [] # Note Y positions (px), by measure
- measure_to_system_index = {} # measure_num -> system_idx
- # -------------------------------
- # 2. Extract Page Margins and Scaling
- # -------------------------------
- page_margins = root.find('.//page-layout/page-margins')
- page_left = float(page_margins.find('left-margin').text)
- page_top = float(page_margins.find('top-margin').text)
- # Find first system's top-system-distance
- first_measure = root.find('.//measure[@number="1"]')
- first_layout = first_measure.find('.//system-layout')
- if first_layout is not None:
- lm_elem = first_layout.find('system-margins/left-margin')
- ySystems.insert(0,float(first_layout.find('top-system-distance').text))
- if lm_elem is not None:
- left_margin_tenths = float(lm_elem.text)
- # Insert at beginning
- xMargins.insert(0, round(left_margin_tenths, 2))
- else:
- xMargins.insert(0, 0.0)
- else:
- xMargins.insert(0, 0.0)
- top_system_distance = float(first_measure.find('.//system-layout/top-system-distance').text)
- scaling = root.find('.//scaling')
- mm_per_tenth = float(scaling.find('millimeters').text) / float(scaling.find('tenths').text)
- DPI = 300
- # 25.4 = millimeters per inch (exact conversion: 1 inch = 25.4 mm)
- tenths_to_pixels = mm_per_tenth * (DPI / 25.4)
- # -------------------------------
- # 4. Single Loop Over All Measures
- # -------------------------------
- for measure in root.findall('.//measure'):
- measure_num = int(measure.get('number'))
- # --- Detect new system ---
- print_elem = measure.find('print')
- new_system = False
- if print_elem is not None and print_elem.get('new-system') == 'yes':
- new_system = True
- dist_elem = print_elem.find('.//system-layout/system-distance')
- if dist_elem is not None:
- ySystems.append(float(dist_elem.text))
- # Finalize current system if starting a new one
- if new_system and current_system:
- systems.append(current_system)
- current_system = []
- current_system.append(measure_num)
- # --- xOffsets: append this measure's width ---
- width = float(measure.get('width'))
- measures_widths.append(width)
- # --- xMargins ---
- left_margin_val = 0.0
- if print_elem is not None and print_elem.get('new-system') == 'yes':
- layout = print_elem.find('system-layout')
- if layout is not None:
- lm_elem = layout.find('system-margins/left-margin')
- if lm_elem is not None:
- left_margin_tenths = float(lm_elem.text)
- xMargins.append(round(left_margin_tenths, 2))
- # --- System index for this measure ---
- sys_idx = len(systems) # current number of completed systems
- # Finalize last system
- if current_system:
- systems.append(current_system)
- # Build px's
- measures_widths_px = [round(val * tenths_to_pixels, 2) for val in measures_widths]
- xMargins_px = [round(val * tenths_to_pixels, 2) for val in xMargins]
- ySystems_px = [round(val * tenths_to_pixels, 2) for val in ySystems]
- page_left_px = round(page_left * tenths_to_pixels, 2)
- page_top_px = round(page_top * tenths_to_pixels, 2)
- top_system_distance_px = round(top_system_distance * tenths_to_pixels, 2)
- # Map measure numbers to system index
- for sys_idx, sys in enumerate(systems):
- for m in sys:
- measure_to_system_index[m] = sys_idx
- # Target measure number (1-based)
- n = 10 # Change this to any measure number
- measure_index = n - 1 # 0-based index
- # Get which system this measure belongs to
- system_idx = measure_to_system_index[n]
- # Get all measures in the same system
- current_system_measures = systems[system_idx]
- # Find the position of the target measure within its system
- target_measure_pos_in_system = current_system_measures.index(n)
- # Cumulative X offset from all previous measures
- cumulative_x_offset_px = sum(measures_widths_px[m - 1] for m in current_system_measures if m < n)
- # Cumulative vertical offset (Sum all ySystems_px up to this system)
- cumulative_y_offset_px = sum(ySystems_px[:system_idx+1])
- # This measure's xMargin in pixels
- x_margin_px = xMargins_px[system_idx] # already in pixels
- # Base X origin for this measure
- measure_origin_x_px = round((cumulative_x_offset_px + page_left_px + x_margin_px),2)
- # Base Y origin for this system
- system_origin_y_px = round((cumulative_y_offset_px + page_top_px + 708),2)
- # system 2 = 236, system 3 = 236 * 2, system 4 = 236 * 3 // 145 teenths is the closest to 236 and the only place to be found is in the default-y position for a 'g' pitch in staff=2 with f clef.
- print(145 * tenths_to_pixels)
- # Now process notes in measure n
- measure = root.find(f'.//measure[@number="{n}"]')
- notes = measure.findall('note')
- absolute_x_positions = []
- absolute_y_positions = []
- for note in notes:
- # xPosition
- default_x_tenths = float(note.get('default-x'))
- default_x_px = default_x_tenths * tenths_to_pixels
- x_abs = measure_origin_x_px + default_x_px
- absolute_x_positions.append(round(x_abs, 2))
- # yPosition
- default_y_tenths = float(note.get('default-y'))
- default_y_px = default_y_tenths * tenths_to_pixels
- y_abs = system_origin_y_px - default_y_px
- absolute_y_positions.append(round(y_abs, 2))
- # # DRAW
- # png_path = '.../b1_01.png'
- # output_path = '.../b1_01_with_dots.png'
- # if not os.path.exists(png_path):
- # raise FileNotFoundError(f"PNG file not found: {png_path}")
- # image = Image.open(png_path).convert("RGB")
- # draw = ImageDraw.Draw(image)
- # dot_radius = 3
- # for x, y in zip(absolute_x_positions, absolute_y_positions):
- # draw.ellipse([x - dot_radius, y - dot_radius, x + dot_radius, y + dot_radius], fill='red', outline='red')
- # image.save(output_path)
- # print(f"✅ Red dots saved to: {output_path}")
Advertisement
Add Comment
Please, Sign In to add comment