Toteuta MIDI-muunnos
This commit is contained in:
parent
058bdbd518
commit
83fd8ea522
9 changed files with 82 additions and 29 deletions
BIN
dokumentaatio/muunnos1.mp3
Executable file
BIN
dokumentaatio/muunnos1.mp3
Executable file
Binary file not shown.
BIN
dokumentaatio/muunnos2.mp3
Executable file
BIN
dokumentaatio/muunnos2.mp3
Executable file
Binary file not shown.
|
@ -23,7 +23,7 @@ Viikko 4: Generoin koodin nykyisellä versiolla 4:nnen asteen Markovin ketjulla
|
|||
|
||||
Viikko 5: Toteutin tällä viikolla manuaalisen rytmin määrittämisen. Generoin 80 lyhyen melodian yksinkertaisella kahden tahdin välein toistuvalla rytmillä. Yllätin siitä kuinka paljon yksinkertainenkin rytmi "elävöitti" generoitua melodiaa.
|
||||
|
||||
Viikko 6: Testasin tällä viikolla kattavammin eri asteilla. Rajoitin asteen alle 5, sillä huomasin että tätä suuremmilla asteilla monessa tilanteessa oli vain yksi vaihtoehto seuraavalle nuotille, joka viittaa siihen että opetusdatan määrä ei ole riittävän suuri. Poistin myös tämän takia aiemmat testit.
|
||||
Viikko 6: Testasin tällä viikolla kattavammin eri asteilla. Rajoitin asteen alle 5, sillä huomasin että tätä suuremmilla asteilla monessa tilanteessa oli vain yksi vaihtoehto seuraavalle nuotille, joka viittaa siihen että opetusdatan määrä ei ole riittävän suuri. Poistin myös tämän takia aiemmat testit. Lisäksi toteutin mekanismin, jolla olemassaolevan MIDI tiedoston 1. raidan nuotin voidaan korvata Markovin ketjun antamilla nuoteilla. Nämä "muunnokset" löytyvät myös alta. Näissä oli käytössä 4. asteen ketju.
|
||||
|
||||
[Aste 1](https://github.com/ArcticCoder/markov-music-generator/blob/main/dokumentaatio/aste_1.mp3)
|
||||
|
||||
|
@ -35,4 +35,8 @@ Viikko 6: Testasin tällä viikolla kattavammin eri asteilla. Rajoitin asteen al
|
|||
|
||||
[Aste 4, ei rytmiä](https://github.com/ArcticCoder/markov-music-generator/blob/main/dokumentaatio/aste_4_rytmiton.mp3)
|
||||
|
||||
[MIDI muunnos 1](https://github.com/ArcticCoder/markov-music-generator/blob/main/dokumentaatio/muunnos1.mp3)
|
||||
|
||||
[MIDI muunnos 2](https://github.com/ArcticCoder/markov-music-generator/blob/main/dokumentaatio/muunnos2.mp3)
|
||||
|
||||
[Sattuma](https://github.com/ArcticCoder/markov-music-generator/blob/main/dokumentaatio/testi-sattuma.mp3)
|
||||
|
|
|
@ -15,3 +15,5 @@ https://musescore.com/user/38606/scores/6082483
|
|||
https://musescore.com/user/110059/scores/980236
|
||||
https://musescore.com/user/36583375/scores/6502523
|
||||
https://musescore.com/r_d/scores/5449385
|
||||
https://musescore.com/user/285631/scores/287116
|
||||
https://musescore.com/user/33617769/scores/6363495
|
||||
|
|
BIN
opetusdata/muunnos1.mid
Normal file
BIN
opetusdata/muunnos1.mid
Normal file
Binary file not shown.
BIN
opetusdata/muunnos2.mid
Normal file
BIN
opetusdata/muunnos2.mid
Normal file
Binary file not shown.
|
@ -45,31 +45,58 @@ def lue_midi(tiedostopolku):
|
|||
|
||||
return tulos
|
||||
|
||||
def kirjoita_midi(tiedostopolku, nuotit, tempo=120, rytmi="1/4"):
|
||||
"""Kirjoittaa halutut nuotit valittuun MIDI-tiedostoon annetulla tempolla"""
|
||||
def kirjoita_midi(tiedostopolku, nuotit, muunnettava_midi=None, tempo=120, rytmi="1/4"):
|
||||
"""Kirjoittaa nuotit MIDI-tiedostoon halutulla tempolla ja rytmillä.
|
||||
Vaihtoehtoisesti ottaa valitun MIDI-tiedoston ja vaihtaa sävelkorkeudet
|
||||
"""
|
||||
midi = mido.MidiFile()
|
||||
raita = mido.MidiTrack()
|
||||
|
||||
rytmi = rytmi_taulukoksi(rytmi)
|
||||
iskun_kesto = midi.ticks_per_beat
|
||||
rytmi = [round(x*4*iskun_kesto) for x in rytmi]
|
||||
if muunnettava_midi:
|
||||
muutettava = mido.MidiFile(muunnettava_midi)
|
||||
muutettava_raita = muutettava.tracks[0]
|
||||
|
||||
raita.append(mido.MetaMessage("set_tempo", tempo=mido.bpm2tempo(tempo), time=0))
|
||||
raita.append(mido.MetaMessage("time_signature"))
|
||||
raita.append(mido.Message("program_change", program=0, time=0))
|
||||
muunnokset = {}
|
||||
|
||||
rytmi_i = 0
|
||||
nuotti_i = 0
|
||||
|
||||
for nuotti in nuotit:
|
||||
if nuotti:
|
||||
raita.append(mido.Message("note_on", note=nuotti, velocity=64, time=0))
|
||||
raita.append(mido.Message("note_on", note=nuotti, velocity=0, time=rytmi[rytmi_i]))
|
||||
rytmi_i = (rytmi_i + 1) % len(rytmi)
|
||||
for viesti in muutettava_raita:
|
||||
if viesti.type == "note_on" and viesti.velocity > 0:
|
||||
muunnokset[viesti.note] = nuotit[nuotti_i]
|
||||
raita.append(mido.Message("note_on",
|
||||
note=muunnokset[viesti.note], velocity=64, time=viesti.time))
|
||||
|
||||
nuotti_i += 1
|
||||
if nuotti_i == len(nuotit):
|
||||
break
|
||||
elif viesti.type == "note_off" or (viesti.type == "note_on" and viesti.velocity == 0):
|
||||
raita.append(mido.Message("note_on",
|
||||
note=muunnokset[viesti.note], velocity=0, time=viesti.time))
|
||||
|
||||
else:
|
||||
raita.append(viesti)
|
||||
else:
|
||||
iskun_kesto = midi.ticks_per_beat
|
||||
rytmi = rytmi_taulukoksi(rytmi)
|
||||
rytmi = [round(x*4*iskun_kesto) for x in rytmi]
|
||||
|
||||
raita.append(mido.MetaMessage("set_tempo", tempo=mido.bpm2tempo(tempo), time=0))
|
||||
raita.append(mido.MetaMessage("time_signature"))
|
||||
raita.append(mido.Message("program_change", program=0, time=0))
|
||||
|
||||
rytmi_i = 0
|
||||
|
||||
for nuotti in nuotit:
|
||||
if nuotti:
|
||||
raita.append(mido.Message("note_on", note=nuotti, velocity=64, time=0))
|
||||
raita.append(mido.Message("note_on", note=nuotti, velocity=0, time=rytmi[rytmi_i]))
|
||||
rytmi_i = (rytmi_i + 1) % len(rytmi)
|
||||
|
||||
midi.tracks.append(raita)
|
||||
midi.save(tiedostopolku)
|
||||
|
||||
def rytmi_taulukoksi(rytmi):
|
||||
"""Muuntaa annetun rytmin numeeriseksi taulukoksi"""
|
||||
rytmi = rytmi.split("|")
|
||||
tulos = []
|
||||
for alkio in rytmi:
|
||||
|
|
|
@ -45,7 +45,7 @@ class MusiikkiGeneraattori:
|
|||
for jono in lue_midi(tiedosto):
|
||||
self._opetusdata.append(jono)
|
||||
# Kaikki virheet halutaan ohittaa
|
||||
except: # pylint: disable=bare-except
|
||||
except Exception: # pylint: disable=broad-except
|
||||
continue
|
||||
|
||||
def valmistele_ketju(self, alkuosa, aste=1):
|
||||
|
@ -95,9 +95,14 @@ class MusiikkiGeneraattori:
|
|||
|
||||
return len(self._nuotit)
|
||||
|
||||
def kirjoita_midi(self, tiedostopolku, tempo=120, rytmi="1/4"):
|
||||
"""Kirjoittaa nuotit MIDI-tiedostoon halutulla tempolla ja rytmillä"""
|
||||
kirjoita_midi(tiedostopolku, self._nuotit, tempo, rytmi)
|
||||
def kirjoita_midi(self, tiedostopolku, muunnettava_midi=None, tempo=120, rytmi="1/4"):
|
||||
"""Kirjoittaa nuotit MIDI-tiedostoon halutulla tempolla ja rytmillä.
|
||||
Vaihtoehtoisesti ottaa valitun MIDI-tiedoston ja vaihtaa sävelkorkeudet
|
||||
"""
|
||||
if muunnettava_midi:
|
||||
kirjoita_midi(tiedostopolku, self._nuotit, muunnettava_midi)
|
||||
else:
|
||||
kirjoita_midi(tiedostopolku, self._nuotit, None, tempo, rytmi)
|
||||
|
||||
def _nuotit_midiksi(self, nuotit: str):
|
||||
"""Muuttaa perinteiset nuottimerkinnät kuten C#4 MIDI-arvoiksi"""
|
||||
|
|
33
src/ui.py
33
src/ui.py
|
@ -1,6 +1,7 @@
|
|||
"""Musiikki generaattorin tekstipohjainen käyttöliittymä
|
||||
from ui import UI"""
|
||||
from os import system, name
|
||||
from os.path import exists
|
||||
from re import search
|
||||
from sys import exit as sys_exit
|
||||
from musiikki_generaattori import musiikki_generaattori
|
||||
|
@ -15,6 +16,7 @@ class UI: # pylint: disable=too-few-public-methods, too-many-instance-attributes
|
|||
self._nuottien_maara = 120
|
||||
self._tempo = 120
|
||||
self._rytmi = "1/4"
|
||||
self._muunnettava_midi_polku = ""
|
||||
|
||||
self._toiminnot = {
|
||||
"A": ("(A)pu", self._tulosta_apu, 0,
|
||||
|
@ -25,14 +27,16 @@ class UI: # pylint: disable=too-few-public-methods, too-many-instance-attributes
|
|||
"Valitse valmiin sävelmän polku"),
|
||||
"K": ("(K)etjun aste", self._aseta_aste, 1,
|
||||
"Aseta Markovin ketjun aste valittuun kokonaislukuun"),
|
||||
"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"),
|
||||
"R": ("(R)ytmi [merkkijono]", self._aseta_rytmi, 1,
|
||||
"Aseta rytmi. Esim. '1/4|1/4|1/2'"),
|
||||
"L": ("a(L)kuosa [merkkijono]", self._aseta_alkuosa, 1,
|
||||
"Aseta alkuosa. Esim. 'C4|D#5|Gb3'"),
|
||||
"M": ("(M)uunnettava MIDI [polku]", self._aseta_muunnettava_midi, 1,
|
||||
"Valitse MIDI, jonka sävelkorkeudet vaihdetaan generoituihin"),
|
||||
"G": ("(G)eneroi sävelmä", self._generoi_savelma, 0,
|
||||
"Generoi sävelmä valituilla asetuksilla"),
|
||||
"S": ("(S)ulje", self._sulje, 0,
|
||||
|
@ -69,9 +73,11 @@ class UI: # pylint: disable=too-few-public-methods, too-many-instance-attributes
|
|||
for i in range(1, 1+parametrien_maara):
|
||||
parametrit.append(komento[i])
|
||||
funktio(parametrit)
|
||||
# Kaikki virheet halutaan ohittaa
|
||||
except: # pylint: disable=bare-except
|
||||
self._virheet.append("KOMENNON MUOTO VÄÄRÄ!")
|
||||
except IndexError:
|
||||
self._virheet.append("ARGUMENTTIEN MÄÄRÄ VÄÄRÄ!")
|
||||
# Kaikki muut virheet halutaan ohittaa
|
||||
except Exception as exception: # pylint: disable=broad-except
|
||||
self._virheet.append(f"TUNTEMATON VIRHE! {str(exception)}")
|
||||
|
||||
def _tyhjenna(self):
|
||||
# windows
|
||||
|
@ -92,12 +98,14 @@ class UI: # pylint: disable=too-few-public-methods, too-many-instance-attributes
|
|||
def _tulosta_arvot(self):
|
||||
print(f"Opetusdata: '{self._opetusdata_polku}'")
|
||||
print(f"Generoidun sävelmän polku: '{self._tulos_polku}'")
|
||||
print()
|
||||
print(f"Markovin ketjun aste: {self._aste}")
|
||||
print(f"Alkuosa: '{self._alku}'")
|
||||
print(f"Sävelmän pituus nuotteina: {self._nuottien_maara}")
|
||||
print()
|
||||
print(f"Tempo: {self._tempo}")
|
||||
print(f"Rytmi: '{self._rytmi}'")
|
||||
print(f"Alkuosa: '{self._alku}'")
|
||||
print("TAI")
|
||||
print(f"Muunnettava MIDI: '{self._muunnettava_midi_polku}'")
|
||||
|
||||
def _tulosta_apu(self, _):
|
||||
print("OHJEET")
|
||||
|
@ -117,7 +125,7 @@ class UI: # pylint: disable=too-few-public-methods, too-many-instance-attributes
|
|||
try:
|
||||
aste = int(aste[0])
|
||||
if aste < 1:
|
||||
raise ValueError;
|
||||
raise ValueError
|
||||
self._aste = aste
|
||||
except ValueError:
|
||||
self._virheet.append("ANNETTU ASTE EI MUUTETTAVISSA KOKONAISLUVUKSI!")
|
||||
|
@ -154,13 +162,20 @@ class UI: # pylint: disable=too-few-public-methods, too-many-instance-attributes
|
|||
else:
|
||||
self._virheet.append("ANNETTU ALKUOSA EI KELPAA!")
|
||||
|
||||
def _aseta_muunnettava_midi(self, polku):
|
||||
self._muunnettava_midi_polku = polku[0]
|
||||
|
||||
def _generoi_savelma(self, _):
|
||||
musiikki_generaattori.lue_opetusdata(self._opetusdata_polku)
|
||||
musiikki_generaattori.valmistele_ketju(self._alku, self._aste)
|
||||
|
||||
generoitu_maara = musiikki_generaattori.generoi_nuotteja(self._nuottien_maara)
|
||||
|
||||
if exists(self._muunnettava_midi_polku):
|
||||
musiikki_generaattori.kirjoita_midi(self._tulos_polku, self._muunnettava_midi_polku)
|
||||
else:
|
||||
musiikki_generaattori.kirjoita_midi(self._tulos_polku, None, self._tempo, self._rytmi)
|
||||
print(f"Generoitiin {generoitu_maara} nuottia!\n")
|
||||
musiikki_generaattori.kirjoita_midi(self._tulos_polku, self._tempo, self._rytmi)
|
||||
|
||||
def _sulje(self):
|
||||
sys_exit(0)
|
||||
|
|
Reference in a new issue