示例#1
0
 def test_contructor(self):
     Note(MusicalPitch.new_from_notename("c'"),
          Duration.new_from_string("4."))
     self.assertRaises(AssertionError, Note, "4.",
                       MusicalPitch.new_from_notename("c'"))
     self.assertRaises(AssertionError, Note, Duration.new_from_string("4."),
                       "c'")
示例#2
0
 def fill_skips(self, voice):
     """
     Add Skips at the end of the bar, so that it is filled.
     We assume that any elements already added are placed at
     the correct timepos.
     """
     # nt = short for "next timepos", the timepos to start fill skips to
     if voice.get_timeposes_of(self):
         nt = voice.get_timeposes_of(self)[-1]
         nt = nt + voice.m_tdict[nt]['elem'][0].m_duration.get_rat_value()
     else:
         # we get here if the bar is empty
         nt = self.m_timepos
     default_skip = Rat(1, 4)
     # pos within default skip
     pp =  nt - int (nt / default_skip) * default_skip
     if pp != Rat(0, 1):
         # Here we add a skip so that the next column will be X times
         # default_skip
         voice.set_elem([Skip(Duration.new_from_rat(default_skip - pp))],
                       nt)
         nt += (default_skip - pp)
     # And the we fill the bar with Skips as long as default_skip.
     while nt < self.end():
         voice.set_elem([Skip(Duration.new_from_rat(default_skip))], nt)
         nt += default_skip
示例#3
0
 def test_contructor(self):
     Note(MusicalPitch.new_from_notename("c'"),
          Duration.new_from_string("4."))
     self.assertRaises(AssertionError,
                       Note, "4.", MusicalPitch.new_from_notename("c'"))
     self.assertRaises(AssertionError,
                       Note, Duration.new_from_string("4."), "c'")
示例#4
0
 def fill_skips(self, voice):
     """
     Add Skips at the end of the bar, so that it is filled.
     We assume that any elements already added are placed at
     the correct timepos.
     """
     # nt = short for "next timepos", the timepos to start fill skips to
     if voice.get_timeposes_of(self):
         nt = voice.get_timeposes_of(self)[-1]
         nt = nt + voice.m_tdict[nt]['elem'][0].m_duration.get_rat_value()
     else:
         # we get here if the bar is empty
         nt = self.m_timepos
     default_skip = Rat(1, 4)
     # pos within default skip
     pp = nt - int(nt / default_skip) * default_skip
     if pp != Rat(0, 1):
         # Here we add a skip so that the next column will be X times
         # default_skip
         voice.set_elem([Skip(Duration.new_from_rat(default_skip - pp))],
                        nt)
         nt += (default_skip - pp)
     # And the we fill the bar with Skips as long as default_skip.
     while nt < self.end():
         voice.set_elem([Skip(Duration.new_from_rat(default_skip))], nt)
         nt += default_skip
示例#5
0
 def test_tuplets(self):
     n1 = Note(MusicalPitch.new_from_notename("g'"),
               Duration(8, 0, Rat(2, 3)))
     n2 = Note(MusicalPitch.new_from_notename("g'"),
               Duration(8, 0, Rat(2, 3)))
     n3 = Note(MusicalPitch.new_from_notename("g'"),
               Duration(8, 0, Rat(2, 3)))
     self.score.voice11.append(n1)
     self.score.voice11.append(n2)
     self.score.voice11.append(n3)
     self.score.voice11.tuplet(Rat(2, 3), const.UP, [n1, n2, n3])
示例#6
0
 def test_misc(self):
     d1 = Duration(4, 0, Rat(1, 1))
     d2 = Duration(4, 1, Rat(1, 1))
     self.assertFalse(d1 == d2)
     self.assertEquals(d1.get_rat_value(), Rat(1, 4))
     self.assertEquals(d2.get_rat_value(), Rat(3, 8))
     d3 = Duration(4, 2, Rat(2, 3))
     self.assertEquals(d3.get_rat_value(), Rat(7, 24))
示例#7
0
 def test_bar_fill_skips(self):
     n1 = Note(MusicalPitch.new_from_notename("g'"), Duration(4, 0))
     self.score.voice11.append(n1)
     self.score.voice11.append(Rest(Duration.new_from_string("4")))
     self.bp.fill_skips()
     self.assertTrue(
         isinstance(self.score.voice11.m_tdict[Rat(0, 1)]['elem'][0], Note))
     self.assertTrue(
         isinstance(self.score.voice11.m_tdict[Rat(1, 4)]['elem'][0], Rest))
     self.assertTrue(
         isinstance(self.score.voice11.m_tdict[Rat(1, 2)]['elem'][0], Skip))
     self.assertTrue(
         isinstance(self.score.voice11.m_tdict[Rat(3, 4)]['elem'][0], Skip))
