コード例 #1
0
ファイル: Generator.py プロジェクト: Magiczne/MusicGenerator
    def __init__(self):
        # Parametry rytmu
        self.metre: Tuple[int, int] = (4, 4)
        self.bar_count: int = 4

        # Parametry melodii
        self.start_note: Note = Note('c', OctaveType.LINE_1)
        self.end_note: Note = Note('c', OctaveType.LINE_1)
        self.ambitus: Dict[str, Note] = {
            'lowest': Note('c', OctaveType.SMALL),
            'highest': Note('c', OctaveType.LINE_4)
        }
        self.rest_probability: float = 0.5
        self.max_consecutive_rests = math.inf

        # Prawdopodobieństwa wystąpień
        #   Interwałów
        #   Nut w obrębie oktawy
        #   Długości nut
        self.intervals_probability: List[int] = [
            8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
        ]
        self.notes_probability: List[int] = [
            9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8
        ]
        self.durations_probability: List[int] = [14, 14, 14, 14, 14, 15, 15]

        # Wygenerowane dane
        self.generated_data: List[Writeable] = []

        # Zmienne pomocnicze
        self._consecutive_rests = 0
コード例 #2
0
    def test_set_ambitus_raises_value_error(self):
        with self.assertRaises(ValueError):
            self.generator.set_ambitus(lowest=Note('c', OctaveType.LINE_6))

        with self.assertRaises(ValueError):
            self.generator.set_ambitus(
                highest=Note('c', OctaveType.SUB_CONTRA))
コード例 #3
0
def main():
    generator = Generator()

    # set_metre przyjmuje każde metrum, którego wartością rytmiczną jest półnuta, ćwierćnuta, ósemka lub szesnastka
    # ilość nut w metrum jest dowolna jeśli tylko większa od 1

    # set_bar_count przyjmuje liczbę taktów, którą chcemy wygenerować

    # set_start_note oraz set_end_note ustalają nuty początkowe i końcowe i przyjmują tylko nuty które znajdują się w
    # ambitusie, który można ustawić za pomocą metody set_ambitus

    # set_rest_probability ustawia prawdopodobieństwa wystąpienia pauzy. Podawana wartość musi być znormalizowana do 1
    # prawdopodobieństwo wystąpienia nuty będzie wynosiło 1 - p, gdzie p to podana wartość

    # set_max_consecutive_rests ustala ile maksymalnie pauz może nastąpić po sobie (UWAGA! W nutach niepogrupowanych)
    # po dzieleniu na takty i grupowaniu, może pojawić się większa liczba pauz

    # set_intervals_probability, set_notes_probability, set_durations_probability to metody, które umożliwiają
    # ustawienie prawdopodobieństw wystąpienia odpowiednio:
    # 1. Konkretnych interwałów - lista interwałów to: [1cz, 2m, 2w, 3m, 3w, 4cz, 4zw, 5zm, 5cz, 6m, 6w, 7m, 7w, 8cz]
    # 2. Konkretnych nut w obrębie oktawy (12 dźwięków począwszy od c do b) - wykorzystywane w algorytmie generującym
    #    gdy nuty wygenerowane po wylosowaniu interwału obie mieszczą się w zadanym ambitusie. Wtedy wykorzystywane jest
    #    prawdopodobieństwo ich wystąpienia podczas losowania, która z nich trafi do końcowej melodii
    # 3. Konkretnych wartości rytmicznych - kolejno: [cała nuta, półnuta, ... aż do 64]
    # Prawdopodobieństwa podawane do tych funkcji muszą być znormalizowane do 100, a każda pojedyncza wartość musi być
    # liczbą całkowitą.

    # set_shortest_note_duration - ustala jaką najkrótszą wartość rytmiczną chcemy zobaczyć w nutach.
    # Skrypt obsługuje aktualnie aż do 64, ale wystarczy zmienić zakres w pliku Generator.py zmiennej
    # correct_note_lengths, aby skrypt pozwolił na wykorzystanie 128, lub innych nut, ponieważ obliczenia są pisane
    # uniwersalnie.

    generator\
        .set_metre(4, 4) \
        .set_bar_count(100) \
        .set_start_note(Note('c', OctaveType.SMALL)) \
        .set_end_note(Note('c', OctaveType.SMALL)) \
        .set_ambitus(lowest=Note('c', OctaveType.SMALL), highest=Note('c', OctaveType.LINE_2)) \
        .set_rest_probability(0.1) \
        .set_max_consecutive_rests(1) \
        .set_intervals_probability([8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7]) \
        .set_notes_probability([9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8]) \
        .set_durations_probability([14, 14, 14, 14, 14, 15, 15]) \
        .set_shortest_note_duration(16)

    # w konstruktorze należy podać nazwę pliku, pod którą będą generowane pliki lilyponda oraz pliki wynikowe
    # można zmienić wiele innych parametrów, wtedy odsyłam do pliku Writer.py
    writer = Writer('generated')

    # from_generator - na podstawie obiektu generatora z określonymi parametrami przetwarza dane, które później mogą
    # zostać wyeksportowane do pliku lilyponda
    writer.from_generator(generator, midi=True)

    # export - eksportuje plik lilyponda
    writer.export()

    # compile - uruchamia lilyponda z odpowiednimi parametrami, tak aby powstał plik wynikowy, dozwolone rozszerzenia
    # to pdf, png oraz ps (tak jak zezwala lilypond)
    writer.compile(ext='png')
