def test_chord_notes_midi_notes(self):
     region = as_region('[:CEG]')
     parsed_chord = Chord.parse(region)
     parsed_chord.resolve(Song())
     self.assertEquals(parsed_chord.midi_notes, [24, 28, 31])
     region = as_region('[:C+EG+]')
     parsed_chord = Chord.parse(region)
     parsed_chord.resolve(Song())
     self.assertEquals(parsed_chord.midi_notes, [25, 28, 32])
    def test_chord_descriptor_midi_notes(self):
        region = as_region('[B]')
        parsed_chord = Chord.parse(region)
        parsed_chord.resolve(Song())
        self.assertEquals(parsed_chord.midi_notes, [35, 39, 42])

        region = as_region('[B-]')
        parsed_chord = Chord.parse(region)
        parsed_chord.resolve(Song())
        self.assertEquals(parsed_chord.midi_notes, [34, 38, 41])
    def test_chord_with_bass(self):
        region = as_region('[:DFA]')
        parsed_chord = Chord.parse(region)
        parsed_chord.resolve(Song())
        self.assertEquals(parsed_chord.bass_midi_note, 14)

        region = as_region('[:DFA/C]')
        parsed_chord = Chord.parse(region)
        parsed_chord.resolve(Song())
        self.assertEquals(parsed_chord.bass_midi_note, 12)
 def test_transpose_out_of_range(self):
     song_lines = ("*song: transpose = 0\n*track.melody: octave = 8\n c")
     parse_string = StringToParse('test_string', song_lines)
     song = Song.parse(parse_string)
     song_lines = ("*song: transpose = 100\n*track.melody: octave = 8\n c")
     parse_string = StringToParse('test_string', song_lines)
     song = Song.parse(parse_string)
     track_visitor = MidiTrackVisitor(transpose=song.transpose)
     note_items = [item for item in song.items if isinstance(item, Note)]
     with self.parse_exception('Note number 208 > 127', 'c'):
         for note in note_items:
             note.visit_midi_track(track_visitor)
 def test_transpose_out_of_range(self):
     song_lines = "*song: transpose = 0\n*track.melody: octave = 8\n c"
     parse_string = StringToParse("test_string", song_lines)
     song = Song.parse(parse_string)
     song_lines = "*song: transpose = 100\n*track.melody: octave = 8\n c"
     parse_string = StringToParse("test_string", song_lines)
     song = Song.parse(parse_string)
     track_visitor = MidiTrackVisitor(transpose=song.transpose)
     note_items = [item for item in song.items if isinstance(item, Note)]
     with self.parse_exception("Note number 208 > 127", "c"):
         for note in note_items:
             note.visit_midi_track(track_visitor)
 def test_parse_2_2_ticks_error(self):
     song_lines = "*song: time_signature = 2/2, ticks_per_beat = 1\n" + " e | d e f g | d"
     parse_string = StringToParse('test_string', song_lines)
     with self.parse_exception(
             'ticks per beat of 1 has to be a multiple of crotchets per beat of 2',
             'ticks_per_beat'):
         song = Song.parse(parse_string)
 def test_invalid_transpose_value(self):
     song_lines = ("*song: transpose = 310\nc c")
     parse_string = StringToParse('test_string', song_lines)
     with self.parse_exception(
             'Invalid value for transpose: 310 - must be an integer from -127 to 127',
             '310'):
         song = Song.parse(parse_string)
 def test_parse_2_2_ticks_error(self):
     song_lines = "*song: time_signature = 2/2, ticks_per_beat = 1\n" + " e | d e f g | d"
     parse_string = StringToParse("test_string", song_lines)
     with self.parse_exception(
         "ticks per beat of 1 has to be a multiple of crotchets per beat of 2", "ticks_per_beat"
     ):
         song = Song.parse(parse_string)
    def test_parse_song(self):
        parse_string = StringToParse("test_string", self.song_lines)
        song = Song.parse(parse_string)
        self.assertEqualsDisplaying(
            song,
            Song(
                [
                    SongValuesCommand([SetSongTempoBpm(120), SetSongTicksPerBeat(4)]),
                    TrackValuesCommand("chord", [SetTrackOctave(2), SetTrackInstrument(40)]),
                    TrackValuesCommand("bass", [SetTrackOctave(1), SetTrackVolume(90)]),
                    Chord(ScaleNote(0), descriptor=""),
                    Note(0, duration=(1, 1)),
                    Note(2, duration=(1, 1)),
                    Chord(ScaleNote(3), other_notes=[ScaleNote(5), ScaleNote(0)]),
                    Note(2, duration=(1, 1)),
                    Note(0, duration=(1, 2)),
                    Note(0, duration=(1, 2)),
                    BarLine(),
                    Chord(ScaleNote(4), descriptor=""),
                    Note(4, duration=(1, 1)),
                    Rest((2, 1)),
                ]
            ),
        )
        chord_track = song.tracks["chord"]
        self.assertEquals(chord_track.instrument, 40)
        self.assertEquals(song.tracks["bass"].volume, 90)
        self.assertEquals(len(chord_track.items), 3)
        self.assertEquals(len(song.tracks["melody"].items), 6)

        self.assertEquals(chord_track.items[0].midi_notes, [36, 40, 43])
        self.assertEquals(chord_track.items[1].bass_midi_note, 29)
        self.assertEquals(song.bar_ticks, [0, 16, 32])
 def test_parse_song_scale(self):
     song_lines = "*song: scale = C2 major\n*track.melody: octave = 2\n c e | d e f g | c, d'' "
     parse_string = StringToParse("test_string", song_lines)
     song = Song.parse(parse_string)
     self.assertEquals(song.scale, Scale(ScaleNote(0, octave=2), RelativeScale("major", [0, 2, 4, 5, 7, 9, 11])))
     note_items = [item for item in song.items if isinstance(item, Note)]
     scale_positions = [song.scale.get_position(note.midi_note) for note in note_items]
     self.assertEquals(scale_positions, [0, 2, 1, 2, 3, 4, 0, 8])
    def test_subticks(self):
        song_lines = """
            *song:         tempo_bpm=120, ticks_per_beat=4, subticks_per_tick = 5
                 | [C] c 
"""
        parse_string = StringToParse('test_string', song_lines)
        song = Song.parse(parse_string)
        self.assertEqualsDisplaying(
            song,
            Song([
                SongValuesCommand([
                    SetSongTempoBpm(120),
                    SetSongTicksPerBeat(4),
                    SetSongSubTicksPerTick(5)
                ]),
                BarLine(),
                Chord(ScaleNote(0), descriptor=''),
                Note(0, duration=(1, 1))
            ]))
    def test_parse_song_cut(self):
        song_lines = """
            *song:         tempo_bpm=120, ticks_per_beat=4
                 | [C] c e 
                 [:FAC] e 
                 ! c | [G] r2
"""
        parse_string = StringToParse('test_string', song_lines)
        song = Song.parse(parse_string)
        self.assertEqualsDisplaying(
            song,
            Song([
                SongValuesCommand(
                    [SetSongTempoBpm(120),
                     SetSongTicksPerBeat(4)]),
                Note(0, duration=(1, 1)),
                BarLine(),
                Chord(ScaleNote(4), descriptor=''),
                Rest((2, 1))
            ]))
 def test_parse_song_scale(self):
     song_lines = "*song: scale = C2 major\n*track.melody: octave = 2\n c e | d e f g | c, d'' "
     parse_string = StringToParse('test_string', song_lines)
     song = Song.parse(parse_string)
     self.assertEquals(
         song.scale,
         Scale(ScaleNote(0, octave=2),
               RelativeScale('major', [0, 2, 4, 5, 7, 9, 11])))
     note_items = [item for item in song.items if isinstance(item, Note)]
     scale_positions = [
         song.scale.get_position(note.midi_note) for note in note_items
     ]
     self.assertEquals(scale_positions, [0, 2, 1, 2, 3, 4, 0, 8])
    def test_parse_song(self):
        parse_string = StringToParse('test_string', self.song_lines)
        song = Song.parse(parse_string)
        self.assertEqualsDisplaying(
            song,
            Song([
                SongValuesCommand(
                    [SetSongTempoBpm(120),
                     SetSongTicksPerBeat(4)]),
                TrackValuesCommand('chord',
                                   [SetTrackOctave(2),
                                    SetTrackInstrument(40)]),
                TrackValuesCommand(
                    'bass',
                    [SetTrackOctave(1), SetTrackVolume(90)]),
                Chord(ScaleNote(0), descriptor=''),
                Note(0, duration=(1, 1)),
                Note(2, duration=(1, 1)),
                Chord(ScaleNote(3), other_notes=[ScaleNote(5),
                                                 ScaleNote(0)]),
                Note(2, duration=(1, 1)),
                Note(0, duration=(1, 2)),
                Note(0, duration=(1, 2)),
                BarLine(),
                Chord(ScaleNote(4), descriptor=''),
                Note(4, duration=(1, 1)),
                Rest((2, 1))
            ]))
        chord_track = song.tracks['chord']
        self.assertEquals(chord_track.instrument, 40)
        self.assertEquals(song.tracks['bass'].volume, 90)
        self.assertEquals(len(chord_track.items), 3)
        self.assertEquals(len(song.tracks['melody'].items), 6)

        self.assertEquals(chord_track.items[0].midi_notes, [36, 40, 43])
        self.assertEquals(chord_track.items[1].bass_midi_note, 29)
        self.assertEquals(song.bar_ticks, [0, 16, 32])
    def test_subticks(self):
        song_lines = """
            *song:         tempo_bpm=120, ticks_per_beat=4, subticks_per_tick = 5
                 | [C] c 
"""
        parse_string = StringToParse("test_string", song_lines)
        song = Song.parse(parse_string)
        self.assertEqualsDisplaying(
            song,
            Song(
                [
                    SongValuesCommand([SetSongTempoBpm(120), SetSongTicksPerBeat(4), SetSongSubTicksPerTick(5)]),
                    BarLine(),
                    Chord(ScaleNote(0), descriptor=""),
                    Note(0, duration=(1, 1)),
                ]
            ),
        )
    def test_parse_song_cut(self):
        song_lines = """
            *song:         tempo_bpm=120, ticks_per_beat=4
                 | [C] c e 
                 [:FAC] e 
                 ! c | [G] r2
"""
        parse_string = StringToParse("test_string", song_lines)
        song = Song.parse(parse_string)
        self.assertEqualsDisplaying(
            song,
            Song(
                [
                    SongValuesCommand([SetSongTempoBpm(120), SetSongTicksPerBeat(4)]),
                    Note(0, duration=(1, 1)),
                    BarLine(),
                    Chord(ScaleNote(4), descriptor=""),
                    Rest((2, 1)),
                ]
            ),
        )
 def test_transpose(self):
     song_lines = (
         "*song: transpose = 3\n*track.melody: octave = 2\n*track.chord: octave = 1\n*track.bass:octave = 0\n"
         + "c c [C]")
     parse_string = StringToParse('test_string', song_lines)
     song = Song.parse(parse_string)
     note_items = [item for item in song.items if isinstance(item, Note)]
     first_note = note_items[0]
     self.assertEquals(first_note.midi_note, 36)
     track_visitor = MidiTrackVisitor(transpose=song.transpose)
     first_note.visit_midi_track(track_visitor)
     self.assertEquals(track_visitor.midi_notes[0], 39)
     chord_items = [item for item in song.items if isinstance(item, Chord)]
     first_chord = chord_items[0]
     self.assertEquals(first_chord.midi_notes, [24, 28, 31])
     first_chord.visit_midi_track(track_visitor)
     self.assertEquals(track_visitor.midi_notes[1], [27, 31, 34])
     self.assertEquals(first_chord.bass_midi_note, 12)
     bass_note = song.tracks['bass'].items[0]
     bass_note.visit_midi_track(track_visitor)
     self.assertEquals(track_visitor.midi_notes[2], 15)
 def test_transpose(self):
     song_lines = (
         "*song: transpose = 3\n*track.melody: octave = 2\n*track.chord: octave = 1\n*track.bass:octave = 0\n"
         + "c c [C]"
     )
     parse_string = StringToParse("test_string", song_lines)
     song = Song.parse(parse_string)
     note_items = [item for item in song.items if isinstance(item, Note)]
     first_note = note_items[0]
     self.assertEquals(first_note.midi_note, 36)
     track_visitor = MidiTrackVisitor(transpose=song.transpose)
     first_note.visit_midi_track(track_visitor)
     self.assertEquals(track_visitor.midi_notes[0], 39)
     chord_items = [item for item in song.items if isinstance(item, Chord)]
     first_chord = chord_items[0]
     self.assertEquals(first_chord.midi_notes, [24, 28, 31])
     first_chord.visit_midi_track(track_visitor)
     self.assertEquals(track_visitor.midi_notes[1], [27, 31, 34])
     self.assertEquals(first_chord.bass_midi_note, 12)
     bass_note = song.tracks["bass"].items[0]
     bass_note.visit_midi_track(track_visitor)
     self.assertEquals(track_visitor.midi_notes[2], 15)
 def test_note_too_low(self):
     song_lines = """*track.melody: octave = 4\n c c, c, c, | c, d, e, f, """
     parse_string = StringToParse("test_string", song_lines)
     with self.parse_exception("Note number -8 < 0", "e, f, "):
         song = Song.parse(parse_string)
 def test_invalid_transpose_value(self):
     song_lines = "*song: transpose = 310\nc c"
     parse_string = StringToParse("test_string", song_lines)
     with self.parse_exception("Invalid value for transpose: 310 - must be an integer from -127 to 127", "310"):
         song = Song.parse(parse_string)
 def _continuation_song(self, string):
     song_lines = "*song: ticks_per_beat=1, time_signature = 4/4\n%s" % string
     parse_string = StringToParse("test_string", song_lines)
     return Song.parse(parse_string)
 def test_note_too_high(self):
     song_lines = """*track.melody: octave = 5\n c c' c' c' | c' d d' e'"""
     parse_string = StringToParse("test_string", song_lines)
     with self.parse_exception("Note number 134 > 127", "d' e'"):
         song = Song.parse(parse_string)
 def _continuation_song(self, string):
     song_lines = "*song: ticks_per_beat=1, time_signature = 4/4\n%s" % string
     parse_string = StringToParse('test_string', song_lines)
     return Song.parse(parse_string)
 def test_note_too_high(self):
     song_lines = """*track.melody: octave = 5\n c c' c' c' | c' d d' e'"""
     parse_string = StringToParse('test_string', song_lines)
     with self.parse_exception('Note number 134 > 127', "d' e'"):
         song = Song.parse(parse_string)
 def test_note_too_low(self):
     song_lines = """*track.melody: octave = 4\n c c, c, c, | c, d, e, f, """
     parse_string = StringToParse('test_string', song_lines)
     with self.parse_exception('Note number -8 < 0', "e, f, "):
         song = Song.parse(parse_string)
 def test_parse_3_4(self):
     song_lines = "*song: time_signature = 3/4\n" + "c e | d e f | c"
     parse_string = StringToParse('test_string', song_lines)
     song = Song.parse(parse_string)
 def test_parse_3_8(self):
     song_lines = "*song: time_signature = 3/8\n" + "ch e | dh e f | ch"
     parse_string = StringToParse("test_string", song_lines)
     song = Song.parse(parse_string)
 def test_parse_3_4(self):
     song_lines = "*song: time_signature = 3/4\n" + "c e | d e f | c"
     parse_string = StringToParse("test_string", song_lines)
     song = Song.parse(parse_string)
 def test_parse_3_8(self):
     song_lines = "*song: time_signature = 3/8\n" + "ch e | dh e f | ch"
     parse_string = StringToParse('test_string', song_lines)
     song = Song.parse(parse_string)