pachet commited on
Commit
6e4f2b4
·
1 Parent(s): 8d89421

Update app.py, format_conversions.py, and hexachords.py

Browse files
app.py CHANGED
@@ -3,12 +3,14 @@ import gradio as gr
3
  import numpy as np
4
  from mido import Message, MidiFile, MidiTrack
5
  import os
6
- from music21 import converter, note
7
  import hexachords
8
  from format_conversions import Format_Converter
9
  import verovio
10
  import subprocess
11
 
 
 
12
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
13
 
14
  def get_verovio_resource_path():
@@ -54,8 +56,6 @@ class HexachordApp:
54
  return False
55
 
56
  def generate_chords(self, note_names, itvl):
57
- # Placeholder for your actual chord generation function
58
- # Assuming hexachord is a list of MIDI note numbers
59
  interval_21 = 'P5'
60
  if itvl == 'fourth':
61
  interval_21 = 'P4'
@@ -63,40 +63,20 @@ class HexachordApp:
63
 
64
  def generate_realizations(self):
65
  # returns triples of midipath, score image, audio player
66
- fm = Format_Converter()
67
  reals = self._hexachord.generate_3_chords_realizations(self._hexachord._base_sequence)
68
- midi_path1 = self.create_midi(reals[0], "real1.mid")
69
- score_path1 = fm.midi_to_svg_file(tk, midi_path1, "real1.svg")
70
- audio_path1 = fm.convert_midi_to_audio(midi_path1, "real1")
71
- midi_path2 = self.create_midi(reals[1], "real2.mid")
72
- score_path2 = fm.midi_to_svg_file(tk, midi_path2, "real2.svg")
73
- audio_path2 = fm.convert_midi_to_audio(midi_path2, "real2")
74
- midi_path3 = self.create_midi(reals[2], "real3.mid")
75
- score_path3 = fm.midi_to_svg_file(tk, midi_path3, "real3.svg")
76
- audio_path3 = fm.convert_midi_to_audio(midi_path3, "real3")
77
- return midi_path1, score_path1, audio_path1, midi_path2, score_path2, audio_path2, midi_path3, score_path3, audio_path3
78
-
79
- def create_midi(self, chords, file_name):
80
- mid = MidiFile()
81
- track = MidiTrack()
82
- mid.tracks.append(track)
83
- delta_time = 480 * 4
84
- for i_chord, chord in enumerate(chords):
85
- for i, note in enumerate(chord):
86
- if i == 0 and i_chord != 0:
87
- track.append(Message('note_on', note=note.pitch.midi, velocity=64, time=1))
88
- # track.append(Message('note_on', note=note.pitch.midi, velocity=64, time=0))
89
- else:
90
- track.append(Message('note_on', note=note.pitch.midi, velocity=64, time=0))
91
- for i, note in enumerate(chord):
92
- if i==0:
93
- track.append(Message('note_off', note=note.pitch.midi, velocity=0, time=delta_time - 1))
94
- # track.append(Message('note_off', note=note.pitch.midi, velocity=0, time=delta_time))
95
- else:
96
- track.append(Message('note_off', note=note.pitch.midi, velocity=0, time=0))
97
  midi_path = os.path.join(BASE_DIR, file_name)
98
- mid.save(midi_path)
99
- return midi_path
100
 
101
  def generate_svg(self, midi_file, output_file_name):
102
  return Format_Converter().midi_to_svg_file(tk, midi_file, output_file_name)
@@ -132,7 +112,7 @@ class HexachordApp:
132
  return "Invalid input. Enter 6 notes separated by spaces."
133
  fm = Format_Converter()
134
  chords = self.generate_chords(notes, itvl)
135
- midi_path = self.create_midi(chords, "base_chords.mid")
136
  score_path = fm.midi_to_svg_file(tk, midi_path, "score_base_chords.svg")
137
  audio_path = fm.convert_midi_to_audio(midi_path, "base_chords")
138
  return (midi_path, score_path, audio_path) + self.generate_realizations()
@@ -143,7 +123,7 @@ class HexachordApp:
143
  for index_of_chord in range(6):