コード例 #4
0
    def test_get_duration_with_double_dot(self):
        note = Note('c', base_duration=4)
        note.add_modifier(NoteModifier.DOUBLE_DOT)
        lengths = [64, 32, 16]

        for length in lengths:
            self.assertEqual(length / 4 + length / 8 + length / 16,
                             note.get_duration(length))
コード例 #5
0
    def test_modifiers_order(self):
        note = Note('c')
        note.add_modifier(NoteModifier.TIE)
        note.add_modifier(NoteModifier.DOT)

        self.assertEqual(2, len(note.modifiers))
        self.assertEqual(NoteModifier.TIE, note.modifiers[1])
        self.assertEqual(NoteModifier.DOT, note.modifiers[0])
コード例 #6
0
    def test_split_note_long(self):
        self.generator.set_shortest_note_duration(16)
        note = Note('c', base_duration=1, modifiers=[NoteModifier.DOUBLE_DOT])

        actual = self.generator.split_note(note, 16)
        expected = [[Note('c', base_duration=1, modifiers=[NoteModifier.TIE])],
                    [Note('c', base_duration=2, modifiers=[NoteModifier.DOT])]]

        self.assertEqual(expected, actual)
コード例 #7
0
    def test_split_note(self):
        Generator.set_shortest_note_duration(16)
        note = Note('c', base_duration=4)

        actual = self.generator.split_note(note, 2)
        expected = [[Note('c', base_duration=8, modifiers=[NoteModifier.TIE])],
                    [Note('c', base_duration=8)]]

        self.assertEqual(expected, actual)
コード例 #8
0
    def test_ge(self):
        note_1 = Note('c')
        note_2 = Note('d')
        self.assertTrue(note_2 >= note_1)

        note_2 = Note('c')
        self.assertTrue(note_2 >= note_1)

        note_1 = Note('d', OctaveType.CONTRA)
        note_2 = Note('d', OctaveType.SMALL)
        self.assertTrue(note_2 >= note_1)
コード例 #9
0
    def test_lt(self):
        note_1 = Note('d')
        note_2 = Note('c')
        self.assertTrue(note_2 < note_1)

        note_2 = Note('d')
        self.assertFalse(note_2 < note_1)

        note_1 = Note('d', OctaveType.CONTRA)
        note_2 = Note('d', OctaveType.SMALL)
        self.assertFalse(note_2 < note_1)
コード例 #10
0
    def test_split_note_multiple_notes_on_left_side(self):
        Generator.set_shortest_note_duration(16)
        note = Note('c', base_duration=2)

        actual = self.generator.split_note(note, 5)
        expected = [[
            Note('c', base_duration=4, modifiers=[NoteModifier.TIE]),
            Note('c', base_duration=16, modifiers=[NoteModifier.TIE])
        ], [Note('c', base_duration=8, modifiers=[NoteModifier.DOT])]]

        self.assertEqual(expected, actual)
