1
0
Fork 0

Siisti koodia

This commit is contained in:
Vili Sinervä 2022-10-01 20:57:46 +03:00
parent e9312f4998
commit 4bf5257534
5 changed files with 69 additions and 35 deletions

View file

@ -1,3 +1,3 @@
[run] [run]
source = src source = src
omit = src/main.py,src/**/__init__.py,src/tests/**,src/ui* omit = src/main.py,src/**/__init__.py,src/tests/**,src/ui.py,src/musiikki_generaattori.py

View file

@ -1,3 +1,4 @@
"""Päämoduuli. Käynnistää ainoastaan UI:n"""
from ui import UI from ui import UI
ui = UI() ui = UI()

View file

@ -1,3 +1,6 @@
"""Mahdollistaa MIDI-tiedostojen lukemisen ja kirjoittamisen.
from midi_kasittelija imort lue_midi, kirjoita_midi
"""
import mido import mido
savellaji_arvot = { savellaji_arvot = {
@ -19,6 +22,7 @@ savellaji_arvot = {
} }
def lue_midi(tiedostopolku): def lue_midi(tiedostopolku):
"""Lukee nuotit MIDI tiedostosta"""
midi = mido.MidiFile(tiedostopolku) midi = mido.MidiFile(tiedostopolku)
tulos = [] tulos = []
for raita in midi.tracks: for raita in midi.tracks:
@ -42,17 +46,17 @@ def lue_midi(tiedostopolku):
return tulos return tulos
def kirjoita_midi(tiedostopolku, nuotit, tempo=120): def kirjoita_midi(tiedostopolku, nuotit, tempo=120):
"""Kirjoittaa halutut nuotit valittuun MIDI-tiedostoon annetulla tempolla"""
midi = mido.MidiFile() midi = mido.MidiFile()
track = mido.MidiTrack() raita = mido.MidiTrack()
track.append(mido.MetaMessage("set_tempo", tempo=mido.bpm2tempo(tempo), time=0)) raita.append(mido.MetaMessage("set_tempo", tempo=mido.bpm2tempo(tempo), time=0))
track.append(mido.MetaMessage("time_signature")) raita.append(mido.MetaMessage("time_signature"))
for nuotti in nuotit: for nuotti in nuotit:
if nuotti: if nuotti:
track.append(mido.Message("note_on", note=nuotti, velocity=64, time=0)) raita.append(mido.Message("note_on", note=nuotti, velocity=64, time=0))
track.append(mido.Message("note_on", note=nuotti, velocity=0, time=480)) raita.append(mido.Message("note_on", note=nuotti, velocity=0, time=480))
midi.tracks.append(track)
midi.tracks.append(raita)
midi.save(tiedostopolku) midi.save(tiedostopolku)

View file

@ -1,11 +1,14 @@
"""Mahdollistaa musiikin generoinnin Markovin ketjujen avulla.
from musiikki_generaattori import musiikki_generaattori
"""
from collections import deque from collections import deque
from glob import glob from glob import glob
from markov_ketju import MarkovKetju from markov_ketju import MarkovKetju
from midi_kasittelija import lue_midi, kirjoita_midi from midi_kasittelija import lue_midi, kirjoita_midi
from trie import Trie from trie import Trie
class MusiikkiGeneraattori: class MusiikkiGeneraattori:
"""Yhden instanssin luokka musiikin generoimiseen."""
def __init__(self): def __init__(self):
self._ketju = None self._ketju = None
self._nuotit = [] self._nuotit = []
@ -31,34 +34,42 @@ class MusiikkiGeneraattori:
"B":11} "B":11}
def lue_opetusdata(self, polku): def lue_opetusdata(self, polku):
"""Lukee nuotit annetun polun MIDI-tiedostoista.
Useamman tiedoston lukeminen *-merkillä esim 'kansio/*.mid'
"""
tiedostot = glob(polku) tiedostot = glob(polku)
self._opetusdata = [] self._opetusdata = []
for tiedosto in tiedostot: for tiedosto in tiedostot:
try: try:
for x in lue_midi(tiedosto): for jono in lue_midi(tiedosto):
self._opetusdata.append(x) self._opetusdata.append(jono)
except: # Kaikki virheet halutaan ohittaa
except: # pylint: disable=bare-except
continue continue
def valmistele_ketju(self, alkuosa, aste=1): def valmistele_ketju(self, alkuosa, aste=1):
"""Luo ja valmistelee halutun asteisen Markovin ketjun annetulla alkuosalla"""
alkuosa = self._nuotit_midiksi(alkuosa) alkuosa = self._nuotit_midiksi(alkuosa)
if len(alkuosa) < aste: if len(alkuosa) < aste:
trie = Trie() trie = Trie()
# Rakentaa poikkeuksellisesti Trien, jossa on kaikki ENINTÄÄN 'aste' mittaiset alkiot,
# jotka löytyvät opetusdatasta.
for jono in self._opetusdata: for jono in self._opetusdata:
if len(jono) > aste: if len(jono) > aste:
alkio = deque() alkio = deque()
for i in range(0, len(jono)): for nuotti in jono:
if len(alkio) > aste: if len(alkio) > aste:
alkio.popleft() alkio.popleft()
alkio.append(jono[i]) alkio.append(nuotti)
for j in range(-len(alkio), 0): for i in range(-len(alkio), 0):
trie.lisaa([alkio[x] for x in range(j, 0)]) trie.lisaa([alkio[x] for x in range(i, 0)])
alkuosa = [x for x in alkuosa] # Täydentää alkuosan riittävän pitkäksi käyttämällä asteittain pidempiä Markovin ketjuja
alkuosa = list(alkuosa)
while len(alkuosa) < aste: while len(alkuosa) < aste:
self._ketju = MarkovKetju(len(alkuosa), trie) self._ketju = MarkovKetju(len(alkuosa), trie)
self._ketju.aseta_alkuosa(alkuosa) self._ketju.aseta_alkuosa(alkuosa)
@ -72,10 +83,11 @@ class MusiikkiGeneraattori:
self._ketju.kasittele_opetusdata(self._opetusdata) self._ketju.kasittele_opetusdata(self._opetusdata)
self._ketju.aseta_alkuosa(alkuosa) self._ketju.aseta_alkuosa(alkuosa)
def generoi_nuotteja(self, n): def generoi_nuotteja(self, maara):
"""Generoi halutun määrän nuotteja aiemmin alustetulla Markovin ketjulla"""
self._nuotit = list(self._ketju.menneet_tilat) self._nuotit = list(self._ketju.menneet_tilat)
nuotteja = n - len(self._nuotit) nuotteja = maara - len(self._nuotit)
for i in range(nuotteja): for _ in range(nuotteja):
# Tunnistaa jos edellinen Markovin ketjun iteraatio palautti None # Tunnistaa jos edellinen Markovin ketjun iteraatio palautti None
if not self._nuotit[-1]: if not self._nuotit[-1]:
break break
@ -84,9 +96,11 @@ class MusiikkiGeneraattori:
return len(self._nuotit) return len(self._nuotit)
def kirjoita_midi(self, tiedostopolku, tempo=120): def kirjoita_midi(self, tiedostopolku, tempo=120):
"""Kirjoittaa nuotit MIDI-tiedostoon halutulla tempolla"""
kirjoita_midi(tiedostopolku, self._nuotit, tempo) kirjoita_midi(tiedostopolku, self._nuotit, tempo)
def _nuotit_midiksi(self, nuotit: str): def _nuotit_midiksi(self, nuotit: str):
"""Muuttaa perinteiset nuottimerkinnät kuten C#4 MIDI-arvoiksi"""
nuotit = nuotit.split("|") nuotit = nuotit.split("|")
midi = [] midi = []
for nuotti in nuotit: for nuotti in nuotit:

View file

@ -1,9 +1,12 @@
"""Musiikki generaattorin tekstipohjainen käyttöliittymä
from ui import UI"""
from os import system, name from os import system, name
from re import search from re import search
from sys import exit as sys_exit from sys import exit as sys_exit
from musiikki_generaattori import musiikki_generaattori from musiikki_generaattori import musiikki_generaattori
class UI: class UI: # pylint: disable=too-few-public-methods, too-many-instance-attributes
"""Tekstipohjainen käyttöliittymä. Käynnistyy automaattisesti, kun olio luodaan"""
def __init__(self): def __init__(self):
self._opetusdata_polku = "opetusdata/*.mid" self._opetusdata_polku = "opetusdata/*.mid"
self._tulos_polku = "savelma.mid" self._tulos_polku = "savelma.mid"
@ -13,15 +16,24 @@ class UI:
self._tempo = 120 self._tempo = 120
self._toiminnot = { self._toiminnot = {
"A": ("(A)pu", self._tulosta_apu, 0, "Tulosta apu"), "A": ("(A)pu", self._tulosta_apu, 0,
"O": ("(O)petusdata [polku]", self._aseta_opetusdata, 1, "Valitse opetusdata"), "Tulosta apu"),
"P": ("(P)olku [polku]", self._aseta_tulos_polku, 1, "Valitse valmiin sävelmän polku"), "O": ("(O)petusdata [polku]", self._aseta_opetusdata, 1,
"K": ("(K)etjun aste", self._aseta_aste, 1, "Aseta Markovin ketjun aste valittuun kokonaislukuun"), "Valitse opetusdata"),
"L": ("a(L)kuosa [merkkijono]", self._aseta_alkuosa, 1, "Aseta alkuosa. Esim. 'C4|D#5|Gb3'"), "P": ("(P)olku [polku]", self._aseta_tulos_polku, 1,
"N": ("(N)uotteja [luku]", self._aseta_nuottien_maara, 1, "Aseta sävelmän nuottien määrä valittuun kokonaislukuun"), "Valitse valmiin sävelmän polku"),
"T": ("(T)empo [luku]", self._aseta_tempo, 1, "Aseta tempo valittuun kokonaislukuun"), "K": ("(K)etjun aste", self._aseta_aste, 1,
"G": ("(G)eneroi sävelmä", self._generoi_savelma, 0, "Generoi sävelmä valituilla asetuksilla"), "Aseta Markovin ketjun aste valittuun kokonaislukuun"),
"S": ("(S)ulje", self._sulje, 0, "Sulje ohjelma") "L": ("a(L)kuosa [merkkijono]", self._aseta_alkuosa, 1,
"Aseta alkuosa. Esim. 'C4|D#5|Gb3'"),
"N": ("(N)uotteja [luku]", self._aseta_nuottien_maara, 1,
"Aseta sävelmän nuottien määrä valittuun kokonaislukuun"),
"T": ("(T)empo [luku]", self._aseta_tempo, 1,
"Aseta tempo valittuun kokonaislukuun"),
"G": ("(G)eneroi sävelmä", self._generoi_savelma, 0,
"Generoi sävelmä valituilla asetuksilla"),
"S": ("(S)ulje", self._sulje, 0,
"Sulje ohjelma")
} }
self._virheet = [] self._virheet = []
@ -42,6 +54,7 @@ class UI:
if komento: if komento:
if komento[0].upper() in self._toiminnot: if komento[0].upper() in self._toiminnot:
# Virheiden välttämiseksi sulkeminen käsitellään ennen muita
if komento[0].upper() == "S": if komento[0].upper() == "S":
self._sulje() self._sulje()
@ -53,9 +66,9 @@ class UI:
for i in range(1, 1+parametrien_maara): for i in range(1, 1+parametrien_maara):
parametrit.append(komento[i]) parametrit.append(komento[i])
funktio(parametrit) funktio(parametrit)
except: # Kaikki virheet halutaan ohittaa
except: # pylint: disable=bare-except
self._virheet.append("KOMENNON MUOTO VÄÄRÄ!") self._virheet.append("KOMENNON MUOTO VÄÄRÄ!")
continue
def _tyhjenna(self): def _tyhjenna(self):
# windows # windows
@ -104,7 +117,7 @@ class UI:
def _aseta_alkuosa(self, alkuosa): def _aseta_alkuosa(self, alkuosa):
alkuosa = alkuosa[0] alkuosa = alkuosa[0]
if search("^([CcDdEeFfGgAaBb][#b]?[0-8]\|)*[CcDdEeFfGgAaBb][#b]?[0-8]$", alkuosa): if search(r"^([CcDdEeFfGgAaBb][#b]?[0-8]\|)*[CcDdEeFfGgAaBb][#b]?[0-8]$", alkuosa):
self._alku = alkuosa self._alku = alkuosa
else: else:
self._virheet.append("ANNETTU ALKUOSA EI KELPAA!") self._virheet.append("ANNETTU ALKUOSA EI KELPAA!")
@ -124,7 +137,9 @@ class UI:
def _generoi_savelma(self, _): def _generoi_savelma(self, _):
musiikki_generaattori.lue_opetusdata(self._opetusdata_polku) musiikki_generaattori.lue_opetusdata(self._opetusdata_polku)
musiikki_generaattori.valmistele_ketju(self._alku, self._aste) musiikki_generaattori.valmistele_ketju(self._alku, self._aste)
print(f"Generoitiin {musiikki_generaattori.generoi_nuotteja(self._nuottien_maara)} nuottia!\n")
generoitu_maara = musiikki_generaattori.generoi_nuotteja(self._nuottien_maara)
print(f"Generoitiin {generoitu_maara} nuottia!\n")
musiikki_generaattori.kirjoita_midi(self._tulos_polku, self._tempo) musiikki_generaattori.kirjoita_midi(self._tulos_polku, self._tempo)
def _sulje(self): def _sulje(self):