144
  chords = [real[index_of_chord] for real in self._hexachord._realizations]
145
  fm = Format_Converter()
146
- midi_path = self.create_midi(chords, f"movement{index_of_chord}.mid")
147
  score_path = fm.midi_to_svg_file(tk, midi_path, f"movement{index_of_chord}.svg")
148
  audio_path = fm.convert_midi_to_audio(midi_path, f"movement{index_of_chord}")
149
  everyone = everyone + (midi_path, score_path, audio_path)
 
3
  import numpy as np
4
  from mido import Message, MidiFile, MidiTrack
5
  import os
6
+ from music21 import converter, note, stream, chord, tempo, meter
7
  import hexachords
8
  from format_conversions import Format_Converter
9
  import verovio
10
  import subprocess
11
 
12
+ from legacy.essai_mido_to_xml import midi_path
13
+
14
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
15
 
16
  def get_verovio_resource_path():
 
56
  return False
57
 
58
  def generate_chords(self, note_names, itvl):
 
 
59
  interval_21 = 'P5'
60
  if itvl == 'fourth':
61
  interval_21 = 'P4'
 
63
 
64
  def generate_realizations(self):
65
  # returns triples of midipath, score image, audio player
 
66
  reals = self._hexachord.generate_3_chords_realizations(self._hexachord._base_sequence)