コード例 #11
0
    def test_split_note_expects_double_dot_and_note(self):
        Generator.set_shortest_note_duration(16)
        note = Note('c', base_duration=1)

        actual = self.generator.split_note(note, 15)
        expected = [[
            Note('c',
                 base_duration=2,
                 modifiers=[NoteModifier.DOUBLE_DOT, NoteModifier.TIE]),
            Note('c', base_duration=16, modifiers=[NoteModifier.TIE])
        ], [Note('c', base_duration=16)]]
        self.assertEqual(expected, actual)
コード例 #12
0
    def test_init(self):
        self.assertEqual((4, 4), self.generator.metre)
        self.assertEqual(4, self.generator.bar_count)

        self.assertEqual(Note('c', OctaveType.LINE_1),
                         self.generator.start_note)
        self.assertEqual(Note('c', OctaveType.LINE_1), self.generator.end_note)
        self.assertEqual(Note('c', OctaveType.SMALL),
                         self.generator.ambitus['lowest'])
        self.assertEqual(Note('c', OctaveType.LINE_4),
                         self.generator.ambitus['highest'])
        self.assertEqual(0.5, self.generator.rest_probability)
        self.assertEqual(100, sum(self.generator.intervals_probability))
コード例 #13
0
    def test_create_accidentals_string(self):
        values = range(-3, 3)
        expected = ['eseses', 'eses', 'es', '', 'is', 'isis', 'isisis']

        for i in values:
            actual = Note.create_accidentals_string(i)
            self.assertEqual(expected[i + 3], actual)
コード例 #14
0
    def test_split_to_bars(self):
        self.generator.set_bar_count(2)
        self.generator.set_shortest_note_duration(16)
        notes: List[Writeable] = [Note('c')] * 7
        notes.append(Rest())

        expected: List[List[Writeable]] = [[Note('c')] * 4,
                                           [
                                               Note('c'),
                                               Note('c'),
                                               Note('c'),
                                               Rest()
                                           ]]

        bars: List[List[Writeable]] = self.generator.split_to_bars(notes)

        self.assertEqual(expected, bars)
コード例 #15
0
    def test_get_next_writeable(self):
        self.generator.generated_data.append(Note('c'))

        for i in range(10):
            writeable = self.generator.get_next_writeable(8)
            self.assertLessEqual(
                writeable.get_duration(self.generator.shortest_note_duration),
                8)
コード例 #16
0
    def test_split_to_bars_long(self):
        self.generator.set_bar_count(2)
        self.generator.set_shortest_note_duration(16)
        notes: List[Writeable] = [
            Note('c', base_duration=1, modifiers=[NoteModifier.DOUBLE_DOT]),
            Note('c')
        ]

        expected: List[List[Writeable]] = [[
            Note('c', base_duration=1, modifiers=[NoteModifier.TIE])
        ], [
            Note('c', base_duration=2, modifiers=[NoteModifier.DOT]),
            Note('c')
        ]]

        bars: List[List[Writeable]] = self.generator.split_to_bars(notes)

        self.assertEqual(expected, bars)
コード例 #17
0
    def test_add_modifier_dot_removes_double_dot(self):
        note = Note('c')
        note.add_modifier(NoteModifier.DOUBLE_DOT)
        note.add_modifier(NoteModifier.DOT)

        self.assertTrue(NoteModifier.DOT in note.modifiers)
        self.assertTrue(NoteModifier.DOUBLE_DOT not in note.modifiers)
コード例 #18
0
    def test_add_remove_modifier(self):
        note = Note('c')
        note.add_modifier(NoteModifier.DOT)
        self.assertTrue(NoteModifier.DOT in note.modifiers)

        note.remove_modifier(NoteModifier.DOT)
        self.assertTrue(NoteModifier.DOT not in note.modifiers)
コード例 #19
0
    def test_str_with_modifiers(self):
        note = Note('d', OctaveType.GREAT, 16)
        note.add_modifier(NoteModifier.TIE)
        self.assertEqual('d,16~', str(note))

        note.add_modifier(NoteModifier.DOT)
        self.assertEqual('d,16.~', str(note))
