csong@1: # This python file is a collection of basic functions that are used in the syncopation models. csong@1: csong@1: import math csong@1: csong@1: # The concatenation function is used to concatenate two sequences. csong@1: def concatenate(seq1,seq2): csong@1: return seq1+seq2 csong@1: csong@1: # The repetition function is to concatenate a sequence to itself for 'times' number of times. csong@1: def repeat(seq,times): csong@1: new_seq = list(seq) csong@1: if times >= 1: csong@1: for i in range(times-1): csong@1: new_seq = concatenate(new_seq,seq) csong@1: else: csong@1: #print 'Error: repetition times needs to be no less than 1.' csong@1: new_seq = [] csong@1: return new_seq csong@1: csong@1: # The subdivision function is to equally subdivide a sequence into 'divisor' number of segments. csong@1: def subdivide(seq,divisor): csong@1: subSeq = [] csong@1: if len(seq) % divisor != 0: csong@1: print 'Error: rhythmic sequence cannot be equally subdivided.' csong@1: else: csong@1: n = len(seq) / divisor csong@1: start , end = 0, n csong@1: for i in range(divisor): csong@1: subSeq.append(seq[start : end]) csong@1: start = end csong@1: end = end + n csong@1: return subSeq csong@1: csong@1: csong@1: # The ceiling function is to round each number inside a sequence up to its nearest integer. csong@1: def ceiling(seq): csong@1: seq_ceil = [] csong@1: for s in seq: csong@1: seq_ceil.append(int(math.ceil(s))) csong@1: return seq_ceil csong@1: csong@1: # The find_divisor function returns a list of all possible divisors for a length of sequence. csong@1: def find_divisor(number): csong@1: divisors = [1] csong@1: for i in range(2,number+1): csong@1: if number%i ==0: csong@1: divisors.append(i) csong@1: return divisors csong@1: csong@1: # The find_divisor function returns a list of all possible divisors for a length of sequence. csong@1: def find_prime_factors(number): csong@1: prime_factors = find_divisor(number) csong@1: csong@1: def is_prime(num): csong@1: if num < 2: csong@1: return False csong@1: if num == 2: csong@1: return True csong@1: else: csong@1: for div in range(2,num): csong@1: if num % div == 0: csong@1: return False csong@1: return True csong@1: csong@1: for i in range(len(prime_factors)-1,0,-1): csong@1: if is_prime(prime_factors[i]) == False: csong@1: del prime_factors[i] csong@1: csong@1: return prime_factors csong@1: csong@1: # The min_timeSpan function searches for the shortest possible time-span representation for a sequence. csong@1: def get_min_timeSpan(seq): csong@1: min_ts = [1] csong@1: for d in find_divisor(len(seq)): csong@1: segments = subdivide(seq,d) csong@1: if len(segments)!=0: csong@1: del min_ts[:] csong@1: for s in segments: csong@1: min_ts.append(s[0]) csong@1: if sum(min_ts) == sum(seq): csong@1: break csong@1: return min_ts csong@1: csong@1: # get_note_indices returns all the indices of all the notes in this sequence csong@1: def get_note_indices(seq): csong@1: note_indices = [] csong@1: csong@1: for index in range(len(seq)): csong@1: if seq[index] != 0: csong@1: note_indices.append(index) csong@1: csong@1: return note_indices csong@1: csong@1: # The get_H returns a sequence of metrical weight for a certain metrical level (horizontal), csong@1: # given the sequence of metrical weights in a hierarchy (vertical) and a sequence of subdivisions. csong@1: def get_H(weight_seq,subdivision_seq, level): csong@1: H = [] csong@1: #print len(weight_seq), len(subdivision_seq), level csong@1: if (level <= len(subdivision_seq)-1) & (level <= len(weight_seq)-1): csong@1: if level == 0: csong@1: H = repeat([weight_seq[0]],subdivision_seq[0]) csong@1: else: csong@1: H_pre = get_H(weight_seq,subdivision_seq,level-1) csong@1: for h in H_pre: csong@1: H = concatenate(H, concatenate([h], repeat([weight_seq[level]],subdivision_seq[level]-1))) csong@1: else: csong@1: print 'Error: a subdivision factor or metrical weight is not defined for the request metrical level.' csong@1: return H csong@1: csong@1: # The get_subdivision_seq function returns the subdivision sequence of several common time-signatures defined by GTTM, csong@1: # or ask for the top three level of subdivision_seq manually set by the user. csong@1: def get_subdivision_seq(timesig, L_max): csong@1: subdivision_seq = [] csong@1: csong@1: if timesig == '2/4' or timesig == '4/4': csong@1: subdivision_seq = [1,2,2] csong@1: elif timesig == '3/4': csong@1: subdivision_seq = [1,3,2] csong@1: elif timesig == '6/8': csong@1: subdivision_seq = [1,2,3] csong@1: elif timesig == '9/8': csong@1: subdivision_seq = [1,3,3] csong@1: elif timesig == '12/8': csong@1: subdivision_seq = [1,4,3] csong@1: elif timesig == '5/4': csong@1: subdivision_seq = [1,5,2] csong@1: elif timesig == '7/4': csong@1: subdivision_seq = [1,7,2] csong@1: elif timesig == '11/4': csong@1: subdivision_seq = [1,11,2] csong@1: else: csong@1: print 'Undefined time-signature. Please indicate subdivision sequence for this requested time-signature, e.g. [1,2,2] for 4/4 meter.' csong@1: for i in range(3): csong@1: s = int(input('Enter the subdivision factor at metrical level '+str(i)+':')) csong@1: subdivision_seq.append(s) csong@1: csong@1: if L_max > 2: csong@1: subdivision_seq = subdivision_seq + [2]*(L_max-2) csong@1: else: csong@1: subdivision_seq = subdivision_seq[0:L_max+1] csong@1: csong@1: return subdivision_seq csong@1: csong@1: # The split_by_bar function seperates the score representation of rhythm by bar lines, csong@1: # resulting in a list representingbar-by-bar rhythm sequence, csong@1: # e.g. rhythm = ['|',[ts1,td1,v1], [ts2,td2,v2], '|',[ts3,td3,v3],'|'...] csong@1: # rhythm_bybar = [ [ [ts1,td1,v1], [ts2,td2,v2] ], [ [ts3,td3,v3] ], [...]] csong@1: # def split_by_bar(rhythm): csong@1: # rhythm_bybar = [] csong@1: # bar_index = [] csong@1: # for index in range(len(rhythm)): csong@1: # if rhythm[index] == '|': csong@1: csong@1: # return rhythm_bybar csong@1: csong@1: # def yseq_to_vseq(yseq): csong@1: # vseq = [] csong@1: csong@1: # return vseq csong@1: csong@1: csong@1: # # testing csong@1: # print find_prime_factors(10)