Benutzer-Werkzeuge

Webseiten-Werkzeuge


ws1516:melodiegenerator

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
ws1516:melodiegenerator [2016/02/02 12:51]
h.schoeller96 [Zwischenprotokoll: Kompositionen.py]
ws1516:melodiegenerator [2016/05/10 14:46] (aktuell)
Zeile 315: Zeile 315:
  
 ====Sitzung 8==== ====Sitzung 8====
-Anwesend: Sebastian, Svenja+Anwesend: Sebastian, Svenja ​ 
 +Datum: 21.01.2015
  
 Auf die Hälfte reduziert, hat sich Sebastian damit beschäftigt,​ wie man möglicherweise die Markovketten in Programm schreiben könnte, außerdem wurde ein Programmschnipsel geschrieben,​ der in Abhängigkeit von Wahrscheinlichkeiten neue Tonhöhen, Lautstärken und Dauern ausgeben kann. Die Wahrscheinlichkeiten und die Möglichkeiten müssen in zwei zueinander passenden Listen vorliegen, was zugegebenermaßen nicht sehr komfortabel ist und vielleicht noch verbessert werden kann. Möglichkeiten sind bei der Tonhöhe dann eben alle Töne, die auf einen bestimmten Ton folgen könnten, denen nach der Analyse der Soli eben eine Wahrscheinlichkeit zugeordnet ist. Auf die Hälfte reduziert, hat sich Sebastian damit beschäftigt,​ wie man möglicherweise die Markovketten in Programm schreiben könnte, außerdem wurde ein Programmschnipsel geschrieben,​ der in Abhängigkeit von Wahrscheinlichkeiten neue Tonhöhen, Lautstärken und Dauern ausgeben kann. Die Wahrscheinlichkeiten und die Möglichkeiten müssen in zwei zueinander passenden Listen vorliegen, was zugegebenermaßen nicht sehr komfortabel ist und vielleicht noch verbessert werden kann. Möglichkeiten sind bei der Tonhöhe dann eben alle Töne, die auf einen bestimmten Ton folgen könnten, denen nach der Analyse der Soli eben eine Wahrscheinlichkeit zugeordnet ist.
Zeile 362: Zeile 363:
 ==== Sitzung 9 ==== ==== Sitzung 9 ====
 Anwesend: Sebastian, Svenja, Csaba, Henry Anwesend: Sebastian, Svenja, Csaba, Henry
 +Datum: 28.01.2016
  
 Heute haben sich Csaba un Henry mit einer Methode beschäftigt,​ die Akkorde generiert. Hierzu benötigt die Methode lediglich den Grundton, die Tonart und eventuell eine Umkehrung. Der Code sieht wie folgt aus: Heute haben sich Csaba un Henry mit einer Methode beschäftigt,​ die Akkorde generiert. Hierzu benötigt die Methode lediglich den Grundton, die Tonart und eventuell eine Umkehrung. Der Code sieht wie folgt aus:
