Siisti koodia
This commit is contained in:
parent
e9312f4998
commit
4bf5257534
5 changed files with 69 additions and 35 deletions
|
@ -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
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
"""Päämoduuli. Käynnistää ainoastaan UI:n"""
|
||||||
from ui import UI
|
from ui import UI
|
||||||
|
|
||||||
ui = UI()
|
ui = UI()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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:
|
||||||
|
|
43
src/ui.py
43
src/ui.py
|
@ -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):
|
||||||
|
|
Reference in a new issue