示例#8
0
 def __init__(self, duration, dots):
     """duration: integer 1 for 1/1 note 4 for 1/4 etc
     """
     if duration:
         self.m_duration = Duration(duration, dots, Rat(1, 1))
     else:
         self.m_duration = None
示例#9
0
 def __init__(self, s):
     if not isinstance(s, str):
         s = s.decode("utf-8")
     assert isinstance(s, str)
     self.m_string = s
     self.m_notelen = Duration(4, 0)
     self.m_idx = 0
     self.m_last_idx = None
示例#10
0
 def test_bar_fill_skips(self):
     n1 = Note(MusicalPitch.new_from_notename("g'"),
               Duration(4, 0))
     self.score.voice11.append(n1)
     self.score.voice11.append(Rest(Duration.new_from_string("4")))
     self.bp.fill_skips()
     self.assertTrue(isinstance(self.score.voice11.m_tdict[Rat(0, 1)]['elem'][0], Note))
     self.assertTrue(isinstance(self.score.voice11.m_tdict[Rat(1, 4)]['elem'][0], Rest))
     self.assertTrue(isinstance(self.score.voice11.m_tdict[Rat(1, 2)]['elem'][0], Skip))
     self.assertTrue(isinstance(self.score.voice11.m_tdict[Rat(3, 4)]['elem'][0], Skip))
示例#11
0
 def test_add_partial_bar(self):
     self.score.add_partial_bar(Duration.new_from_string("4"), TimeSignature(4, 4))
     self.score.add_bar(None)
     self.assertEqual(self.score.m_bars[0].m_timepos, Rat(0, 1))
     self.assertEqual(self.score.m_bars[0].end(), Rat(1, 4))
     self.assertEqual(self.score.m_bars[1].m_timepos, Rat(1, 4))
     self.assertEqual(self.score.get_bar_at(Rat(0, 1)), self.score.m_bars[0])
     self.assertEqual(self.score.get_bar_at(Rat(1, 4)), self.score.m_bars[1])
     self.score.voice11.append(Note.new_from_string("c4"))
     self.score.voice11.append(Note.new_from_string("c1"))
     self.score.voice11.append(Note.new_from_string("c1"))
示例#12
0
 def new_from_string(string):
     s = string.strip()
     m = re_melodic.match(s)
     if m.end() < len(s) - 1:
         # FIXME: raise ValueError like rest
         raise Note.Exception("characters left in string", string)
     return Note(
         MusicalPitch.new_from_notename(
             "%s%s" % (m.group('notename'), m.group('octave'))),
         Duration.new_from_string("%s%s" %
                                  (m.group('len'), m.group('dots'))))
示例#13
0
 def new_from_string(string):
     s = string.strip()
     m = re_melodic.match(s)
     if m.end() < len(s) - 1:
         # FIXME: raise ValueError like rest
         raise Note.Exception("characters left in string", string)
     return Note(
         MusicalPitch.new_from_notename("%s%s" % (m.group('notename'),
                                                  m.group('octave'))),
         Duration.new_from_string("%s%s" % (m.group('len'), m.group('dots')))
     )
示例#14
0
 def test_misc(self):
     d1=Duration(4, 0, Rat(1, 1))
     d2=Duration(4, 1, Rat(1, 1))
     self.assertFalse(d1 == d2)
     self.assertEquals(d1.get_rat_value(), Rat(1, 4))
     self.assertEquals(d2.get_rat_value(), Rat(3, 8))
     d3=Duration(4, 2, Rat(2, 3))
     self.assertEquals(d3.get_rat_value(), Rat(7, 24))
示例#15
0
 def test_add_partial_bar(self):
     self.score.add_partial_bar(Duration.new_from_string("4"),
                                TimeSignature(4, 4))
     self.score.add_bar(None)
     self.assertEqual(self.score.m_bars[0].m_timepos, Rat(0, 1))
     self.assertEqual(self.score.m_bars[0].end(), Rat(1, 4))
     self.assertEqual(self.score.m_bars[1].m_timepos, Rat(1, 4))
     self.assertEqual(self.score.get_bar_at(Rat(0, 1)),
                      self.score.m_bars[0])
     self.assertEqual(self.score.get_bar_at(Rat(1, 4)),
                      self.score.m_bars[1])
     self.score.voice11.append(Note.new_from_string("c4"))
     self.score.voice11.append(Note.new_from_string("c1"))
     self.score.voice11.append(Note.new_from_string("c1"))
示例#16
0
 def test_midigen_rest(self):
     self.score.voice11.append(Note.new_from_string("c4"))
     self.score.voice11.append(Rest(Duration.new_from_string("4")))
     self.score.voice11.append(Note.new_from_string("c4"))
     t = mpd.score_to_tracks(self.score)
     self.assertEqual(t[0].str_repr(), "n48 d1/4 o48 d1/4 n48 d1/4 o48")