コード例 #20
0
ファイル: Generator.py プロジェクト: Magiczne/MusicGenerator
    def set_end_note(self, note: Note):
        """
        Ustaw nutę końcową dla generowanej melodii

        Args:
            note:   Nuta końcowa
        """
        if not note.between(self.ambitus['lowest'], self.ambitus['highest']):
            raise NoteOutsideAmbitus(note, self.ambitus['lowest'],
                                     self.ambitus['highest'])

        self.end_note = note
        return self
コード例 #21
0
    def test_split_to_bars_long_note(self):
        self.generator.set_bar_count(3)

        data: List[Writeable] = [
            Rest(base_duration=2, modifiers=[RestModifier.DOT]),
            Note('c', base_duration=1, modifiers=[NoteModifier.DOT]),
            Rest(base_duration=2, modifiers=[RestModifier.DOT])
        ]
        expected: List[List[Writeable]] = [[
            Rest(base_duration=2, modifiers=[RestModifier.DOT]),
            Note('c', base_duration=4, modifiers=[NoteModifier.TIE])
        ], [Note('c', base_duration=1, modifiers=[NoteModifier.TIE])],
                                           [
                                               Note('c', base_duration=4),
                                               Rest(base_duration=2,
                                                    modifiers=[
                                                        RestModifier.DOT
                                                    ])
                                           ]]

        bars = self.generator.split_to_bars(data)
        self.assertEqual(expected, bars)
コード例 #22
0
    def test_sub_interval(self):
        note = Note('c')

        intervals = Interval.names()
        expected = [
            'c', 'b', 'bes', 'a', 'aes', 'g', 'ges', 'fis', 'f', 'e', 'ees',
            'd', 'des', 'c'
        ]

        for i in range(len(expected)):
            new_note: Note = note - Interval(intervals[i])
            self.assertEqual(expected[i], new_note.note)

        note = Note('f')
        expected = [
            'f', 'e', 'ees', 'd', 'des', 'c', 'ces', 'b', 'bes', 'a', 'aes',
            'g', 'ges', 'f'
        ]

        for i in range(len(expected)):
            new_note: Note = note - Interval(intervals[i])
            self.assertEqual(expected[i], new_note.note)
コード例 #23
0
ファイル: Generator.py プロジェクト: Magiczne/MusicGenerator
    def get_random_note(self, longest_duration: Optional[int] = None) -> Note:
        """
        Wygeneruj nutę z losowymi parametrami o pewnej maksymalnej długości podanej w parametrze.

        Args:
            longest_duration:   Najdłuższa możliwa wartość rytmiczna, która może wystąpić podana w ilości
                                shortest_note_duration.
                                Jeśli nie podano, skrypt zakłada że nuta o każdej długości jest dozwolona.

        Returns:
            Nuta z losowymi parametrami o maksymalnej długości wynoszącej longest_duration
        """
        # Jeśli nie był podany parametr najdłuższej możliwej wartości rytmicznej, to zakładamy że nuta o każdej długości
        # jest dozwolona do wygenerowania
        if longest_duration is None:
            longest_duration = self.shortest_note_duration

        available_mods = []

        base_note = np.random.choice(Note.base_notes)
        octave = OctaveType.random()
        base_duration = self.get_random_duration(
            longest_duration=longest_duration)
        has_mod = np.random.choice([True, False])

        note = Note(note=base_note, octave=octave, base_duration=base_duration)

        # Jeśli długość nuty jest najkrótsza jaką możemy uzyskać, to nie możemy dodać modyfikatora wydłużającego,
        # gdyż kropka lub podwójna kropka doda mniejszą wartość rytmiczną
        if base_duration >= self.shortest_note_duration:
            has_mod = False

        # Jeśli dostępne miejsce jest większej lub równej długości niż potencjalna nuta z kropką, to do dostępnych
        # modyfikatorów możemy dodać przedłużenie w postaci kropki
        if longest_duration >= note.get_duration(
                self.shortest_note_duration) * 1.5:
            available_mods.append(NoteModifier.DOT)

        # Jeśli dostępne miejsce jest większej lub równej długości niż potencjalna nuta z podwójną kropką, to do
        # dostępnych modyfikatorów możemy dodać przedłużenie w postaci podwójnej kropki.
        # Sprawdzamy również, czy nie jest to przedostatnia dostępna wartość rytmiczna. Jeśli tak jest, to nie możemy
        # dodać podwójnej kropki, gdyż skutkowałoby to dodaniem nuty o połowę mniejszej wartości rytmicznej niż
        # dozwolona
        if longest_duration >= note.get_duration(self.shortest_note_duration) * 1.75 \
                and note.base_duration > 2 * self.shortest_note_duration:
            available_mods.append(NoteModifier.DOUBLE_DOT)

        if has_mod and len(available_mods) > 0:
            note.add_modifier(np.random.choice(available_mods))

        return note