Zeile 387: Zeile 389:
 </​code>​ </​code>​
  
 +Im Gegensatz zu dem Vorgehen in der Klasse Akkord, haben wir uns hier entschieden,​ keine Zahlen als Eingangsvariablen akzeptieren,​ weil aus einer bestimmten Tonhöhe noch nicht eindeutig der Tonname hervorgeht und somit musiktheoretisch nicht eindeutig ein Akkord gebaut werden kann (Fis und Ges z.B. haben die Selbe Tonhöhe).
 +
 +==== Sitzung 10 ====
 +Anwesend: Sebastian, Svenja, Csaba, Henry
 +Datum: 04.02.2016
 +
 +Heute hat Henry sich daran gemacht, die Markov-Analyse in die aktuell bestehende Programmierugebung zu integrieren. Hierzu wurde ein neues Dokument mit dem Titel "​Analyse"​ erstellt.
 +
 +<code python>
 +
 +from __future__ import division
 +from Kompositionen import Stimme
 +from Kompositionen import Ton
 +from Kompositionen import hoehenrechner
 +from pickle import Pickler
 +from pickle import Unpickler
 +
 +def speicher(wb,​ datei):
 +    with open(datei,"​w"​)as f:
 +        p=Pickler(f)
 +        p.dump(wb)
 +        ​
 +def oeffne(datei):​
 +    with open(datei, "​r"​)as f:
 +        u=Unpickler(f)
 +        wb=u.load
 +        return wb
 +
 +def build_markov(melodie,​ tonstat={}): ​   ​
 +    '''​Diese Methode erwartet eine melodie als Objekt der Klasse Stimme. Aus dieser legt 
 +    sie ein Wörterbuch an, welches Für jeden Ton speichert, ob und wenn ja,
 +    wie häufig ein anderer Ton nach diesem Ton vorkam. Nur die Tonhöhe ist relevant.
 +    Ebenfalls erwartet es ein Wörterbuch,​ in dem die Tonfolgehäufigkeiten gespeichert sind. Gibt es keins, wird ein leeres erzeugt.'''​
 +    for i,ton in enumerate (melodie.toene):​
 +        if i==len(melodie.toene)-1:​
 +            break
 +        if ton.hoehe not in tonstat:
 +            wb={} #Falls der Ton noch nicht vorkam, lege ein Wörterbuch an, speichere den Folgeton und 
 +            wb[melodie.toene[i+1].hoehe]=1 # füge das Wörterbuch dem großen Wörterbuch hinzu.
 +            tonstat[ton.hoehe]=wb
 +        else:#Ist der Folgeton für diesen Ton noch nicht aufgetauch, lege einen neuen Eintrag im Wörterbuch an.
 +            if melodie.toene[i+1].hoehe not in tonstat[ton.hoehe]:​
 +                tonstat[ton.hoehe][melodie.toene[i+1].hoehe]=1
 +            else:#​Ansonsten erhöhe den Häufigkeitswert um 1.
 +                tonstat[ton.hoehe][melodie.toene[i+1].hoehe]+=1
 +    return tonstat
 +
 +</​code>​
 +
 +Die Methode build_markov liefert also die absolut statistische Grundlage für eine Analyse. Lediglich kann die Methode nur eine einzelne Datei zur Zeit analysieren. Zur Analyse von einer ganzen Menge Dateien dient die Methode "​analyse":​
 +
 +<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 einem Tonhäufigkeitswörterbuch für alle Dateien zusammen zurück.''' ​   ​
 +    tonstat={}
 +    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
 +                tonstat=build_markov(aktmelodie,​tonstat)#​sexy Rekursion; fügt die Tonhäufigkeiten der aktuellen Melodie dem bestehenden Wörterbuch hinzu
 +    return tonstat
 +</​code>​
 +
 +Als letztes wurde eine Methode geschrieben,​ die aus einem Wörterbuch,​ welches absolute Häufigkeiten gespeichert hat, ein Wörterbuch erzeugt, welches für jeden Ton die Wahrscheinlichkeiten für die Folgetöne speichert. Dies geschieht in der Methode "​build_markovp":​
 +
 +<code python>
 +def build_markovp(tonstat):​
 +    '''​Diese Methode erwartet ein absolute Häufigkeiten und wandelt diese in relative Häufigkeiten um.'''​
 +    tonstatp={} ​   ​
 +    for ton in tonstat:
 +        tonstatp[ton]={}
 +        summe=0 ​       ​
 +        for folgeton in tonstat[ton]:#​Zählt,​ wie viele Folgetöne für den Ton (absolut) vorkamen.
 +            summe=summe+tonstat[ton][folgeton]
 +        for folgeton in tonstat[ton]:#​Weist jedem Folgeton seinen relativen Häufigkeitswert zu.
 +            tonstatp[ton][folgeton]=(tonstat[ton][folgeton])/​summe
 +        neue_summe=0
 +        for folgeton in tonstatp[ton]:#​Weist den Folgetönen Bereiche zwischen 0 und 1 zu, deren Länge ihrer Häufigkeit entsprechen.
 +            neue_summe=neue_summe+tonstatp[ton][folgeton]#​Wird später eine Zufallszahl ziwschen 0 und 1 erzeugt, wird der Ton gewählt, in dessen Bereich diese Zufallszahl trifft. ​       ​
 +            tonstatp[ton][folgeton]=neue_summe
 +    return tonstatp
 +</​code>​
 +
 +
 +==== Sitzung 11 ====
 +Anwesend: Sebastian, Svenja, Csaba, Henry
 +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>​
ws1516/melodiegenerator.1454413892.txt.gz · Zuletzt geändert: 2016/05/10 14:46 (Externe Bearbeitung)