示例#17
0
 def test_set_from_rat(self):
     for i in (1, 2, 4, 8, 16, 32, 64):
         d = Duration.new_from_rat(Rat(1, i))
         self.assertEquals(d, Duration(i, 0))
     d = Duration.new_from_rat(Rat(3, 8))
     self.assertEquals(d.get_rat_value(), Rat(3, 8))
示例#18
0
 def test_new_from_string(self):
     d = Duration.new_from_string("4")
     self.assertEquals(d.get_rat_value(), Rat(1, 4))
     self.assertRaises(Duration.BadStringException,
         Duration.new_from_string, "44x")
示例#19
0
 def test_constructor(self):
     for a, b, f in ((1, 0, 1.0), (2, 0, 0.5), (2, 1, 0.75)):
         d = Duration(a, b)
         r = d.get_rat_value()
         self.assertEquals(float(r), f)
示例#20
0
 def test_set_from_rat(self):
     for i in (1, 2, 4, 8, 16, 32, 64):
         d = Duration.new_from_rat(Rat(1, i))
         self.assertEquals(d, Duration(i, 0))
     d = Duration.new_from_rat(Rat(3, 8))
     self.assertEquals(d.get_rat_value(), Rat(3, 8))
示例#21
0
 def test_add_rest(self):
     self.score.voice11.append(Rest(Duration.new_from_string("8")))
     self.assertIsInstance(self.score.voice11.m_tdict[Rat(0, 1)]['elem'][0], Rest)
     self.assertIsInstance(self.score.voice11.m_tdict[Rat(0, 1)]['elem'][0].w_parent(), Voice)
示例#22
0
 def test_add_rest(self):
     self.score.voice11.append(Rest(Duration.new_from_string("8")))
     self.assertIsInstance(self.score.voice11.m_tdict[Rat(0, 1)]['elem'][0],
                           Rest)
     self.assertIsInstance(
         self.score.voice11.m_tdict[Rat(0, 1)]['elem'][0].w_parent(), Voice)
