#!/usr/bin/env python3 from itertools import combinations import toene_dict as Dict def getmidinum(ton): """liefert die gewünschte Notennummer (Midi) zu einem Ton, eingegeben im Lilypond-Format""" midinotnum = Dict.toene_notnums[ton] return midinotnum def notnames2midinums(tonfolge): """ dasselbe wie getmidinum, aber mit einer folge von Tönen""" midinotnums = [ ] tonfolge = tonfolge.split() for t in tonfolge: midinotnums.append(getmidinum(t)) return midinotnums def getpc(ton): """liefert die pc-Nummer (0-11) zu einem gewünschten Ton,eingegeben im Lilypond-Format""" notnum = getmidinum(ton) pc = notnum%12 return pc def getton(num): # evtl. könnte man ja noch was machen, dass es auch bes gibt """ Liefert den zu einer Midi-Note passenden Ton, allerdings nur als erhöhten Ton.""" ton = Dict.notnums_toene[num] return ton def rotier_pcs(pcs): """ Findet die Rotationen bzw. \"Akkordumkehrungen\" eines pcs heraus. """ rotationen = [pcs] for i in range(1,len(pcs)): new_pcs = rotationen[i-1][1:] new_pcs.append(rotationen[i-1][0]) rotationen.append(new_pcs) return rotationen def find_pcs_intervall(pcs,pos_a,pos_b): """ Bestimmt das Intervall (die Differenz) zwischen den Elementen an den Stellen von pos_a und pos_b eines pcs.""" intervall = pcs[pos_b]-pcs[pos_a] if intervall < 0: intervall+=12 return intervall def find_minima(neliste): """Findet in einer Liste heraus, wo sich in einer Liste der kleinste Wert befindet. Gibt die Indices dieser Liste heraus. """ smallest = min(neliste) indices_smallest = [ ] for n in range(len(neliste)): if neliste[n] == smallest: indices_smallest.append(n) return indices_smallest def find_list_with_smallest_intervall(long_list,pos_a,pos_b): # zuerst eine liste erstellen,in der sich alle intervalle befinden intervall_liste= [ ] for n in long_list: intervall = find_pcs_intervall(n,pos_a,pos_b) intervall_liste.append(intervall) # dann herausfinden, wo sich das kleinste intervall befindet indices_kleinste_intervalle = find_minima(intervall_liste) # aus der langen liste die Listen filtern, in denen sich diese kleinsten intervalle befinden matches_list = [ ] for i in indices_kleinste_intervalle: matches_list.append(long_list[i]) return matches_list def get_normalform(pcs): """ Ermittelt die Normalform (nach Forte) eins Pcs.""" normalformen = rotier_pcs(pcs) for i in range(len(normalformen)): Indx = -1*(i+1) normalformen = find_list_with_smallest_intervall(normalformen,0,Indx) if len(normalformen) ==1: break return normalformen[0] def get_inversion(pitchnums): """Bildet die Umkehrung einer Tonfolge, gegeben in Midi-notnums oder als pcs""" intervalle = [ ] for i in range(1,len(pitchnums)): intervalle.append(pitchnums[i]-pitchnums[0]) intervalle = [i*-1 for i in intervalle ] spiegel = [pitchnums[-1]] for i in intervalle: spiegel.append(pitchnums[-1]+i) return spiegel def zeropc(pcs): """Das pcs wird auf "c"(0) transponiert""" return [(i-pcs[0])%12 for i in pcs ] def get_prime(pcs): """Ermittelt die Prime-Form (nach Forte) eins Pcs.""" normalform = get_normalform(pcs) inversion = sorted(get_inversion(normalform)) inversion = [i%12 for i in inversion ] # normalform auf c transponieren: normalform = zeropc(normalform) inversion = zeropc(get_normalform(inversion)) #inversion = [(i-inversion[0])%12 for i in inversion ] #print(inversion) if inversion 6: diff = 12-diff intervalle.append(diff) # jetzt in eine liste eintragen, wie oft die Werte 1-6 erscheinen intervall_vector = [ ] for n in range(1,7): num_matches = 0 for i in intervalle: if i ==n: num_matches +=1 intervall_vector.append(num_matches) return intervall_vector # alle pitch classes allpc_12edo = list(range(0,12)) # alle primeformen ermitteln, der Größe 2 bis 10 primes_12edo = [ ] for i in range(2,11): all_kombis = list(combinations(allpc_12edo,i)) for l in all_kombis: primeform = get_prime(list(l)) if primeform not in primes_12edo: primes_12edo.append(primeform) def find_lists_of_length(longlist,c): """ Find lists of length c (cardinality).""" matches = [ ] for l in longlist: if len(l) == c: matches.append(l) return matches def get_complement(pcs): """Findet die Töne, die nicht in einem pcs vorkommen""" rest = allpc_12edo.copy() for i in pcs: rest.remove(i) return rest # def transpose(pcs,value): """ Transponiert das pcs um den Wert von Value""" return [ (i+value)%12 for i in pcs ] def get_sublists(prime): """ Returns all sublists of prime form, from cardinality 3 up to len(prime)-1""" sublists = [ ] normforms_sublists = [ ] for i in range(3,len(prime)): sublists.extend(list(combinations(prime,i))) # wahrscheinlich muss mann noch mal die normalform dieser sublisten erstellen for l in sublists: normform = get_prime(list(l)) if normform not in normforms_sublists: normforms_sublists.append(normform) return normforms_sublists def findNumMatches(mylistA,mylistB): myNumMatches = 0 for i in mylistB: if i in mylistA: myNumMatches +=1 return myNumMatches def find_superlists(primeform): """ Find all lists that include the primeform or it's inversion, may it be transposed or not""" superlists = [ ] inversion = get_inversion(primeform) for i in range(12): pcs = transpose(primeform,i) pcs_inverted = transpose(inversion,i) for l in primes_12edo: if findNumMatches(l,pcs) == len(primeform) and l not in superlists: superlists.append(l) elif findNumMatches(l,pcs_inverted) == len(primeform) and l not in superlists: superlists.append(l) return superlists # check rp related primeforms def find_rps(prime): """ Searches for other primeforms, which have all but one pc in common with the given prime""" rpsets = [ ] # die primeforms gleicher Größe wie prime finden pcs_of_same_size = find_lists_of_length(primes_12edo,len(prime)) pcs_of_same_size.remove(prime) # aus dieser Liste prime entfernen # von jeder dieser primeform und deren spiegel alle transpositionen bilden und nach der anzahl der treffer len(prime) -1 schauen for pcs in pcs_of_same_size: pcs_inverted = sorted(get_inversion(pcs)) for i in range(12): pcs_transposed = transpose(pcs,i) if findNumMatches(prime,pcs_transposed) == len(prime)-1 and pcs not in rpsets: rpsets.append(pcs) elif findNumMatches(prime,pcs_inverted) == len(prime)-1 and pcs not in rpsets: rpsets.append(pcs) return rpsets def check_eq_trans(prime): """Searches for transpositions, which are identical with it's prime form. Puts out a list with intervall steps, that produce these transpositions.""" intervals = [ ] for i in range(1,12): pcs_transposed = transpose(prime,i) if set(prime) == set(pcs_transposed): intervals.append(i) return intervals def check_eq_invers(prime): # evtl. muss hier noch transponiert werden """ Searches for primeforms, which are identical with it's inversion""" if set(prime) == set(get_inversion(prime)): return True else: return False def check_zrel(prime_a,prime_b): """ Checks if two primes have the same inverval vector or not""" vec_a = get_vector(prime_a) vec_b = get_vector(prime_b) return vec_a == vec_b # Intervallvektoren vergleichen: def comp_vectors(vec_a,vec_b): """Finds out, how many interval-class entries between two vectors are of the same length and how many are not. Shows these interval-classes.""" equals = [ ] unequals = [ ] for i in range(len(vec_a)): interval_class = i+1 num_intervals_a = vec_a[i] num_intervals_b = vec_b[i] if num_intervals_b == num_intervals_a: equals.append((interval_class,num_intervals_a)) else: unequals.append((interval_class,vec_a[i],vec_b[i])) num_equals = len(equals) num_unequals = len(vec_a)-num_equals return num_equals,equals,num_unequals,unequals # list with all primeforms and their vectors primes_and_vectors_12edo = [ ] for p in primes_12edo: primes_and_vectors_12edo.append((p,get_vector(p))) # names for primes and their vectors that have the same length primes_vecs_of_three,primes_vecs_of_four,primes_vecs_of_five,primes_vecs_of_six,primes_vecs_of_seven,primes_vecs_of_eight,primes_vecs_of_nine =[],[],[],[],[],[],[] list_names = [primes_vecs_of_three,primes_vecs_of_four,primes_vecs_of_five,primes_vecs_of_six,primes_vecs_of_seven,primes_vecs_of_eight,primes_vecs_of_nine] for i in range(3,10): for p in primes_and_vectors_12edo: if len(p[0]) == i: list_names[i-3].append(p) def find_zrels(longlist): """ Finds pairs of primeforms with the same intervall-vector. Puts out first the vector followed by it's related primeforms """ zrels = [ ] all_pairs = combinations(longlist,2) for p in all_pairs: vec_a = get_vector(p[0]) vec_b = get_vector(p[1]) print(vec_a,vec_b) if vec_a == vec_b: zrels.append((vec_a,p[0],p[1])) return zrels def find_zrels(c,longlist): """ Finds pairs of primeforms of the length c, that share the same intervall-vector. Puts out the vector followed by it's related primeforms """ list_len_c = [ ] z_list = [ ] for l in longlist: if len(l[0]) == c: list_len_c.append(l) # paare bilden pairs = combinations(list_len_c,2) # die vectoren der Paare vergleichen: for p in pairs: if p[0][1] == p[1][1]: z_list.append((p[0][1],p[0][0],p[1][0])) return z_list print(find_zrels(4,primes_and_vectors_12edo))