Hier werden die Unterschiede zwischen zwei Versionen gezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
ws1516:melodiegenerator [2016/02/16 20:52] h.schoeller96 [Sitzung 10] |
ws1516:melodiegenerator [2016/05/10 14:46] (aktuell) |
||
---|---|---|---|
Zeile 478: | Zeile 478: | ||
Anwesend: Sebastian, Svenja, Csaba, Henry | Anwesend: Sebastian, Svenja, Csaba, Henry | ||
Datum: 11.02.2016 | Datum: 11.02.2016 | ||
+ | |||
+ | Heute wurde an der Datei "Analyse" weitergearbeitet. Es wurde eine Methode hinzugefügt, welche aus einem "Folgetonwahrscheinlichkeitswörterbuch" (so wie tonstatp, siehe oben) eine zufällige Melodie erzeugt. Diese Methode heißt buid_melodie: | ||
+ | |||
+ | <code python> | ||
+ | import random | ||
+ | |||
+ | def build_melodie(tonstatp, anfangston, laenge=16,): | ||
+ | '''Erzeugt eine Zufallsmelodie, die ein relatives Folgetonhäufigkeitswörterbuch tonstatp benötigt. Der Anfangston kann selbst gewählt werden. | ||
+ | ''' | ||
+ | neue_melodie=Stimme(0) | ||
+ | anfangston=hoehenrechner(anfangston) | ||
+ | i=0 | ||
+ | while i<laenge: | ||
+ | rdauer=random.randint(1,4) | ||
+ | if i==0: | ||
+ | neuer_ton=Ton(rdauer,anfangston,0.4) | ||
+ | else: | ||
+ | rhoehe=random.random() | ||
+ | for folgeton in tonstatp[neue_melodie.toene[len(neue_melodie.toene)-1].hoehe]: | ||
+ | #Geht die relativen Häufigkeitswerte des Eintrages des aktuell letzten Tones der Melodie im Wörterbuch durch. | ||
+ | if rhoehe<tonstatp[neue_melodie.toene[len(neue_melodie.toene)-1].hoehe][folgeton]: | ||
+ | #Ist der Bereich gefunden, in dem die Zufallsvariable rhoehe liegt, wird dieser Ton ausgewählt. | ||
+ | neuer_ton=Ton(rdauer,folgeton,0.4) | ||
+ | break | ||
+ | neue_melodie.add_ton(neuer_ton) | ||
+ | i+=1 | ||
+ | return neue_melodie | ||
+ | |||
+ | </code> | ||
+ | |||
+ | Außerdem wurde nun der bestehende Code so umgeschrieben, dass zwischen Moll und Dur differenziert wird und alle eingelesenen Melodien auf Tonarten ohne Vorzeichen transponiert werden (also C-Dur oder A-Moll). Die relevanten Passagen finden sich in der Methode "add_melodie" und der Methode "trans": | ||
+ | |||
+ | <code python> | ||
+ | def add_melodie(datei) | ||
+ | | ||
+ | [...] | ||
+ | | ||
+ | #Falls in der .mid Datei die Tonart gespeichert ist, wird sie der Stimme hinzugefügt. | ||
+ | for event in melodie: | ||
+ | if isinstance(event, midi.KeySignatureEvent): | ||
+ | if event.data[1]==0: | ||
+ | self.tonart=vorzeichendur[event.data[0]] +"_"+"dur" | ||
+ | elif event.data[1]==1: | ||
+ | self.tonart=vorzeichendur[(event.data[0]+3)%256]+"_"+"moll" | ||
+ | | ||
+ | #Die Melodie wird nun in eine Tonart ohne Vorzeichen transponiert. | ||
+ | if (not self.tonart=="c_dur") and (not self.tonart=="a_moll") and (not self.tonart==""): | ||
+ | aktgeschlecht=(self.tonart.split('_'))[1] | ||
+ | if aktgeschlecht=='moll': | ||
+ | self.trans('a_moll') | ||
+ | elif aktgeschlecht=='dur': | ||
+ | self.trans('c_dur') | ||
+ | | ||
+ | def trans(self, zieltonart): | ||
+ | '''Diese Methode transponiert die Stimme von der aktuellen in die Zieltonart. zieltonart liegt dabei als String der Form "Ton_Tongeschlecht" vor, | ||
+ | also zum Beispiel "Fis_dur"''' | ||
+ | zielgrundton=zieltonart.lower() | ||
+ | zielgrundton=zielgrundton.split('_') | ||
+ | zielgrundton=tonleiter[zielgrundton[0]] | ||
+ | aktgrundton=self.tonart.lower() | ||
+ | aktgrundton=aktgrundton.split('_') | ||
+ | aktgrundton=tonleiter[aktgrundton[0]] | ||
+ | for ton in self.toene: | ||
+ | ton.hoehe=ton.hoehe+(zielgrundton-aktgrundton) | ||
+ | self.tonart=zieltonart | ||
+ | </code> | ||
+ | |||
+ | Auch wurde in der Datei "analyse" einiges umgeschrieben. So wurde in der Methode "analyse" zwischen Dur und Moll differenziert: | ||
+ | |||
+ | <code python> | ||
+ | def analyse (Ordner): | ||
+ | '''Diese Methode analysiert alle Dateien im Verzeichnis Ordner (als String, also bspw. "Mathesis"), die auf .mid enden. | ||
+ | Sie gibt ein Wörterbuch mit zwei Tonhäufigkeitswörterbüchern (eines für Dur , eines für Moll) zurück.''' | ||
+ | tonstatd={}#dur | ||
+ | tonstatm={}#moll | ||
+ | for root,dirs,files in os.walk(Ordner): | ||
+ | for file in files: | ||
+ | if str(file)[-4:]=='.mid': | ||
+ | aktmelodie=Stimme(0)#legt eine neue Stimme an | ||
+ | aktmelodie.add_melodie(os.path.join(Ordner,file))#liest die aktuelle Melodie in die Stimme ein | ||
+ | if not aktmelodie.tonart=="":#Wenn eine Tonart in der Datei gefunden wurde | ||
+ | aktgeschlecht=aktmelodie.tonart[-4:] | ||
+ | if aktgeschlecht=='_dur': | ||
+ | tonstatd=build_markov(aktmelodie,tonstatd)#sexy Rekursion; fügt die Tonhäufigkeiten der aktuellen Melodie dem bestehenden Wörterbuch hinzu | ||
+ | elif aktgeschlecht=='moll': | ||
+ | tonstatm=build_markov(aktmelodie,tonstatm) | ||
+ | tonstat={'dur':tonstatd, 'moll':tonstatm} | ||
+ | return tonstat | ||
+ | </code> | ||
+ | |||
+ | Für ein schnelleres Arbeiten mit dem Programm wurden die Markovtabellen, in denen die Wahrscheinlichkeiten gespeichert sind (tonstatp, tonstatpm, tonstatpd) per Pickle gespeichert und müssen somit nicht mehr bei jedem Aufruf des Programms neu eingelesen werden: | ||
+ | |||
+ | <code python> | ||
+ | |||
+ | with open ("tonstatp.pickle","r")as f: | ||
+ | u=Unpickler(f) | ||
+ | tonstatp=u.load() | ||
+ | |||
+ | with open ("tonstatpd.pickle","r")as f: | ||
+ | u=Unpickler(f) | ||
+ | tonstatpd=u.load() | ||
+ | |||
+ | with open ("tonstatpm.pickle","r")as f: | ||
+ | u=Unpickler(f) | ||
+ | tonstatpm=u.load() | ||
+ | |||
+ | </code> |