示例#23
0
def parse_to_score_object(music):
    lexer = Lexer(music)
    relative_mode = None
    relto = None
    transpose_pitch = None
    TOPLEVEL = 1  # 'toplevel'
    NOTES = 2  # 'notes'
    START_OF_CHORD = 3  # 'start-of-chord'
    CHORD = 4  # 'chord'
    context = TOPLEVEL
    score = elems.Score()
    chord_duration = None
    cur_duration = Duration(4, 0)
    tie_is_in_the_air = 0
    beam = None
    # None when not parsing notes in a tuplet. Item 0 is the ration and 1.. is the notes
    times = None
    cur_staff = None
    # we set it just so pyflakes does not complain.
    relto_backup = None
    # This variable is set to the duration of the pickup bar from we parse
    # \partial nn until the bar has been created.
    partial = None
    for toc, toc_data in lexer:
        try:
            if toc_data.m_duration:
                cur_duration = toc_data.m_duration.clone()
        except AttributeError:
            pass
        if toc == Lexer.STAFF:
            assert context == TOPLEVEL
            cur_staff = score.add_staff(elems.Staff)
            cur_voice = cur_staff.m_voices[-1]
            stem_dir = const.BOTH
            tuplet_dir = const.BOTH
            relative_mode = None
            timepos = Rat(0)
            last_pos = timepos
        elif toc == Lexer.RHYTHMSTAFF:
            assert context == TOPLEVEL
            cur_staff = score.add_staff(elems.RhythmStaff)
            cur_voice = cur_staff.m_voices[-1]
            stem_dir = const.BOTH
            tuplet_dir = const.BOTH
            relative_mode = None
            timepos = Rat(0)
            last_pos = timepos
        elif toc == Lexer.VOICE:
            if not cur_staff:
                raise ParseError("Don't use \\addvoice before \\staff", lexer)
            relative_mode = None
            timepos = Rat(0)
            cur_voice = cur_staff.add_voice()
        elif toc == Lexer.RELATIVE:
            assert not relative_mode
            relative_mode = 1
            relto = toc_data
        elif toc == Lexer.TRANSPOSE:
            transpose_pitch = toc_data
        elif toc == Lexer.PARTIAL:
            partial = toc_data
        elif toc == Lexer.TIME:
            if not cur_staff:
                raise ParseError("\\time can not be used before \\staff", lexer)
            # FIXME
            # Also now, we only allow the first voice to change time signatures
            if cur_staff.m_voices.index(cur_voice) != 0:
                raise ParseError("only timesig in first voice", lexer)
            # FIXME: we are stricter with time signatures that both solfege 3.16
            # and LilyPond
            if not cur_voice.is_bar_full():
                raise ParseError("timesig change only when bar is full!", lexer)
            if partial:
                score.add_partial_bar(partial, toc_data)
                partial = None
            else:
                score.add_bar(toc_data)
        elif toc == Lexer.KEY:
            p = MusicalPitch.new_from_notename(toc_data[0])
            if transpose_pitch:
                p.transpose_by_musicalpitch(transpose_pitch)
            k = (p.get_notename(), toc_data[1])
            if not cur_staff:
                raise ParseError("\\key can not be used before \\staff", lexer)
            cur_staff.set_key_signature(k, timepos)
        elif toc == Lexer.TIMES:
            if not times:
                times = [toc_data]
            else:
                raise ParseError(r"\times nn/nn does not nest", lexer)
        elif toc == Lexer.CLEF:
            try:
                cur_staff.set_clef(toc_data, timepos)
            except elems.UnknownClefException as e:
                e.m_lineno, e.m_linepos1, e.m_linepos2 = lexer.get_error_location()
                raise
        elif toc == '|':
            if timepos != score.get_bar_at(last_pos).end():
                logging.warning("Bar check failed at %s", timepos)
        elif toc == '{':
            if (context == TOPLEVEL):
                context = NOTES
                # if not cur_staff.m_coldict[Rat(0, 1)].m_keysignature:
                # FIXME dont understand
                if transpose_pitch:
                    k = (transpose_pitch.get_notename(), 'major')
                else:
                    k = ('c', 'major')
                cur_voice.set_key_signature(k)
            else:
                raise ParseError("Token '{' not allowed here.", lexer)
        elif toc == '<':
            if context == NOTES:
                context = START_OF_CHORD
            else:
                raise ParseError("Token '<' not allowed here.", lexer)
        elif toc == '>':
            if context == CHORD:
                if tie_is_in_the_air:
                    # The 3.16-parser only handles ties between whole chords, not
                    # single tones of a chord.
                    if tie_is_in_the_air:
                        for last_note in cur_voice.m_tdict[last_pos]['elem']:
                            for cur_note in cur_voice.m_tdict[timepos]['elem']:
                                if last_note.m_musicalpitch.get_octave_notename() == cur_note.m_musicalpitch.get_octave_notename():
                                    cur_voice.tie([last_note, cur_note])
                    tie_is_in_the_air = 0
                last_pos = timepos
                timepos = timepos + chord_duration.get_rat_value()
                chord_duration = None
                relto = relto_backup
                relto_backup = None
                context = NOTES
            else:
                raise ParseError("Token '>' not allowed here.", lexer)
        elif toc == '}':
            if context == NOTES:
                if times:
                    cur_voice.tuplet(times[0], tuplet_dir, times[1:])
                    times = None
                    cur_duration.m_tuplet = Rat(1, 1)
                else:
                    context = TOPLEVEL
            else:
                raise ParseError("Token '}' not allowed here.", lexer)
        elif toc == '[':
            beam = []
        elif toc == ']':
            cur_voice.beam(beam)
            beam = None
        elif toc == '~':
            tie_is_in_the_air = 1
        elif toc == Lexer.NOTE and (context in [NOTES, CHORD, START_OF_CHORD]):
            # FIXME check if toc_data.m_duration will ever be undefined.
            # If not we can do this:   if not toc_data.m_duration:
            if not getattr(toc_data, 'm_duration', None):
                toc_data.m_duration = cur_duration.clone()
            if times:
                toc_data.m_duration.m_tuplet = times[0].clone()
            if relative_mode:
                toc_data.m_pitch = musicalpitch_relative(
                                          relto, toc_data.m_pitch)
                relto = toc_data.m_pitch.clone()
            if transpose_pitch:
                toc_data.transpose(transpose_pitch)
            if partial:
                score.add_partial_bar(partial, None)
                partial = None
            if context == NOTES:
                note = elems.Note(toc_data.m_pitch, toc_data.m_duration)
                try:
                    cur_voice.append(note, stem_dir)
                except elems.Voice.BarFullException as e:
                    raise ParseError(str(e), lexer)
                if beam is not None:
                    beam.append(note)
                if times is not None:
                    times.append(note)
                # The 3.16-parser only handles ties between whole chords, not
                # single tones of a chord.
                if tie_is_in_the_air:
                    for note in cur_voice.m_tdict[last_pos]['elem']:
                        for n in cur_voice.m_tdict[timepos]['elem']:
                            if n.m_musicalpitch.get_octave_notename() == note.m_musicalpitch.get_octave_notename():
                                cur_voice.tie([note, n])
                    tie_is_in_the_air = 0
                last_pos = timepos
                timepos = timepos + toc_data.m_duration.get_rat_value()
            elif context == START_OF_CHORD:
                cur_voice.append(elems.Note(toc_data.m_pitch, toc_data.m_duration), stem_dir)
                relto_backup = relto
                chord_duration = toc_data.m_duration
                context = CHORD
            elif context == CHORD:
                cur_voice.add_to(timepos, elems.Note(toc_data.m_pitch, toc_data.m_duration))
        elif toc == Lexer.SKIP and context == NOTES:
            if toc_data.m_duration:
                cur_duration = toc_data.m_duration.clone()
            else:
                toc_data.m_duration = cur_duration.clone()
            skip = elems.Skip(toc_data.m_duration)
            cur_voice.append(skip)
            last_pos = timepos
            timepos = timepos + toc_data.m_duration.get_rat_value()
        elif toc == Lexer.REST and context == NOTES:
            if toc_data.m_duration:
                cur_duration = toc_data.m_duration.clone()
            else:
                toc_data.m_duration = cur_duration.clone()
            rest = elems.Rest(toc_data.m_duration)
            cur_voice.append(rest)
            last_pos = timepos
            timepos += toc_data.m_duration.get_rat_value()
        elif toc == Lexer.STEMDIR:
            stem_dir = toc_data
        elif toc == Lexer.TUPLETDIR:
            tuplet_dir = toc_data
        else:
            raise ParseError(toc, lexer)
    return score
