annotate Syncopation models/basic_functions.py @ 1:b2da092dc2e0

The consolidated syncopation software. Have finished individual model and basic functions. Need to revise the coding in main.py, and add rhythm-input interface.
author Chunyang Song <csong@eecs.qmul.ac.uk>
date Sun, 05 Oct 2014 21:52:41 +0100
parents
children
rev   line source
csong@1 1 # This python file is a collection of basic functions that are used in the syncopation models.
csong@1 2
csong@1 3 import math
csong@1 4
csong@1 5 # The concatenation function is used to concatenate two sequences.
csong@1 6 def concatenate(seq1,seq2):
csong@1 7 return seq1+seq2
csong@1 8
csong@1 9 # The repetition function is to concatenate a sequence to itself for 'times' number of times.
csong@1 10 def repeat(seq,times):
csong@1 11 new_seq = list(seq)
csong@1 12 if times >= 1:
csong@1 13 for i in range(times-1):
csong@1 14 new_seq = concatenate(new_seq,seq)
csong@1 15 else:
csong@1 16 #print 'Error: repetition times needs to be no less than 1.'
csong@1 17 new_seq = []
csong@1 18 return new_seq
csong@1 19
csong@1 20 # The subdivision function is to equally subdivide a sequence into 'divisor' number of segments.
csong@1 21 def subdivide(seq,divisor):
csong@1 22 subSeq = []
csong@1 23 if len(seq) % divisor != 0:
csong@1 24 print 'Error: rhythmic sequence cannot be equally subdivided.'
csong@1 25 else:
csong@1 26 n = len(seq) / divisor
csong@1 27 start , end = 0, n
csong@1 28 for i in range(divisor):
csong@1 29 subSeq.append(seq[start : end])
csong@1 30 start = end
csong@1 31 end = end + n
csong@1 32 return subSeq
csong@1 33
csong@1 34
csong@1 35 # The ceiling function is to round each number inside a sequence up to its nearest integer.
csong@1 36 def ceiling(seq):
csong@1 37 seq_ceil = []
csong@1 38 for s in seq:
csong@1 39 seq_ceil.append(int(math.ceil(s)))
csong@1 40 return seq_ceil
csong@1 41
csong@1 42 # The find_divisor function returns a list of all possible divisors for a length of sequence.
csong@1 43 def find_divisor(number):
csong@1 44 divisors = [1]
csong@1 45 for i in range(2,number+1):
csong@1 46 if number%i ==0:
csong@1 47 divisors.append(i)
csong@1 48 return divisors
csong@1 49
csong@1 50 # The find_divisor function returns a list of all possible divisors for a length of sequence.
csong@1 51 def find_prime_factors(number):
csong@1 52 prime_factors = find_divisor(number)
csong@1 53
csong@1 54 def is_prime(num):
csong@1 55 if num < 2:
csong@1 56 return False
csong@1 57 if num == 2:
csong@1 58 return True
csong@1 59 else:
csong@1 60 for div in range(2,num):
csong@1 61 if num % div == 0:
csong@1 62 return False
csong@1 63 return True
csong@1 64
csong@1 65 for i in range(len(prime_factors)-1,0,-1):
csong@1 66 if is_prime(prime_factors[i]) == False:
csong@1 67 del prime_factors[i]
csong@1 68
csong@1 69 return prime_factors
csong@1 70
csong@1 71 # The min_timeSpan function searches for the shortest possible time-span representation for a sequence.
csong@1 72 def get_min_timeSpan(seq):
csong@1 73 min_ts = [1]
csong@1 74 for d in find_divisor(len(seq)):
csong@1 75 segments = subdivide(seq,d)
csong@1 76 if len(segments)!=0:
csong@1 77 del min_ts[:]
csong@1 78 for s in segments:
csong@1 79 min_ts.append(s[0])
csong@1 80 if sum(min_ts) == sum(seq):
csong@1 81 break
csong@1 82 return min_ts
csong@1 83
csong@1 84 # get_note_indices returns all the indices of all the notes in this sequence
csong@1 85 def get_note_indices(seq):
csong@1 86 note_indices = []
csong@1 87
csong@1 88 for index in range(len(seq)):
csong@1 89 if seq[index] != 0:
csong@1 90 note_indices.append(index)
csong@1 91
csong@1 92 return note_indices
csong@1 93
csong@1 94 # The get_H returns a sequence of metrical weight for a certain metrical level (horizontal),
csong@1 95 # given the sequence of metrical weights in a hierarchy (vertical) and a sequence of subdivisions.
csong@1 96 def get_H(weight_seq,subdivision_seq, level):
csong@1 97 H = []
csong@1 98 #print len(weight_seq), len(subdivision_seq), level
csong@1 99 if (level <= len(subdivision_seq)-1) & (level <= len(weight_seq)-1):
csong@1 100 if level == 0:
csong@1 101 H = repeat([weight_seq[0]],subdivision_seq[0])
csong@1 102 else:
csong@1 103 H_pre = get_H(weight_seq,subdivision_seq,level-1)
csong@1 104 for h in H_pre:
csong@1 105 H = concatenate(H, concatenate([h], repeat([weight_seq[level]],subdivision_seq[level]-1)))
csong@1 106 else:
csong@1 107 print 'Error: a subdivision factor or metrical weight is not defined for the request metrical level.'
csong@1 108 return H
csong@1 109
csong@1 110 # The get_subdivision_seq function returns the subdivision sequence of several common time-signatures defined by GTTM,
csong@1 111 # or ask for the top three level of subdivision_seq manually set by the user.
csong@1 112 def get_subdivision_seq(timesig, L_max):
csong@1 113 subdivision_seq = []
csong@1 114
csong@1 115 if timesig == '2/4' or timesig == '4/4':
csong@1 116 subdivision_seq = [1,2,2]
csong@1 117 elif timesig == '3/4':
csong@1 118 subdivision_seq = [1,3,2]
csong@1 119 elif timesig == '6/8':
csong@1 120 subdivision_seq = [1,2,3]
csong@1 121 elif timesig == '9/8':
csong@1 122 subdivision_seq = [1,3,3]
csong@1 123 elif timesig == '12/8':
csong@1 124 subdivision_seq = [1,4,3]
csong@1 125 elif timesig == '5/4':
csong@1 126 subdivision_seq = [1,5,2]
csong@1 127 elif timesig == '7/4':
csong@1 128 subdivision_seq = [1,7,2]
csong@1 129 elif timesig == '11/4':
csong@1 130 subdivision_seq = [1,11,2]
csong@1 131 else:
csong@1 132 print 'Undefined time-signature. Please indicate subdivision sequence for this requested time-signature, e.g. [1,2,2] for 4/4 meter.'
csong@1 133 for i in range(3):
csong@1 134 s = int(input('Enter the subdivision factor at metrical level '+str(i)+':'))
csong@1 135 subdivision_seq.append(s)
csong@1 136
csong@1 137 if L_max > 2:
csong@1 138 subdivision_seq = subdivision_seq + [2]*(L_max-2)
csong@1 139 else:
csong@1 140 subdivision_seq = subdivision_seq[0:L_max+1]
csong@1 141
csong@1 142 return subdivision_seq
csong@1 143
csong@1 144 # The split_by_bar function seperates the score representation of rhythm by bar lines,
csong@1 145 # resulting in a list representingbar-by-bar rhythm sequence,
csong@1 146 # e.g. rhythm = ['|',[ts1,td1,v1], [ts2,td2,v2], '|',[ts3,td3,v3],'|'...]
csong@1 147 # rhythm_bybar = [ [ [ts1,td1,v1], [ts2,td2,v2] ], [ [ts3,td3,v3] ], [...]]
csong@1 148 # def split_by_bar(rhythm):
csong@1 149 # rhythm_bybar = []
csong@1 150 # bar_index = []
csong@1 151 # for index in range(len(rhythm)):
csong@1 152 # if rhythm[index] == '|':
csong@1 153
csong@1 154 # return rhythm_bybar
csong@1 155
csong@1 156 # def yseq_to_vseq(yseq):
csong@1 157 # vseq = []
csong@1 158
csong@1 159 # return vseq
csong@1 160
csong@1 161
csong@1 162 # # testing
csong@1 163 # print find_prime_factors(10)