67
+ all_paths = []
68
+ fm = Format_Converter()
69
+ for i, real in enumerate(reals):
70
+ midi_path = f"real{i}.mid"
71
+ all_paths.append(self.create_midi_file(real, midi_path))
72
+ all_paths.append(fm.midi_to_svg_file(tk, midi_path, f"real{i}.svg"))
73
+ all_paths.append(fm.convert_midi_to_audio(midi_path, f"real{i}"))
74
+ return tuple(all_paths)
75
+
76
+ def create_midi_file(self, chords, file_name, duration_in_quarter_lengths=4.0, tempo_bpm=120, time_signature="4/4"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  midi_path = os.path.join(BASE_DIR, file_name)
78
+ self._hexachord.save_chords_to_midi_file(chords, midi_path)
79
+ return file_name
80
 
81
  def generate_svg(self, midi_file, output_file_name):
82
  return Format_Converter().midi_to_svg_file(tk, midi_file, output_file_name)
 
112
  return "Invalid input. Enter 6 notes separated by spaces."
113
  fm = Format_Converter()
114
  chords = self.generate_chords(notes, itvl)
115
+ midi_path = self.create_midi_file(chords, "base_chords.mid")
116
  score_path = fm.midi_to_svg_file(tk, midi_path, "score_base_chords.svg")
117
  audio_path = fm.convert_midi_to_audio(midi_path, "base_chords")
118
  return (midi_path, score_path, audio_path) + self.generate_realizations()
 
123
  for index_of_chord in range(6):
124
  chords = [real[index_of_chord] for real in self._hexachord._realizations]
125
  fm = Format_Converter()
126
+ midi_path = self.create_midi_file(chords, f"movement{index_of_chord}.mid")
127
  score_path = fm.midi_to_svg_file(tk, midi_path, f"movement{index_of_chord}.svg")
128
  audio_path = fm.convert_midi_to_audio(midi_path, f"movement{index_of_chord}")
129
  everyone = everyone + (midi_path, score_path, audio_path)
format_conversions.py CHANGED
@@ -53,66 +53,13 @@ class Format_Converter:
53
  musicxml_str = exporter.parse().decode('utf-8')
54
  return musicxml_str
55
 
56
- @classmethod
57
- def midi_to_musicxml_string_two_staves_old(cls, midi_path):
58
- # Parse MIDI file into a music21 stream
59
- score = converter.parse(midi_path)
60
- score = score.flattenParts()
61
- # Create a new Score with two staves: Treble and Bass
62
- treble = stream.Part()
63
- bass = stream.Part()
64
- treble.id = 'Treble'
65
- bass.id = 'Bass'
66
- # Assign clefs (optional but recommended)
67
- from music21 import clef
68
- treble.insert(0, clef.TrebleClef())
69
- bass.insert(0, clef.BassClef())
70
- split_pitch = 60
71
- # Split notes by pitch (simple heuristic)
72
- treble_voice = stream.Voice()
73
- bass_voice = stream.Voice()
74
- for el in score.recurse().notesAndRests:
75
- true_offset = el.getOffsetInHierarchy(score)
76
- if isinstance(el, note.Rest):
77
- # Send same rest to both staves (or adjust as needed)
78
- treble.insert(true_offset, el)
79
- bass.insert(true_offset, el)
80
-
81
- elif isinstance(el, note.Note):
82
- target = treble if el.pitch.midi >= split_pitch else bass
83
- target.insert(true_offset, el)
84
-
85
- elif isinstance(el, chord.Chord):
86
- # Split the chord into individual notes
87
- for p in el.pitches:
88
- n = note.Note(p)
89
- n.quarterLength = el.quarterLength
90
- n.volume = el.volume
91
- if p.midi >= split_pitch:
92
- treble_voice.insert(true_offset, n)
93
- else:
94
- bass_voice.insert(true_offset, n)
95
- # Combine the two parts into a score
96
- treble.append(treble_voice)
97
- bass.append(bass_voice)
98
- new_score = stream.Score()
99
- new_score.insert(0, treble)
100
- new_score.insert(0, bass)
101
- # staff_group = StaffGroup([bass, treble], symbol='brace', barTogether=True)
102
- # new_score.insert(0, staff_group)
103
- # Export to MusicXML string
104
- exporter = musicxml.m21ToXml.GeneralObjectExporter(new_score)
105
- musicxml_str = exporter.parse().decode('utf-8') # parse() returns bytes
106
- return musicxml_str
107
-
108
  @classmethod
109
  def midi_to_musicxml_string(cls, midi_path):
110
  # Parse MIDI file into a music21 stream
111
  score = converter.parse(midi_path)
112
  # Export to MusicXML string
113
  exporter = musicxml.m21ToXml.GeneralObjectExporter(score)
114
- musicxml_str = exporter.parse().decode('utf-8') # parse() returns bytes
115
- return musicxml_str
116
 
117
  @classmethod
118
  def xml_to_mei_string(cls, tk, xmlstring):
@@ -123,8 +70,8 @@ class Format_Converter:
123
  def midi_to_svg(cls, tk, midi_path):
124
  try:
125
  # Convert MIDI to MEI using music21
126
- musicxml = cls.midi_to_musicxml_string(midi_path)
127
- mei_str = cls.xml_to_mei_string(tk, musicxml)
128
  # Load MEI and render SVG
129
  tk.loadData(mei_str)
130
  svg = tk.renderToSVG(1)
@@ -132,7 +79,6 @@ class Format_Converter:
132
  except Exception as e:
133
  return f"<p style='color:red'>Error: {e}</p>"
134
 
135
-
136
  @classmethod
137
  def midi_to_svg_file(cls, tk, midi_path, output_file):
138
  try:
@@ -148,6 +94,29 @@ class Format_Converter:
148
  # return f"<p style='color:red'>Error: {e}</p>"
149
  return output_file
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  def convert_midi_to_audio(self, midi_path, file_name):
152
  if not shutil.which("fluidsynth"):
153
  try:
 
53
  musicxml_str = exporter.parse().decode('utf-8')
54
  return musicxml_str
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  @classmethod
57
  def midi_to_musicxml_string(cls, midi_path):
58
  # Parse MIDI file into a music21 stream
59
  score = converter.parse(midi_path)
60
  # Export to MusicXML string
61
  exporter = musicxml.m21ToXml.GeneralObjectExporter(score)
62
+ return exporter.parse().decode('utf-8') # parse() returns bytes
 
63
 
64
  @classmethod
65
  def xml_to_mei_string(cls, tk, xmlstring):
 
70
  def midi_to_svg(cls, tk, midi_path):
71
  try:
72
  # Convert MIDI to MEI using music21
73
+ musicxmlobj = cls.midi_to_musicxml_string(midi_path)
74
+ mei_str = cls.xml_to_mei_string(tk, musicxmlobj)
75
  # Load MEI and render SVG
76
  tk.loadData(mei_str)
77
  svg = tk.renderToSVG(1)
 
79
  except Exception as e:
80
  return f"<p style='color:red'>Error: {e}</p>"
81
 
 
82
  @classmethod
83
  def midi_to_svg_file(cls, tk, midi_path, output_file):
84
  try:
 
94
  # return f"<p style='color:red'>Error: {e}</p>"
95
  return output_file
96
 
97
+ @classmethod
98
+ def m21_to_xml(cls, m21):
99
+ # Export to MusicXML string
100
+ exporter = musicxml.m21ToXml.GeneralObjectExporter()
101
+ return exporter.parse(m21).decode('utf-8')
102
+
103
+ @classmethod
104
+ def m21_to_svg_file(cls, m21, output_file):
105
+ # Export to MusicXML string
106
+ exporter = musicxml.m21ToXml.GeneralObjectExporter()
107
+ musicxmlobj = exporter.parse(m21).decode('utf-8')
108
+ try:
109
+ tk = verovio.toolkit()
110
+ mei_str = cls.xml_to_mei_string(tk, musicxmlobj)
111
+ # Load MEI and render SVG
112
+ tk.loadData(mei_str)
113
+ svg = tk.renderToSVGFile(output_file)
114
+ return output_file
115
+ except Exception as e:
116
+ print("error in midi_to_svg_file")
117
+ # return f"<p style='color:red'>Error: {e}</p>"
118
+ return output_file
119
+
120
  def convert_midi_to_audio(self, midi_path, file_name):
121
  if not shutil.which("fluidsynth"):
122
  try:
hexachords.py CHANGED
@@ -1,3 +1,6 @@
 
 
 
1
  from music21 import note, stream, interval, meter, chord
2
  from ortools.sat.python import cp_model
3
 
@@ -82,17 +85,30 @@ class Hexachord:
82
  self._realizations = res1, res2, res3
83
  return self._realizations
84
 
85
- def chords_to_stream(self, chords, file_name):
86
  s = stream.Stream()
87
  s.append(meter.TimeSignature("4/4"))
88
  for c in chords:
89
  ch = chord.Chord(c)
90
  ch.duration.quarterLength = 4
91
  s.append(ch)
92
- # s.show('midi')
93
- s.write('midi', file_name)
94
  return s
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  def alternate_chords(self, s1, s2):
97
  """Create a new stream alternating between chords from s1 and s2"""
98
  new_stream = stream.Stream()
@@ -160,6 +176,7 @@ class Hexachord:
160
 
161
  return optimized_chords
162
 
 
163
  if __name__ == '__main__':
164
  hexa = Hexachord()
165
  note_names = ["C3", "Eb3", "E3", "F#3", "G3", "Bb3"]
@@ -170,7 +187,7 @@ if __name__ == '__main__':
170
  # alternation = alternate_chords(cs1, cs2)
171
  # alternation.write('midi',"alternation.mid")
172
 
173
- hexa.chords_to_stream(cs1, 'temp.mid').show('text')
174
  # optimized = optimize_voice_leading([c1, c2, c3])
175
  optimized = hexa.optimize_voice_leading(cs1)
176
  stream1 = stream.Stream(optimized)
 
1
+ import os
2
+
3
+ from mido import MidiFile, Message, MidiTrack
4
  from music21 import note, stream, interval, meter, chord
5
  from ortools.sat.python import cp_model
6
 
 
85
  self._realizations = res1, res2, res3
86
  return self._realizations
87
 
88
+ def chords_to_m21(self, chords):
89
  s = stream.Stream()
90
  s.append(meter.TimeSignature("4/4"))
91
  for c in chords:
92
  ch = chord.Chord(c)
93
  ch.duration.quarterLength = 4
94
  s.append(ch)
 
 
95
  return s
96
 
97
+ def chords_to_m21_voices(self, chords):
98
+ s = stream.Stream()
99
+ s.append(meter.TimeSignature("4/4"))
100
+ for i_chord, c in enumerate(chords):
101
+ for chord_note in c:
102
+ n = note.Note(chord_note.pitch)
103
+ n.duration.quarterLength = 4
104
+ s.insert(i_chord * 4, n)
105
+ return s
106
+
107
+ def save_chords_to_midi_file(self, chords, file_name):
108
+ m21 = self.chords_to_m21_voices(chords)
109
+ m21.write('midi', file_name)
110
+ return file_name
111
+
112
  def alternate_chords(self, s1, s2):
113
  """Create a new stream alternating between chords from s1 and s2"""
114
  new_stream = stream.Stream()
 
176
 
177
  return optimized_chords
178
 
179
+
180
  if __name__ == '__main__':
181
  hexa = Hexachord()
182
  note_names = ["C3", "Eb3", "E3", "F#3", "G3", "Bb3"]
 
187
  # alternation = alternate_chords(cs1, cs2)
188
  # alternation.write('midi',"alternation.mid")
189
 
190
+ hexa.save_chords_to_midi_file(cs1, 'temp.mid')
191
  # optimized = optimize_voice_leading([c1, c2, c3])
192
  optimized = hexa.optimize_voice_leading(cs1)
193
  stream1 = stream.Stream(optimized)
legacy/essai.py DELETED
@@ -1,37 +0,0 @@
1
- import verovio
2
- import os
3
-
4
- def get_verovio_resource_path():
5
- for path in verovio.__path__:
6
- candidate = os.path.join(path, "data")
7
- if os.path.exists(candidate):
8
- return candidate
9
- return None
10
-
11
- def render_mei(mei_path):
12
- tk = verovio.toolkit()
13
- # Set resource path explicitly
14
- resource_path = get_verovio_resource_path()
15
- print("[Debug] Using resource path:", resource_path)
16
- if resource_path:
17
- try:
18
- tk.setResourcePath(resource_path)
19
- except Exception as e:
20
- print("[Error] Failed to set resourcePath:", e)
21
- # tk.setOptions({
22
- # "font": "/app/data/Bravura", # Path to the font folder
23
- # })
24
- with open(mei_path, "r", encoding="utf-8") as f:
25
- mei_data = f.read()
26
- # tk.loadFile("path-to-mei-file")
27
- # return tk.renderToSVG(1)
28
-
29
- try:
30
- tk.loadData(mei_data)
31
- return tk.renderToSVG(1)
32
- except Exception as e:
33
- return f"<pre>Rendering failed:\n{e}</pre>"
34
-
35
-
36
- string = render_mei("output.mei")
37
- print(string)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
legacy/essai_m21_to_xml_Measure.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from music21 import stream, note, tie, meter
2
+ # working version but using Measure
3
+ from format_conversions import Format_Converter
4
+
5
+ # Create Voice 1 (tied C4 over two half notes)
6
+ voice1 = stream.Voice()
7
+ n1 = note.Note('C4', quarterLength=2.0)
8
+ n1.tie = tie.Tie('start')
9
+ n2 = note.Note('C4', quarterLength=2.0)
10
+ n2.tie = tie.Tie('stop')
11
+ voice1.append([n1, n2])
12
+ voice1.append(note.Note('E4', quarterLength=2.0))
13
+
14
+ # Create Voice 2 (a single E4 half note)
15
+ voice2 = stream.Voice()
16
+ voice2.append(note.Note('E4', quarterLength=2.0))
17
+ voice2.append(note.Note('G4', quarterLength=2.0))
18
+ voice2.append(note.Note('C5', quarterLength=2.0))
19
+ voice2.append(note.Note('D5', quarterLength=2.0))
20
+ voice2.append(note.Note('E5', quarterLength=2.0))
21
+ voice2.append(note.Note('G5', quarterLength=2.0))
22
+
23
+ voice3 = stream.Voice()
24
+ voice3.append(note.Note('G4', quarterLength=2.0))
25
+ voice3.append(note.Note('C5', quarterLength=2.0))
26
+ voice3.append(note.Note('E5', quarterLength=2.0))
27
+
28
+ # Put both voices into a Measure
29
+ measure = stream.Measure()
30
+ measure.timeSignature = meter.TimeSignature('4/4') # optional, but helpful
31
+ measure.insert(0, voice1)
32
+ measure.insert(0, voice2)
33
+ measure.insert(0, voice3)
34
+
35
+ # Wrap in a Part and Score
36
+ part = stream.Part()
37
+ part.append(measure)
38
+
39
+ score = stream.Score()
40
+ score.append(part)
41
+
42
+ # Write to MusicXML
43
+ score.write('musicxml', fp='two_voice_example.musicxml')
44
+ Format_Converter().m21_to_svg_file(score, "output.svg")
legacy/essai_mido_to_xml.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import verovio
4
+ from mido import MidiFile, MidiTrack, Message
5
+ from music21 import stream
6
+
7
+ from format_conversions import Format_Converter
8
+
9
+ mid = MidiFile()
10
+ track = MidiTrack()
11
+ mid.tracks.append(track)
12
+ delta_time = 480 * 4
13
+
14
+ track.append(Message('note_on', note=60, velocity=64, time=0))
15
+ track.append(Message('note_on', note=64, velocity=64, time=0))
16
+
17
+ track.append(Message('note_off', note=60, velocity=0, time=delta_time))
18
+ track.append(Message('note_on', note=62, velocity=64, time=0))
19
+ track.append(Message('note_off', note=62, velocity=0, time=delta_time))
20
+ track.append(Message('note_off', note=64, velocity=0, time=0))
21
+
22
+ midi_path = os.path.join("","output.mid")
23
+ mid.save(midi_path)
24
+ str = Format_Converter().midi_to_musicxml_string("output.mid")
25
+ with open("output.musicxml", "a") as f:
26
+ f.write(str)
27
+ Format_Converter().midi_to_svg_file(verovio.toolkit(), "output.mid", "output2.svg")
legacy/essai_music21_to_xml.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from music21 import stream, chord, note, tie
2
+
3
+ from format_conversions import Format_Converter
4
+
5
+ # Create two voices
6
+ voice1 = stream.Voice()
7
+ voice2 = stream.Voice()
8
+
9
+ n1 = note.Note('C4', quarterLength=2.0)
10
+ voice1.append(n1)
11
+ n2 = note.Note('C4', quarterLength=2.0)
12
+ voice1.append(n2)
13
+
14
+ voice2.append(note.Note('E4', quarterLength=2.0))
15
+ voice2.append(note.Note('G4', quarterLength=2.0))
16
+ # voice2.append(note.Note('A4', quarterLength=2.0))
17
+
18
+ n1.tie = tie.Tie('start') # beginning of tie
19
+ n2.tie = tie.Tie('stop')
20
+ # Combine them into a part
21
+ part = stream.Part()
22
+ part.insert(0, voice1)
23
+ part.insert(0, voice2)
24
+
25
+ score = stream.Score()
26
+ score.append(part)
27
+ # score.show('midi')
28
+ # score.show('musicxml')
29
+ Format_Converter().m21_to_svg_file(score, 'essai.svg')
30
+ score.write('musicxml', fp='my_score.musicxml')
31
+ # xml = Format_Converter().m21_to_xml(score)
32
+ # with open("my_score.musicxml", "w", encoding="utf-8") as f:
33
+ # f.write(xml)
legacy/example.mei DELETED
@@ -1,28 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="4.0.0">
3
- <music>
4
- <body>
5
- <mdiv>
6
- <score>
7
- <scoreDef>
8
- <staffGrp>
9
- <staffDef n="1" lines="5"/>
10
- </staffGrp>
11
- </scoreDef>
12
- <section>
13
- <measure n="1">
14
- <staff n="1">
15
- <layer n="1">
16
- <note pname="c" oct="4" dur="4"/>
17
- <note pname="d" oct="4" dur="4"/>
18
- <note pname="e" oct="4" dur="4"/>
19
- <note pname="f" oct="4" dur="4"/>
20
- </layer>
21
- </staff>
22
- </measure>
23
- </section>
24
- </score>
25
- </mdiv>
26
- </body>
27
- </music>
28
- </mei>