示例#24
0
 def new_from_string(string):
     return Skip(Duration.new_from_string(string))
示例#25
0
 def test_constructor(self):
     for a, b, f in ((1, 0, 1.0), (2, 0, 0.5), (2, 1, 0.75)):
         d = Duration(a, b)
         r = d.get_rat_value()
         self.assertEquals(float(r), f)
示例#26
0
 def test_midigen_rest(self):
     self.score.voice11.append(Note.new_from_string("c4"))
     self.score.voice11.append(Rest(Duration.new_from_string("4")))
     self.score.voice11.append(Note.new_from_string("c4"))
     t = mpd.score_to_tracks(self.score)
     self.assertEqual(t[0].str_repr(), "n48 d1/4 o48 d1/4 n48 d1/4 o48")
示例#27
0
def parse_to_score_object(music):
    lexer = Lexer(music)
    relative_mode = None
    relto = None
    transpose_pitch = None
    TOPLEVEL = 1  #'toplevel'
    NOTES = 2  #'notes'
    START_OF_CHORD = 3  #'start-of-chord'
    CHORD = 4  #'chord'
    context = TOPLEVEL
    score = elems.Score()
    chord_duration = None
    cur_duration = Duration(4, 0)
    tie_is_in_the_air = 0
    beam = None
    # None when not parsing notes in a tuplet. Item 0 is the ration and 1.. is the notes
    times = None
    cur_staff = None
    # This variable is set to the duration of the pickup bar from we parse
    # \partial nn until the bar has been created.
    partial = None
    for toc, toc_data in lexer:
        try:
            if toc_data.m_duration:
                cur_duration = toc_data.m_duration.clone()
        except AttributeError:
            pass
        if toc == Lexer.STAFF:
            assert context == TOPLEVEL
            cur_staff = score.add_staff(elems.Staff)
            cur_voice = cur_staff.m_voices[-1]
            stem_dir = const.BOTH
            tuplet_dir = const.BOTH
            relative_mode = None
            timepos = Rat(0)
            last_pos = timepos
        elif toc == Lexer.RHYTHMSTAFF:
            assert context == TOPLEVEL
            cur_staff = score.add_staff(elems.RhythmStaff)
            cur_voice = cur_staff.m_voices[-1]
            stem_dir = const.BOTH
            tuplet_dir = const.BOTH
            relative_mode = None
            timepos = Rat(0)
            last_pos = timepos
        elif toc == Lexer.VOICE:
            if not cur_staff:
                raise ParseError("Don't use \\addvoice before \\staff", lexer)
            relative_mode = None
            timepos = Rat(0)
            cur_voice = cur_staff.add_voice()
        elif toc == Lexer.RELATIVE:
            assert not relative_mode
            relative_mode = 1
            relto = toc_data
        elif toc == Lexer.TRANSPOSE:
            transpose_pitch = toc_data
        elif toc == Lexer.PARTIAL:
            partial = toc_data
        elif toc == Lexer.TIME:
            if not cur_staff:
                raise ParseError(u"\\time can not be used before \\staff",
                                 lexer)
            # FIXME
            # Also now, we only allow the first voice to change time signatures
            if cur_staff.m_voices.index(cur_voice) != 0:
                raise ParseError(u"only timesig in first voice", lexer)
            # FIXME: we are stricter with time signatures that both solfege 3.16
            # and LilyPond
            if not cur_voice.is_bar_full():
                raise ParseError(u"timesig change only when bar is full!",
                                 lexer)
            if partial:
                score.add_partial_bar(partial, toc_data)
                partial = None
            else:
                score.add_bar(toc_data)
        elif toc == Lexer.KEY:
            p = MusicalPitch.new_from_notename(toc_data[0])
            if transpose_pitch:
                p.transpose_by_musicalpitch(transpose_pitch)
            k = (p.get_notename(), toc_data[1])
            if not cur_staff:
                raise ParseError(u"\\key can not be used before \\staff",
                                 lexer)
            cur_staff.set_key_signature(k, timepos)
        elif toc == Lexer.TIMES:
            if not times:
                times = [toc_data]
            else:
                raise ParseError(r"\times nn/nn does not nest", lexer)
        elif toc == Lexer.CLEF:
            try:
                cur_staff.set_clef(toc_data, timepos)
            except elems.UnknownClefException, e:
                e.m_lineno, e.m_linepos1, e.m_linepos2 = lexer.get_error_location(
                )
                raise
        elif toc == '|':
            if timepos != score.get_bar_at(last_pos).end():
                logging.warning("Bar check failed at %s", timepos)