コード例 #24
0
    def test_add_interval(self):
        notes = ['c', 'f', 'fes', 'feses', 'fis', 'eisis']
        expected = [[
            'c', 'des', 'd', 'ees', 'e', 'f', 'fis', 'ges', 'g', 'aes', 'a',
            'bes', 'b', 'c'
        ],
                    [
                        'f', 'ges', 'g', 'aes', 'a', 'bes', 'b', 'ces', 'c',
                        'des', 'd', 'ees', 'e', 'f'
                    ],
                    [
                        'fes', 'geses', 'ges', 'aeses', 'aes', 'beses', 'bes',
                        'ceses', 'ces', 'deses', 'des', 'eeses', 'ees', 'fes'
                    ],
                    [
                        'feses', 'fes', 'geses', 'ges', 'aeses', 'aes',
                        'beses', 'beses', 'ceses', 'ces', 'deses', 'des',
                        'eeses', 'feses'
                    ],
                    [
                        'fis', 'g', 'gis', 'a', 'ais', 'b', 'bis', 'c', 'cis',
                        'd', 'dis', 'e', 'eis', 'fis'
                    ],
                    [
                        'eisis', 'fisis', 'gis', 'gisis', 'ais', 'aisis',
                        'bis', 'bis', 'bisis', 'cisis', 'dis', 'disis', 'eis',
                        'eisis'
                    ]]
        intervals = Interval.names()

        for i in range(len(notes)):
            note = Note(notes[i])

            for j in range(len(expected[i])):
                new_note = note + Interval(intervals[j])
                self.assertEqual(expected[i][j], new_note.note)
コード例 #25
0
    def test_split_to_bars_break_rest(self):
        self.generator.set_bar_count(2)
        self.generator.set_shortest_note_duration(16)
        data: List[Writeable] = [
            Note('c'),
            Note('c', base_duration=2),
            Rest(base_duration=2),
            Note('c', base_duration=2),
            Rest()
        ]

        expected: List[List[Writeable]] = [[
            Note('c'), Note('c', base_duration=2),
            Rest()
        ], [Rest(), Note('c', base_duration=2),
            Rest()]]

        bars: List[List[Writeable]] = self.generator.split_to_bars(data)

        self.assertEqual(expected, bars)
コード例 #26
0
 def test_repr(self):
     note = Note('c')
     self.assertEqual('Note <c4>', repr(note))
コード例 #27
0
 def test_str_full(self):
     note = Note('d', OctaveType.GREAT, 16)
     self.assertEqual('d,16', str(note))
コード例 #28
0
 def test_str(self):
     note = Note('c')
     self.assertEqual('c4', str(note))
コード例 #29
0
    def test_between_swap_low_and_high(self):
        low = Note('c', OctaveType.LINE_1)
        mid = Note('c', OctaveType.LINE_2)
        high = Note('c', OctaveType.LINE_3)

        self.assertTrue(mid.between(high, low))
コード例 #30
0
    def test_between(self):
        low = Note('c', OctaveType.LINE_1)
        mid = Note('c', OctaveType.LINE_2)
        high = Note('c', OctaveType.LINE_3)

        self.assertTrue(mid.between(low, high))