annotate Syncopation models/basic_functions.py @ 26:d9d22e6f396d

fixed SG!
author csong <csong@eecs.qmul.ac.uk>
date Sun, 12 Apr 2015 15:53:58 +0100
parents df1e7c378ee0
children 5de1cb45c145
rev   line source
csong@2 1 # This python file is a collection of basic functions that are used in the syncopation models.
csong@2 2
csong@2 3 import math
csong@2 4
csong@2 5 # The concatenation function is used to concatenate two sequences.
csong@2 6 def concatenate(seq1,seq2):
csong@2 7 return seq1+seq2
csong@2 8
csong@2 9 # The repetition function is to concatenate a sequence to itself for 'times' number of times.
csong@2 10 def repeat(seq,times):
csong@2 11 new_seq = list(seq)
csong@2 12 if times >= 1:
csong@2 13 for i in range(times-1):
csong@2 14 new_seq = concatenate(new_seq,seq)
csong@2 15 else:
csong@2 16 #print 'Error: repetition times needs to be no less than 1.'
csong@2 17 new_seq = []
csong@2 18 return new_seq
csong@2 19
csong@2 20 # The subdivision function is to equally subdivide a sequence into 'divisor' number of segments.
csong@2 21 def subdivide(seq,divisor):
csong@2 22 subSeq = []
csong@2 23 if len(seq) % divisor != 0:
csong@2 24 print 'Error: rhythmic sequence cannot be equally subdivided.'
csong@2 25 else:
csong@2 26 n = len(seq) / divisor
csong@2 27 start , end = 0, n
csong@2 28 for i in range(divisor):
csong@2 29 subSeq.append(seq[start : end])
csong@2 30 start = end
csong@2 31 end = end + n
csong@2 32 return subSeq
csong@2 33
csong@2 34
csong@2 35 # The ceiling function is to round each number inside a sequence up to its nearest integer.
csong@2 36 def ceiling(seq):
csong@2 37 seq_ceil = []
csong@2 38 for s in seq:
csong@2 39 seq_ceil.append(int(math.ceil(s)))
csong@2 40 return seq_ceil
csong@2 41
csong@2 42 # The find_divisor function returns a list of all possible divisors for a length of sequence.
csong@2 43 def find_divisor(number):
csong@2 44 divisors = [1]
csong@2 45 for i in range(2,number+1):
csong@2 46 if number%i ==0:
csong@2 47 divisors.append(i)
csong@2 48 return divisors
csong@2 49
csong@2 50 # The find_divisor function returns a list of all possible divisors for a length of sequence.
csong@2 51 def find_prime_factors(number):
csong@20 52 primeFactors = find_divisor(number)
csong@2 53
csong@20 54 # remove 1 because 1 is not prime number
csong@20 55 del primeFactors[0]
csong@2 56
csong@20 57 # reversely traverse all the divisors list and once find a non-prime then delete
csong@20 58 for i in range(len(primeFactors)-1,0,-1):
csong@20 59 # print primeFactors[i], is_prime(primeFactors[i])
csong@20 60 if not is_prime(primeFactors[i]):
csong@20 61 del primeFactors[i]
csong@2 62
csong@20 63 return primeFactors
csong@20 64
csong@20 65 def is_prime(number):
csong@20 66 isPrime = True
csong@20 67 # 0 or 1 is not prime numbers
csong@20 68 if number < 2:
csong@20 69 isPrime = False
csong@20 70 # 2 is the only even prime number
csong@20 71 elif number == 2:
csong@20 72 pass
csong@20 73 # all the other even numbers are non-prime
csong@20 74 elif number % 2 == 0:
csong@20 75 isPrime = False
csong@20 76 else:
csong@20 77 for odd in range(3, int(math.sqrt(number) + 1), 2):
csong@20 78 if number % odd == 0:
csong@20 79 isPrime = False
csong@20 80 return isPrime
csong@2 81
csong@26 82 # upsample a velocity sequence to certain length, e.g. [1,1] to [1,0,0,0,1,0,0,0]
csong@26 83 def upsample_velocity_sequence(velocitySequence, length):
csong@26 84 upsampledVelocitySequence = [0]*length
csong@26 85 if length%len(velocitySequence) != 0:
csong@26 86 print 'Error: the velocity sequence can only be upsampled to the interger times of its length.'
csong@26 87 else:
csong@26 88 scalingFactor = length/len(velocitySequence)
csong@26 89 for index in range(len(velocitySequence)):
csong@26 90 upsampledVelocitySequence[index*scalingFactor] = velocitySequence[index]
csong@26 91 return upsampledVelocitySequence
csong@26 92
csong@26 93
csong@22 94 # convert a velocity sequence to its minimum time-span representation
csong@23 95 def velocity_sequence_to_min_timespan(velocitySequence):
csong@22 96 minTimeSpanVelocitySeq = [1]
csong@22 97 for divisors in find_divisor(len(velocitySequence)):
csong@22 98 segments = subdivide(velocitySequence,divisors)
csong@2 99 if len(segments)!=0:
csong@23 100 del minTimeSpanVelocitySeq[:]
csong@2 101 for s in segments:
csong@22 102 minTimeSpanVelocitySeq.append(s[0])
csong@22 103 if sum(minTimeSpanVelocitySeq) == sum(velocitySequence):
csong@2 104 break
csong@22 105 return minTimeSpanVelocitySeq
csong@2 106
csong@22 107 # convert a note sequence to its minimum time-span representation
csong@23 108 def note_sequence_to_min_timespan(noteSequence):
csong@23 109 from music_objects import note_sequence_to_velocity_sequence
csong@23 110 timeSpanTicks = len(note_sequence_to_velocity_sequence(noteSequence))
csong@23 111 # print timeSpanTicks
csong@23 112
csong@23 113 barBinaryArray = [0]*(timeSpanTicks+1)
csong@22 114 for note in noteSequence:
csong@22 115 # mark note_on event (i.e. startTime) and note_off event (i.e. endTime = startTime + duration) as 1 in the barBinaryArray
csong@23 116 barBinaryArray[note.startTime] = 1
csong@23 117 barBinaryArray[note.startTime + note.duration] = 1
csong@22 118
csong@22 119 # convert the barBinaryArray to its minimum time-span representation
csong@23 120 minBarBinaryArray = velocity_sequence_to_min_timetpan(barBinaryArray[:-1])
csong@23 121 print barBinaryArray
csong@23 122 print minBarBinaryArray
csong@22 123 delta_t = len(barBinaryArray)/len(minBarBinaryArray)
csong@22 124
csong@22 125 # scale the startTime and duration of each note by delta_t
csong@22 126 for note in noteSequence:
csong@23 127 note.startTime = note.startTime/delta_t
csong@23 128 note.duration = note.duration/delta_t
csong@22 129
csong@22 130 return noteSequence
csong@22 131
csong@22 132
csong@22 133 # get_note_indices returns all the indices of all the notes in this velocity_sequence
csong@22 134 def get_note_indices(velocitySequence):
csong@20 135 noteIndices = []
csong@2 136
csong@22 137 for index in range(len(velocitySequence)):
csong@22 138 if velocitySequence[index] != 0:
csong@20 139 noteIndices.append(index)
csong@2 140
csong@20 141 return noteIndices
csong@2 142
csong@22 143
csong@2 144 # The get_H returns a sequence of metrical weight for a certain metrical level (horizontal),
csong@2 145 # given the sequence of metrical weights in a hierarchy (vertical) and a sequence of subdivisions.
csong@19 146 def get_H(weightSequence,subdivisionSequence, level):
csong@2 147 H = []
csong@2 148 #print len(weight_seq), len(subdivision_seq), level
csong@19 149 if (level <= len(subdivisionSequence)-1) and (level <= len(weightSequence)-1):
csong@2 150 if level == 0:
csong@19 151 H = repeat([weightSequence[0]],subdivisionSequence[0])
csong@2 152 else:
csong@19 153 H_pre = get_H(weightSequence,subdivisionSequence,level-1)
csong@2 154 for h in H_pre:
csong@19 155 H = concatenate(H, concatenate([h], repeat([weightSequence[level]],subdivisionSequence[level]-1)))
csong@2 156 else:
csong@2 157 print 'Error: a subdivision factor or metrical weight is not defined for the request metrical level.'
csong@2 158 return H
csong@2 159
csong@22 160
csong@22 161 def calculate_bar_ticks(numerator, denominator, ticksPerQuarter):
csong@21 162 return (numerator * ticksPerQuarter *4) / denominator
csong@21 163
csong@22 164
csong@22 165 def get_rhythm_category(velocitySequence, subdivisionSequence):
csong@22 166 '''
csong@22 167 The get_rhythm_category function is used to detect rhythm category: monorhythm or polyrhythm.
csong@22 168 For monorhythms, all prime factors of the length of minimum time-span representation of this sequence are
csong@22 169 elements of its subdivision_seq, otherwise it is polyrhythm;
csong@22 170 e.g. prime_factors of polyrhythm 100100101010 in 4/4 is [2,3] but subdivision_seq = [1,2,2] for 4/4
csong@22 171 '''
csong@22 172 rhythmCategory = 'mono'
csong@26 173 for f in find_prime_factors(len(velocity_sequence_to_min_timespan(velocitySequence))):
csong@22 174 if not (f in subdivisionSequence):
csong@22 175 rhythmCategory = 'poly'
csong@22 176 break
csong@22 177 return rhythmCategory
csong@22 178
csong@22 179
csong@22 180 def string_to_sequence(inputString):
csong@22 181 return map(int, inputString.split(','))
csong@22 182
csong@19 183 # # The get_subdivision_seq function returns the subdivision sequence of several common time-signatures defined by GTTM,
csong@19 184 # # or ask for the top three level of subdivision_seq manually set by the user.
csong@19 185 # def get_subdivision_seq(timesig, L_max):
csong@19 186 # subdivision_seq = []
csong@2 187
csong@19 188 # if timesig == '2/4' or timesig == '4/4':
csong@19 189 # subdivision_seq = [1,2,2]
csong@19 190 # elif timesig == '3/4' or timesig == '3/8':
csong@19 191 # subdivision_seq = [1,3,2]
csong@19 192 # elif timesig == '6/8':
csong@19 193 # subdivision_seq = [1,2,3]
csong@19 194 # elif timesig == '9/8':
csong@19 195 # subdivision_seq = [1,3,3]
csong@19 196 # elif timesig == '12/8':
csong@19 197 # subdivision_seq = [1,4,3]
csong@19 198 # elif timesig == '5/4' or timesig == '5/8':
csong@19 199 # subdivision_seq = [1,5,2]
csong@19 200 # elif timesig == '7/4' or timesig == '7/8':
csong@19 201 # subdivision_seq = [1,7,2]
csong@19 202 # elif timesig == '11/4' or timesig == '11/8':
csong@19 203 # subdivision_seq = [1,11,2]
csong@19 204 # else:
csong@19 205 # print 'Time-signature',timesig,'is undefined. Please indicate subdivision sequence for this requested time-signature, e.g. [1,2,2] for 4/4 meter.'
csong@19 206 # for i in range(3):
csong@19 207 # s = int(input('Enter the subdivision factor at metrical level '+str(i)+':'))
csong@19 208 # subdivision_seq.append(s)
csong@2 209
csong@19 210 # if L_max > 2:
csong@19 211 # subdivision_seq = subdivision_seq + [2]*(L_max-2)
csong@19 212 # else:
csong@19 213 # subdivision_seq = subdivision_seq[0:L_max+1]
csong@2 214
csong@19 215 # return subdivision_seq
csong@2 216
csong@9 217
csong@2 218 # The split_by_bar function seperates the score representation of rhythm by bar lines,
csong@2 219 # resulting in a list representingbar-by-bar rhythm sequence,
csong@2 220 # e.g. rhythm = ['|',[ts1,td1,v1], [ts2,td2,v2], '|',[ts3,td3,v3],'|'...]
csong@2 221 # rhythm_bybar = [ [ [ts1,td1,v1], [ts2,td2,v2] ], [ [ts3,td3,v3] ], [...]]
csong@2 222 # def split_by_bar(rhythm):
csong@2 223 # rhythm_bybar = []
csong@2 224 # bar_index = []
csong@2 225 # for index in range(len(rhythm)):
csong@2 226 # if rhythm[index] == '|':
csong@2 227
csong@2 228 # return rhythm_bybar
csong@2 229
csong@2 230 # def yseq_to_vseq(yseq):
csong@2 231 # vseq = []
csong@2 232
csong@2 233 # return vseq
csong@2 234
csong@2 235
csong@2 236 # # testing
csong@20 237 # print find_prime_factors(10)
csong@20 238 # print find_prime_factors(2)
csong@20 239 # print find_prime_factors(12)
csong@20 240
csong@20 241
csong@20 242 # print is_prime(1) # False
csong@20 243 # print is_prime(2) # True
csong@20 244 # print is_prime(3) # True
csong@20 245 # print is_prime(29) # True
csong@20 246 # print is_prime(345) # False
csong@20 247 # print is_prime(999979) # True
csong@20 248 # print is_prime(999981) # False