示例#28
0
 def _next(self):
     # Doing this while loop inside the exception clause is a little
     # faster than using a regular expression.
     try:
         while self.m_string[self.m_idx] in (' ', '\n', '\t'):
             self.m_idx += 1
     except IndexError:
         raise StopIteration
     self.m_last_idx = self.m_idx
     m = self.re_rest.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         resttype, notelen, dots = m.groups()
         numdots = len(dots)
         if notelen:
             notelen = int(notelen)
         else:
             notelen = 0
             if numdots:
                 raise LexerError(
                     'Need a digit before dots. Write "%(goodcode)s", not "%(badcode)s".'
                     % {
                         'badcode':
                         m.group().strip(),
                         'goodcode':
                         '%s%i%s' % (resttype, self.m_notelen.m_nh, dots)
                     }, self)
         if notelen is 0:
             return self.REST, RestRequest(None, None)
         else:
             self.m_notelen = Duration(notelen, numdots)
             return self.REST, RestRequest(notelen, numdots)
     m = self.re_skip.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         IGN1, skiplen, dots = m.groups()
         numdots = len(dots)
         if skiplen:
             skiplen = int(skiplen)
             self.m_notelen = Duration(skiplen, numdots)
         else:
             skiplen = 0
             if numdots:
                 raise LexerError(
                     'Need a digit before dots. Write "%(goodcode)s", not "%(badcode)s".'
                     % {
                         'badcode': m.group().strip(),
                         'goodcode': 's%i%s' % (self.m_notelen.m_nh, dots)
                     }, self)
         if skiplen is 0:
             return self.SKIP, SkipRequest(skiplen, numdots)
         else:
             self.m_notelen = Duration(skiplen, numdots)
             return self.SKIP, SkipRequest(skiplen, numdots)
     m = self.re_partial.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         num, dot = m.groups()
         num = int(num)
         dot = len(dot)
         return self.PARTIAL, Duration(num, dot)
     m = self.re_melodic.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         notename, IGN1, IGN2, notelen, dots = m.groups()
         numdots = len(dots)
         if notelen:
             notelen = int(notelen)
             self.m_notelen = Duration(notelen, numdots)
         else:
             notelen = 0
             if dots:
                 raise LexerError(
                     'Need a digit before dots. Write "%(goodcode)s", not "%(badcode)s".'
                     % {
                         'badcode':
                         m.group().strip(),
                         'goodcode':
                         '%s%i%s' % (notename, self.m_notelen.m_nh, dots)
                     }, self)
         n = MusicRequest(notename, notelen, numdots)
         return self.NOTE, n
     m = self.re_staff.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.STAFF, None
     m = self.re_rhythmstaff.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.RHYTHMSTAFF, None
     m = self.re_voice.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.VOICE, None
     m = self.re_relative.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.RELATIVE, MusicalPitch.new_from_notename(m.group(1))
     m = self.re_clef_quoted.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.CLEF, m.group(1)
     m = self.re_clef.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.CLEF, m.group(1)
     m = self.re_stem_updown.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         d = [const.UP, const.DOWN, const.BOTH][['Up', 'Down',
                                                 'Both'].index(m.group(2))]
         return self.STEMDIR, d
     m = self.re_tuplet_updown.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         d = [const.UP, const.DOWN, const.BOTH][['Up', 'Down',
                                                 'Both'].index(m.group(2))]
         return self.TUPLETDIR, d
     m = self.re_transpose.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.TRANSPOSE, MusicalPitch.new_from_notename(m.group(1))
     m = self.re_time.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.TIME, elems.TimeSignature(int(m.group(1)),
                                               int(m.group(2)))
     m = self.re_key.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.KEY, (m.group(1), m.group(2))
     m = self.re_times.match(self.m_string, self.m_idx)
     if m:
         self.m_idx = m.end()
         return self.TIMES, Rat(int(m.groups()[0]), int(m.groups()[1]))
     if self.m_idx == len(self.m_string):
         raise StopIteration
     self.m_idx += 1
     return self.m_string[self.m_idx - 1], None
示例#29
0
 def test_single_tuplet(self):
     n1 = Note(MusicalPitch.new_from_notename("g'"),
               Duration(8, 0, Rat(2, 3)))
     self.score.voice11.append(n1)
     self.score.voice11.tuplet(Rat(2, 3), const.UP, [n1])
     self.assertEqual(n1.w_parent().m_tupletinfo, 'end')
示例#30
0
 def test_new_from_string(self):
     d = Duration.new_from_string("4")
     self.assertEquals(d.get_rat_value(), Rat(1, 4))
     self.assertRaises(Duration.BadStringException,
                       Duration.new_from_string, "44x")
示例#31
0
 def new_from_string(string):
     return Rest(Duration.new_from_string(string))
示例#32
0
 def new_from_string(string):
     return Rest(Duration.new_from_string(string))
示例#33
0
 def new_from_string(string):
     return Skip(Duration.new_from_string(string))
示例#34
0
def parse_to_score_object(music):
    lexer = Lexer(music)
    relative_mode = None
    relto = None
    transpose_pitch = None
    TOPLEVEL = 1  # 'toplevel'
    NOTES = 2  # 'notes'
    START_OF_CHORD = 3  # 'start-of-chord'
    CHORD = 4  # 'chord'
    context = TOPLEVEL
    score = elems.Score()
    chord_duration = None
    cur_duration = Duration(4, 0)
    tie_is_in_the_air = 0
    beam = None
    # None when not parsing notes in a tuplet. Item 0 is the ration and 1.. is the notes
    times = None
    cur_staff = None
    # we set it just so pyflakes does not complain.
    relto_backup = None
    # This variable is set to the duration of the pickup bar from we parse
    # \partial nn until the bar has been created.
    partial = None
    for toc, toc_data in lexer:
        try:
            if toc_data.m_duration:
                cur_duration = toc_data.m_duration.clone()
        except AttributeError:
            pass
        if toc == Lexer.STAFF:
            assert context == TOPLEVEL
            cur_staff = score.add_staff(elems.Staff)
            cur_voice = cur_staff.m_voices[-1]
            stem_dir = const.BOTH
            tuplet_dir = const.BOTH
            relative_mode = None
            timepos = Rat(0)
            last_pos = timepos
        elif toc == Lexer.RHYTHMSTAFF:
            assert context == TOPLEVEL
            cur_staff = score.add_staff(elems.RhythmStaff)
            cur_voice = cur_staff.m_voices[-1]
            stem_dir = const.BOTH
            tuplet_dir = const.BOTH
            relative_mode = None
            timepos = Rat(0)
            last_pos = timepos
        elif toc == Lexer.VOICE:
            if not cur_staff:
                raise ParseError("Don't use \\addvoice before \\staff", lexer)
            relative_mode = None
            timepos = Rat(0)
            cur_voice = cur_staff.add_voice()
        elif toc == Lexer.RELATIVE:
            assert not relative_mode
            relative_mode = 1
            relto = toc_data
        elif toc == Lexer.TRANSPOSE:
            transpose_pitch = toc_data
        elif toc == Lexer.PARTIAL:
            partial = toc_data
        elif toc == Lexer.TIME:
            if not cur_staff:
                raise ParseError("\\time can not be used before \\staff",
                                 lexer)
            # FIXME
            # Also now, we only allow the first voice to change time signatures
            if cur_staff.m_voices.index(cur_voice) != 0:
                raise ParseError("only timesig in first voice", lexer)
            # FIXME: we are stricter with time signatures that both solfege 3.16
            # and LilyPond
            if not cur_voice.is_bar_full():
                raise ParseError("timesig change only when bar is full!",
                                 lexer)
            if partial:
                score.add_partial_bar(partial, toc_data)
                partial = None
            else:
                score.add_bar(toc_data)
        elif toc == Lexer.KEY:
            p = MusicalPitch.new_from_notename(toc_data[0])
            if transpose_pitch:
                p.transpose_by_musicalpitch(transpose_pitch)
            k = (p.get_notename(), toc_data[1])
            if not cur_staff:
                raise ParseError("\\key can not be used before \\staff", lexer)
            cur_staff.set_key_signature(k, timepos)
        elif toc == Lexer.TIMES:
            if not times:
                times = [toc_data]
            else:
                raise ParseError(r"\times nn/nn does not nest", lexer)
        elif toc == Lexer.CLEF:
            try:
                cur_staff.set_clef(toc_data, timepos)
            except elems.UnknownClefException as e:
                e.m_lineno, e.m_linepos1, e.m_linepos2 = lexer.get_error_location(
                )
                raise
        elif toc == '|':
            if timepos != score.get_bar_at(last_pos).end():
                logging.warning("Bar check failed at %s", timepos)
        elif toc == '{':
            if (context == TOPLEVEL):
                context = NOTES
                # if not cur_staff.m_coldict[Rat(0, 1)].m_keysignature:
                # FIXME dont understand
                if transpose_pitch:
                    k = (transpose_pitch.get_notename(), 'major')
                else:
                    k = ('c', 'major')
                cur_voice.set_key_signature(k)
            else:
                raise ParseError("Token '{' not allowed here.", lexer)
        elif toc == '<':
            if context == NOTES:
                context = START_OF_CHORD
            else:
                raise ParseError("Token '<' not allowed here.", lexer)
        elif toc == '>':
            if context == CHORD:
                if tie_is_in_the_air:
                    # The 3.16-parser only handles ties between whole chords, not
                    # single tones of a chord.
                    if tie_is_in_the_air:
                        for last_note in cur_voice.m_tdict[last_pos]['elem']:
                            for cur_note in cur_voice.m_tdict[timepos]['elem']:
                                if last_note.m_musicalpitch.get_octave_notename(
                                ) == cur_note.m_musicalpitch.get_octave_notename(
                                ):
                                    cur_voice.tie([last_note, cur_note])
                    tie_is_in_the_air = 0
                last_pos = timepos
                timepos = timepos + chord_duration.get_rat_value()
                chord_duration = None
                relto = relto_backup
                relto_backup = None
                context = NOTES
            else:
                raise ParseError("Token '>' not allowed here.", lexer)
        elif toc == '}':
            if context == NOTES:
                if times:
                    cur_voice.tuplet(times[0], tuplet_dir, times[1:])
                    times = None
                    cur_duration.m_tuplet = Rat(1, 1)
                else:
                    context = TOPLEVEL
            else:
                raise ParseError("Token '}' not allowed here.", lexer)
        elif toc == '[':
            beam = []
        elif toc == ']':
            cur_voice.beam(beam)
            beam = None
        elif toc == '~':
            tie_is_in_the_air = 1
        elif toc == Lexer.NOTE and (context in [NOTES, CHORD, START_OF_CHORD]):
            # FIXME check if toc_data.m_duration will ever be undefined.
            # If not we can do this:   if not toc_data.m_duration:
            if not getattr(toc_data, 'm_duration', None):
                toc_data.m_duration = cur_duration.clone()
            if times:
                toc_data.m_duration.m_tuplet = times[0].clone()
            if relative_mode:
                toc_data.m_pitch = musicalpitch_relative(
                    relto, toc_data.m_pitch)
                relto = toc_data.m_pitch.clone()
            if transpose_pitch:
                toc_data.transpose(transpose_pitch)
            if partial:
                score.add_partial_bar(partial, None)
                partial = None
            if context == NOTES:
                note = elems.Note(toc_data.m_pitch, toc_data.m_duration)
                try:
                    cur_voice.append(note, stem_dir)
                except elems.Voice.BarFullException as e:
                    raise ParseError(str(e), lexer)
                if beam is not None:
                    beam.append(note)
                if times is not None:
                    times.append(note)
                # The 3.16-parser only handles ties between whole chords, not
                # single tones of a chord.
                if tie_is_in_the_air:
                    for note in cur_voice.m_tdict[last_pos]['elem']:
                        for n in cur_voice.m_tdict[timepos]['elem']:
                            if n.m_musicalpitch.get_octave_notename(
                            ) == note.m_musicalpitch.get_octave_notename():
                                cur_voice.tie([note, n])
                    tie_is_in_the_air = 0
                last_pos = timepos
                timepos = timepos + toc_data.m_duration.get_rat_value()
            elif context == START_OF_CHORD:
                cur_voice.append(
                    elems.Note(toc_data.m_pitch, toc_data.m_duration),
                    stem_dir)
                relto_backup = relto
                chord_duration = toc_data.m_duration
                context = CHORD
            elif context == CHORD:
                cur_voice.add_to(
                    timepos, elems.Note(toc_data.m_pitch, toc_data.m_duration))
        elif toc == Lexer.SKIP and context == NOTES:
            if toc_data.m_duration:
                cur_duration = toc_data.m_duration.clone()
            else:
                toc_data.m_duration = cur_duration.clone()
            skip = elems.Skip(toc_data.m_duration)
            cur_voice.append(skip)
            last_pos = timepos
            timepos = timepos + toc_data.m_duration.get_rat_value()
        elif toc == Lexer.REST and context == NOTES:
            if toc_data.m_duration:
                cur_duration = toc_data.m_duration.clone()
            else:
                toc_data.m_duration = cur_duration.clone()
            rest = elems.Rest(toc_data.m_duration)
            cur_voice.append(rest)
            last_pos = timepos
            timepos += toc_data.m_duration.get_rat_value()
        elif toc == Lexer.STEMDIR:
            stem_dir = toc_data
        elif toc == Lexer.TUPLETDIR:
            tuplet_dir = toc_data
        else:
            raise ParseError(toc, lexer)
    return score