Mercurial > hg > syncopation-dataset
changeset 20:b959c2acb927
Refactored all models except for KTH, all past testing except for SG.
author | csong <csong@eecs.qmul.ac.uk> |
---|---|
date | Tue, 07 Apr 2015 19:05:07 +0100 |
parents | 9030967a05f8 |
children | b6daddeefda9 |
files | Syncopation models/KTH.py Syncopation models/LHL.py Syncopation models/PRS.py Syncopation models/SG.py Syncopation models/TMC.py Syncopation models/TOB.py Syncopation models/TimeSignature.pkl Syncopation models/WNBD.py Syncopation models/basic_functions.py Syncopation models/music_objects.py Syncopation models/parameter_setter.py Syncopation models/rhythm_parser.py |
diffstat | 12 files changed, 301 insertions(+), 196 deletions(-) [+] |
line wrap: on
line diff
--- a/Syncopation models/KTH.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/KTH.py Tue Apr 07 19:05:07 2015 +0100 @@ -5,10 +5,10 @@ ''' ## Problems! Note indices, post bar -from BasicFuncs import get_min_timeSpan, get_note_indices, repeat +from basic_functions import get_min_timeSpan, get_note_indices, repeat # To find the nearest power of 2 equal to or less than the given number -def roundDownPower2(number): +def round_down_power_2(number): i = 0 if number > 0: while pow(2,i) > number or number >= pow(2,i+1): @@ -20,39 +20,40 @@ return power2 # To find the nearest power of 2 equal to or more than the given number -def roundUpPower2(number): +def round_up_power_2(number): i = 0 while pow(2,i) < number: i = i + 1 return pow(2,i) # To examine whether start_time is 'off-beat' -def start(start_time, c_n): +def start(startTime, c_n): s = 0 - if start_time % c_n != 0: + if startTime % c_n != 0: s = 2 return s # To examine whether end_time is 'off-beat' -def end(end_time, c_n): +def end(endTime, c_n): s = 0 - if end_time % c_n != 0: + if endTime % c_n != 0: s = 1 return s # To calculate syncopation value of the sequence in the given time-signature. -def get_syncopation(seq, timesig, postbar_seq): +#def get_syncopation(seq, timesig, postbar_seq): +def get_syncopation(bar, parameter = None): syncopation = 0 numerator = int(timesig.split("/")[0]) - if numerator == roundDownPower2(numerator): # if is a binary time-signature + if numerator == round_down_power_2(numerator): # if is a binary time-signature # converting to minimum time-span format seq = get_min_timeSpan(seq) if postbar_seq != None: postbar_seq = get_min_timeSpan(postbar_seq) # sf is a stretching factor matching rhythm sequence and meter, as Keith defines the note duration as a multiple of 1/(2^d) beats where d is number of metrical level - sf = roundUpPower2(len(seq)) + sf = round_up_power_2(len(seq)) # retrieve all the indices of all the notes in this sequence note_indices = get_note_indices(seq) @@ -71,7 +72,7 @@ end_time = note_indices[i+1]*sf/float(len(seq)) duration = end_time - start_time - c_n = roundDownPower2(duration) + c_n = round_down_power_2(duration) syncopation = syncopation + start(start_time,c_n) + end(end_time,c_n) else: print 'Error: KTH model can only deal with binary time-signature, e.g. 2/4 and 4/4. '
--- a/Syncopation models/LHL.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/LHL.py Tue Apr 07 19:05:07 2015 +0100 @@ -30,15 +30,13 @@ for a in range(len(subBinarySequences)): recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1) +#!!!! needs fixing def are_parameters_valid(parameters): - areValid = False - if 'Lmax' not in parameters : + areValid = True +# if 'Lmax' not in parameters : def get_syncopation(bar, parameters = None): - ''' - The get_syncopation function calculates syncopation value . - ''' -#def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category): + del terminalNodes[:] syncopation = None binarySequence = bar.get_binary_sequence() @@ -50,7 +48,7 @@ # If the parameters are not given, use the default settings if parameters == None: Lmax = 5 - weightSequence = range(0,-Lmax,-1) + weightSequence = range(0,-Lmax,-1) # i.e. [0,-1,-2,-3,-4] else: if are_parameters_valid(parameters): Lmax = parameters['Lmax'] @@ -65,7 +63,7 @@ recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) # Only keep the last note-type node - while terminalNodes[-1].node_type != 'N': + while terminalNodes[-1].nodeType != 'N': del terminalNodes[-1] del terminalNodes[0:-1] @@ -73,15 +71,15 @@ recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) # for t in terminalNodes: - # print '<', t.node_type, t.metrical_weight, '>' + # print '<', t.nodeType, t.metricalWeight, '>' # Search for the NR pairs that contribute to syncopation, # then add the weight-difference to the NRpairSyncopation list NRpairSyncopation = [] for i in range(len(terminalNodes)-1,0,-1): - if terminalNodes[i].node_type == 'R': + if terminalNodes[i].nodeType == 'R': for j in range(i-1, -1, -1): - if (terminalNodes[j].node_type == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight): + if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight): NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight) break #print NRpairSyncopation
--- a/Syncopation models/PRS.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/PRS.py Tue Apr 07 19:05:07 2015 +0100 @@ -14,9 +14,9 @@ cost = 1 elif sequence[0] == 1 and sequence[-1] == 0: # run1 prototype cost = 2 - elif sequence[0] == 1 and (nextSequence == None or nenextSequencext_seq[0] == 0): # run2 prototype + elif sequence[0] == 1 and (nextSequence == None or nextSequence[0] == 0): # run2 prototype cost = 2 - elif sequence[0] == 1 and sequence[-1] == 1 and nextSequence != None and nextSequence[0] == 1: # upbeat prototype + elif sequence[-1] == 1 and nextSequence != None and nextSequence[0] == 1: # upbeat prototype cost = 3 elif sequence[0] == 0: # syncopated prototype cost = 5 @@ -25,44 +25,47 @@ # This function calculates the syncopation value (cost) for the sequence with the postbar_seq for a certain level. def syncopation_perlevel(subSequences): + print 'subSequences', subSequences total = 0 for l in range(len(subSequences)-1): + print 'cost', get_cost(subSequences[l], subSequences[l+1]) total = total + get_cost(subSequences[l], subSequences[l+1]) + print 'total this level', total normalised = float(total)/(len(subSequences)-1) return normalised -#def get_syncopation(seq,subdivision_seq, postbar_seq, rhythm_category): def get_syncopation(bar, parameters = None): - ''' - The get_syncopation function calculates the overall syncopation value for a bar of sequence. - ''' syncopation = None binarySequence = bar.get_binary_sequence() subdivisionSequence = bar.get_subdivision_sequence() + # PRS does not handle polyrhythms if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': print 'Warning: PRS model detects polyrhythms so returning None.' else: syncopation = 0 + # retrieve the binary sequence in the next bar if bar.get_next_bar() != None: nextbarBinarySequence = bar.get_next_bar().get_binary_sequence() else: nextbarBinarySequence = None - # the initial number of sub-sequences at a certain metrical level + # numberOfSubSeqs is the number of sub-sequences at a certain metrical level, initialised to be 1 (at the bar level) numberOfSubSeqs = 1 for subdivisor in subdivisionSequence: - # the number of sub-sequence at the current level is product of all the subdivisors up to the current level + # numberOfSubSeqs is product of all the subdivisors up to the current level numberOfSubSeqs = numberOfSubSeqs * subdivisor + # recursion stops when the length of sub-sequence is less than 2 if len(binarySequence)/numberOfSubSeqs >= 2: # generate sub-sequences and append the next bar sequence subSequences = subdivide(ceiling(binarySequence), numberOfSubSeqs) subSequences.append(nextbarBinarySequence) # adding syncopation at each metrical level to the total syncopation + #print 'per level', syncopation_perlevel(subSequences) syncopation += syncopation_perlevel(subSequences) else: break
--- a/Syncopation models/SG.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/SG.py Tue Apr 07 19:05:07 2015 +0100 @@ -4,73 +4,85 @@ ''' -from BasicFuncs import get_H, get_min_timeSpan +from basic_functions import get_H, get_min_timeSpan, get_rhythm_category +from TMC import find_L -def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category): +#def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category): +def get_syncopation(bar, parameters = None): syncopation = None - if rhythm_category == 'poly': - print 'Error: SG model cannot deal with polyrhythms.' + velocitySequence = bar.get_velocity_sequence() + subdivisionSequence = bar.get_subdivision_sequence() + + if get_rhythm_category(velocitySequence, subdivisionSequence) == 'poly': + print 'Warning: SG model detects polyrhythms so returning None.' else: - - seq = get_min_timeSpan(seq) # converting to the minimum time-span format - - # checking whether the given L_max is enough to analyse the given sequence, if not, request a bigger L_max - new_L_max = True - matching_level = L_max - while matching_level >= 0: - if len(get_H(weight_seq,subdivision_seq, matching_level)) == len(seq): - new_L_max = False - break + velocitySequence = get_min_timeSpan(velocitySequence) # converting to the minimum time-span format + + # If the parameters are not given, use the default settings + if parameters == None: + Lmax = 5 + weightSequence = range(Lmax+1) # i.e. [0,1,2,3,4,5] + else: + if are_parameters_valid(parameters): + Lmax = parameters['Lmax'] + weightSequence = parameters['W'] else: - matching_level = matching_level - 1 + pass + #raise InvalidParameterError - if new_L_max == True: - print 'Error: needs a bigger L_max (i.e. the lowest metrical level) to match the given rhythm sequence.' - - else: + L = find_L(velocitySequence, Lmax, weightSequence, subdivisionSequence) + print 'L', L + if L != None: syncopation = 0 # generate the metrical weights of the lowest level - H = get_H(weight_seq,subdivision_seq, matching_level) + H = get_H(weightSequence,subdivisionSequence, L) + print 'H', H - # The aveDif_neighbours function calculates the (weighted) average of the difference between the note at a certain index and its neighbours in a certain metrical level - def aveDif_neighbours(index, level): + # The ave_dif_neighbours function calculates the (weighted) average of the difference between the note at a certain index and its neighbours in a certain metrical level + def ave_dif_neighbours(index, level): + averages = [] - parameter_garma = 0.8 + parameterGarma = 0.8 # The findPre function is to calculate the index of the previous neighbour at a certain metrical level. - def findPre(index, level): - pre_index = (index - 1)%len(H) - while(H[pre_index] > level): - pre_index = (pre_index - 1)%len(H) - return pre_index + def find_pre(index, level): + preIndex = (index - 1)%len(H) # using % is to restrict the index varies within range(0, len(H)) + while(H[preIndex] > level): + preIndex = (preIndex - 1)%len(H) + print 'preIndex', preIndex + return preIndex # The findPost function is to calculate the index of the next neighbour at a certain metrical level. - def findPost(index, level): - post_index = (index + 1)%len(H) - while(H[post_index] > level): - post_index = (post_index + 1)%len(H) - return post_index + def find_post(index, level): + postIndex = (index + 1)%len(H) + while(H[postIndex] > level): + postIndex = (postIndex + 1)%len(H) + print 'postIndex', postIndex + return postIndex # The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence def dif(index1,index2): - parameter_beta = 0.5 - dif_v = seq[index1]-seq[index2] + parameterBeta = 0.5 + dif_v = velocitySequence[index1]-velocitySequence[index2] dif_h = abs(H[index1]-H[index2]) - dif = dif_v*(parameter_beta*dif_h/4+1-parameter_beta) + dif = dif_v*(parameterBeta*dif_h/4+1-parameterBeta) + print 'dif', dif return dif # From the highest to the lowest metrical levels where the current note resides, calculate the difference between the note and its neighbours at that level for l in range(level, max(H)+1): - ave = ( parameter_garma*dif(index,findPre(index,l))+dif(index,findPost(index,l)) )/(1+parameter_garma) + ave = (parameterGarma*dif(index,find_pre(index,l))+dif(index,find_post(index,l)) )/(1+parameterGarma) averages.append(ave) + print 'averages', averages return averages # Calculate the syncopation value for each note - for index in range(len(seq)): - if seq[index] != 0: # Onset detected - h = H[index] - potential = 1 - pow(0.5,h) # Syncopation potential according to its metrical level, which is equal to the metrical weight - level = h # Metrical weight happens to be equal to its metrical level - syncopation += min(aveDif_neighbours(index, h))*potential + for index in range(len(velocitySequence)): + if velocitySequence[index] != 0: # Onset detected + h = H[index] + # Syncopation potential according to its metrical level, which is equal to the metrical weight + potential = 1 - pow(0.5,h) + level = h # Metrical weight is equal to its metrical level + syncopation += min(ave_dif_neighbours(index, level))*potential return syncopation
--- a/Syncopation models/TMC.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/TMC.py Tue Apr 07 19:05:07 2015 +0100 @@ -4,52 +4,81 @@ ''' -from BasicFuncs import get_H, ceiling, get_min_timeSpan +from basic_functions import get_H, ceiling, get_min_timeSpan, get_rhythm_category # The get_metricity function calculates the metricity for a binary sequence with given sequence of metrical weights in a certain metrical level. -def get_metricity(seq, H): +def get_metricity(binarySequence, H): metricity = 0 - for m in range(len(seq)): - metricity = metricity + seq[m]*H[m] + for m in range(len(binarySequence)): + metricity = metricity + binarySequence[m]*H[m] return metricity # The get_max_metricity function calculates the maximum metricity for the same number of notes in a binary sequence. -def get_max_metricity(seq, H): - max_metricity = 0 +def get_max_metricity(binarySequence, H): + maxMetricity = 0 H.sort(reverse=True) # Sort the metrical weight sequence from large to small - for i in range(sum(seq)): - max_metricity = max_metricity+H[i] - return max_metricity + for i in range(sum(binarySequence)): + maxMetricity = maxMetricity+H[i] + return maxMetricity + +# find the metrical level L that contains the same number of metrical positions as the length of the binary sequence +# if the given Lmax is not big enough to analyse the given sequence, request a bigger Lmax +def find_L(rhythmSequence, Lmax, weightSequence, subdivisionSequence): + L = Lmax + + # initially assuming the Lmax is not big enough + needBiggerLmax = True + + # from the lowest metrical level (Lmax) to the highest, find the matching metrical level that + # has the same length as the length of binary sequence + while L >= 0: + if len(get_H(weightSequence,subdivisionSequence, L)) == len(rhythmSequence): + needBiggerLmax = False + break + else: + L = L - 1 + + # if need a bigger Lmax, print error message and return None; otherwise return the matching metrical level L + if needBiggerLmax: + print 'Error: needs a bigger L_max (i.e. the lowest metrical level) to match the given rhythm sequence.' + L = None + + return L # The get_syncopation function calculates the syncopation value of the given sequence for TMC model. -def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category): +#def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category): +def get_syncopation(bar, parameters = None): syncopation = None - if rhythm_category == 'poly': - print 'Error: TMC model cannot deal with polyrhythms.' + binarySequence = bar.get_binary_sequence() + subdivisionSequence = bar.get_subdivision_sequence() + + if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': + print 'Warning: TMC model detects polyrhythms so returning None.' else: - seq = get_min_timeSpan(seq) # converting to the minimum time-span format + binarySequence = get_min_timeSpan(binarySequence) # converting to the minimum time-span format - # checking whether the given L_max is enough to analyse the given sequence, if not, request a bigger L_max - new_L_max = True - matching_level = L_max - while matching_level >= 0: - if len(get_H(weight_seq,subdivision_seq, matching_level)) == len(seq): - new_L_max = False - break + # If the parameters are not given, use the default settings + if parameters == None: + Lmax = 5 + weightSequence = range(Lmax+1,0,-1) # i.e. [6,5,4,3,2,1] + else: + if are_parameters_valid(parameters): + Lmax = parameters['Lmax'] + weightSequence = parameters['W'] else: - matching_level = matching_level - 1 + pass + #raise InvalidParameterError - if new_L_max == True: - print 'Error: needs a bigger L_max (i.e. the lowest metrical level) to match the given rhythm sequence.' - - else: - # generate the metrical weights of the lowest level, - # using the last matching_level number of elements in the weight_seq list, to make sure the last element is 1 - H = get_H (weight_seq[-(matching_level+1):], subdivision_seq, matching_level) + L = find_L(binarySequence, Lmax, weightSequence, subdivisionSequence) + if L != None: + #? generate the metrical weights of the lowest level, + #? using the last matching_level number of elements in the weightSequence, to make sure the last element is 1 + H = get_H (weightSequence[-(L+1):], subdivisionSequence, L) - metricity = get_metricity(ceiling(seq), H) # converting to binary sequence then calculate metricity - max_metricity = get_max_metricity(ceiling(seq), H) + metricity = get_metricity(binarySequence, H) # converting to binary sequence then calculate metricity + maxMetricity = get_max_metricity(binarySequence, H) - syncopation = max_metricity - metricity + syncopation = maxMetricity - metricity + return syncopation
--- a/Syncopation models/TOB.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/TOB.py Tue Apr 07 19:05:07 2015 +0100 @@ -4,21 +4,32 @@ ''' -from BasicFuncs import ceiling, find_divisor, get_min_timeSpan +from basic_functions import ceiling, find_divisor, is_prime, get_min_timeSpan -# This function calculates the syncopation value for TOB model. -def get_syncopation(seq): +def get_syncopation(bar, parameter = None): + binarySequence = bar.get_binary_sequence() + sequenceLength = len(binarySequence) + syncopation = 0 - bseq_ts = get_min_timeSpan(ceiling(seq)) # converting to binary and mininum time-span sequence - divisors = find_divisor(len(bseq_ts)) # find all the divisors other than 1 and the length of this sequence - del divisors[0] - del divisors[-1] - offbeatness = [1]*len(bseq_ts) - for index in range(len(bseq_ts)): - for d in divisors: - if index % d == 0: - offbeatness[index] = 0 - break - syncopation += bseq_ts[index]*offbeatness[index] + # if the length of b_sequence is 1 or a prime number, syncopation is 0; + # otherwise the syncopation is calculated by adding up the number of off-beat notes + if not ( (sequenceLength == 1) or (is_prime(sequenceLength)) ): + # find all the divisors other than 1 and the length of this sequence + divisors = find_divisor(sequenceLength) + del divisors[0] + del divisors[-1] + + # the on-beat/off-beat positions are the ones that can/cannot be subdivided by the sequenceLength; + # the on-beat positions are set to be 0, off-beat positions are set to be 1 + offbeatness = [1]*sequenceLength + for index in range(sequenceLength): + for d in divisors: + if index % d == 0: + offbeatness[index] = 0 + break + #print 'offbeatness', offbeatness + # syncopation is the sum of the hadamard-product of the rhythm binary-sequence and the off-beatness + syncopation += binarySequence[index]*offbeatness[index] + return syncopation
--- a/Syncopation models/TimeSignature.pkl Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/TimeSignature.pkl Tue Apr 07 19:05:07 2015 +0100 @@ -8,6 +8,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'3/2' p5 @@ -18,6 +19,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'3/4' p8 @@ -28,6 +30,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'12/8' p11 @@ -38,6 +41,7 @@ aI2 aI3 aI2 +aI2 aaI2 asS'3/8' p14 @@ -48,6 +52,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'2/2' p17 @@ -58,6 +63,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'6/8' p20 @@ -68,6 +74,7 @@ aI3 aI2 aI2 +aI2 aaI1 asS'5/4' p23 @@ -78,6 +85,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'4/2' p26 @@ -88,6 +96,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'7/4' p29 @@ -98,6 +107,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'5/8' p32 @@ -108,6 +118,7 @@ aI2 aI2 aI2 +aI2 aaI1 asS'4/4' p35 @@ -118,6 +129,7 @@ aI2 aI2 aI2 +aI2 aaI2 asS'9/8' p38 @@ -128,5 +140,6 @@ aI3 aI2 aI2 +aI2 aaI1 as. \ No newline at end of file
--- a/Syncopation models/WNBD.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/WNBD.py Tue Apr 07 19:05:07 2015 +0100 @@ -3,7 +3,7 @@ Institution: Centre for Digital Music, Queen Mary University of London ''' -from BasicFuncs import repeat, get_note_indices +from basic_functions import repeat, get_note_indices # To find the product of multiple numbers def cumu_multiply(numbers): @@ -12,56 +12,72 @@ product = product*n return product -def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq): +#def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq): +def get_syncopation(bar, parameters = None): syncopation = None - num_beats = cumu_multiply(subdivision_seq[0:strong_beat_level+1]) # num_beats is the number of strong beats + binarySequence = bar.get_binary_sequence() + sequenceLength = len(binarySequence) + subdivisionSequence = bar.get_subdivision_sequence() + strongBeatLevel = bar.get_beat_level() + nextbarBinarySequence = None + + if bar.get_next_bar() != None: + nextbarBinarySequence = bar.get_next_bar().get_binary_sequence() + + numberOfBeats = cumu_multiply(subdivisionSequence[0:strongBeatLevel+1]) # numberOfBeats is the number of strong beats - if len(seq)%num_beats != 0: - print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision_seq.' + if sequenceLength % numberOfBeats != 0: + print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision sequence.' else: # Find the indices of all the strong-beats - beat_indices = [] - beat_interval = len(seq)/num_beats - for i in range(num_beats+1): - beat_indices.append(i*beat_interval) - if postbar_seq != None: # if there is a postbar_seq, add another two beats index for later calculation - beat_indices += [len(seq)+beat_interval, len(seq)+ 2* beat_interval] + beatIndices = [] + beatInterval = sequenceLength / numberOfBeats + for i in range(numberOfBeats+1): + beatIndices.append(i*beatInterval) + if nextbarBinarySequence != None: # if there is a postbar_seq, add another two beats index for later calculation + beatIndices += [sequenceLength+beatInterval, sequenceLength+ 2* beatInterval] - note_indices = get_note_indices(seq) # all the notes + noteIndices = get_note_indices(binarySequence) # all the notes # Calculate the WNBD measure for each note - def measure_pernote(note_index, nextnote_index): + def measure_pernote(noteIndices, nextNoteIndex): # Find the nearest beats where this note locates - in [beat_indices[j], beat_indices[j+1]) j = 0 - while note_index < beat_indices[j] or note_index >= beat_indices[j+1]: + while noteIndices < beatIndices[j] or noteIndices >= beatIndices[j+1]: j = j + 1 # The distance of note to nearest beat normalised by the beat interval - distance_nearest_beat = min(abs(note_index - beat_indices[j]), abs(note_index - beat_indices[j+1]))/float(beat_interval) + distanceToNearestBeat = min(abs(noteIndices - beatIndices[j]), abs(noteIndices - beatIndices[j+1]))/float(beatInterval) # if this note is on-beat - if distance_nearest_beat == 0: + if distanceToNearestBeat == 0: measure = 0 # or if this note is held on past the following beat, but ends on or before the later beat - elif beat_indices[j+1] < nextnote_index <= beat_indices[j+2]: - measure = float(2)/distance_nearest_beat + elif beatIndices[j+1] < nextNoteIndex <= beatIndices[j+2]: + measure = float(2)/distanceToNearestBeat else: - measure = float(1)/distance_nearest_beat - + measure = float(1)/distanceToNearestBeat return measure total = 0 - for i in range(len(note_indices)): - if i == len(note_indices)-1:# if this is the last note, end_time is the index of the following note in the next bar - if postbar_seq != None and postbar_seq != repeat([0],len(postbar_seq)): - nextnote_index = get_note_indices(postbar_seq)[0]+len(seq) - else: # or if the next bar is none or full rest, end_time is the end of this sequence. - nextnote_index = len(seq) + for i in range(len(noteIndices)): + # if this is the last note, end_time is the index of the following note in the next bar + if i == len(noteIndices)-1: + # if the next bar is not none or a bar of full rest, + # the nextNoteIndex is the sum of sequence length in the current bar and the noteIndex in the next bar + if nextbarBinarySequence != None and nextbarBinarySequence != repeat([0],len(nextbarBinarySequence)): + nextNoteIndex = get_note_indices(nextbarBinarySequence)[0]+sequenceLength + # else when the next bar is none or full rest, end_time is the end of this sequence. + else: + nextNoteIndex = sequenceLength + # else this is not the last note, the nextNoteIndex is the following element in the noteIndices list else: - nextnote_index = note_indices[i+1] - total += measure_pernote(note_indices[i],nextnote_index) + nextNoteIndex = noteIndices[i+1] + # sum up the syncopation value for individual note at noteIndices[i] + total += measure_pernote(noteIndices[i],nextNoteIndex) #syncopation = float(total) / len(note_indices) + # return the total value, leave the normalisation done in the end return total
--- a/Syncopation models/basic_functions.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/basic_functions.py Tue Apr 07 19:05:07 2015 +0100 @@ -49,47 +49,58 @@ # The find_divisor function returns a list of all possible divisors for a length of sequence. def find_prime_factors(number): - prime_factors = find_divisor(number) + primeFactors = find_divisor(number) - def is_prime(num): - if num < 2: - return False - if num == 2: - return True - else: - for div in range(2,num): - if num % div == 0: - return False - return True + # remove 1 because 1 is not prime number + del primeFactors[0] - for i in range(len(prime_factors)-1,0,-1): - if is_prime(prime_factors[i]) == False: - del prime_factors[i] + # reversely traverse all the divisors list and once find a non-prime then delete + for i in range(len(primeFactors)-1,0,-1): + # print primeFactors[i], is_prime(primeFactors[i]) + if not is_prime(primeFactors[i]): + del primeFactors[i] - return prime_factors + return primeFactors + +def is_prime(number): + isPrime = True + # 0 or 1 is not prime numbers + if number < 2: + isPrime = False + # 2 is the only even prime number + elif number == 2: + pass + # all the other even numbers are non-prime + elif number % 2 == 0: + isPrime = False + else: + for odd in range(3, int(math.sqrt(number) + 1), 2): + if number % odd == 0: + isPrime = False + return isPrime # The min_timeSpan function searches for the shortest possible time-span representation for a sequence. def get_min_timeSpan(seq): - min_ts = [1] + minTimeSpan = [1] for d in find_divisor(len(seq)): segments = subdivide(seq,d) if len(segments)!=0: - del min_ts[:] + del minTimeSpan[:] for s in segments: - min_ts.append(s[0]) - if sum(min_ts) == sum(seq): + minTimeSpan.append(s[0]) + if sum(minTimeSpan) == sum(seq): break - return min_ts + return minTimeSpan # get_note_indices returns all the indices of all the notes in this sequence -def get_note_indices(seq): - note_indices = [] +def get_note_indices(sequence): + noteIndices = [] - for index in range(len(seq)): - if seq[index] != 0: - note_indices.append(index) + for index in range(len(sequence)): + if sequence[index] != 0: + noteIndices.append(index) - return note_indices + return noteIndices # The get_H returns a sequence of metrical weight for a certain metrical level (horizontal), # given the sequence of metrical weights in a hierarchy (vertical) and a sequence of subdivisions. @@ -179,4 +190,15 @@ # # testing -# print find_prime_factors(10) \ No newline at end of file +# print find_prime_factors(10) +# print find_prime_factors(2) +# print find_prime_factors(12) + + +# print is_prime(1) # False +# print is_prime(2) # True +# print is_prime(3) # True +# print is_prime(29) # True +# print is_prime(345) # False +# print is_prime(999979) # True +# print is_prime(999981) # False \ No newline at end of file
--- a/Syncopation models/music_objects.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/music_objects.py Tue Apr 07 19:05:07 2015 +0100 @@ -96,7 +96,7 @@ return self.timeSignature.get_subdivision_sequence() def get_beat_level(self): - return ParameterSetter.get_beat_level(self.timeSignature) + return self.timeSignature.get_beat_level() def get_time_signature(self): return self.timeSignature @@ -107,17 +107,17 @@ class TimeSignature(): def __init__(self, inputString): - if inputString in parameter_setter.readTimesig(): + if inputString in parameter_setter.read_time_signature(): self.tsString = inputString else: print "Error: undefined time-signature ", inputString raise NullTimeSignatureError def get_subdivision_sequence(self): - return parameter_setter.timesigBase[self.tsString][0] + return parameter_setter.timeSignatureBase[self.tsString][0] def get_beat_level(self): - return parameter_setter.timesigBase[self.tsString][1] + return parameter_setter.timeSignatureBase[self.tsString][1] def get_numerator(self): return int(self.tsString.split('/')[0])
--- a/Syncopation models/parameter_setter.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/parameter_setter.py Tue Apr 07 19:05:07 2015 +0100 @@ -8,19 +8,19 @@ # {'key': time-signature} : # {'value': [subdivision_seq, theoretical beat-level represented by index in the subdivision_seq list]} timeSignatureBase = { - '2/2': [[1,2,2,2,2],1], - '3/2': [[1,3,2,2,2],1], - '4/2': [[1,2,2,2,2],1], - '2/4': [[1,2,2,2,2],1], - '3/4': [[1,3,2,2,2],1], - '4/4': [[1,2,2,2,2],2], - '5/4': [[1,5,2,2,2],1], - '7/4': [[1,7,2,2,2],1], - '3/8': [[1,3,2,2,2],1], - '5/8': [[1,5,2,2,2],1], - '6/8': [[1,2,3,2,2],1], - '9/8': [[1,3,3,2,2],1], - '12/8':[[1,2,2,3,2],2], + '2/2': [[1,2,2,2,2,2],1], + '3/2': [[1,3,2,2,2,2],1], + '4/2': [[1,2,2,2,2,2],1], + '2/4': [[1,2,2,2,2,2],1], + '3/4': [[1,3,2,2,2,2],1], + '4/4': [[1,2,2,2,2,2],2], + '5/4': [[1,5,2,2,2,2],1], + '7/4': [[1,7,2,2,2,2],1], + '3/8': [[1,3,2,2,2,2],1], + '5/8': [[1,5,2,2,2,2],1], + '6/8': [[1,2,3,2,2,2],1], + '9/8': [[1,3,3,2,2,2],1], + '12/8':[[1,2,2,3,2,2],2], } def add_time_signature(timeSignature, subdivisionSequence, beatLevel):
--- a/Syncopation models/rhythm_parser.py Fri Apr 03 22:57:27 2015 +0100 +++ b/Syncopation models/rhythm_parser.py Tue Apr 07 19:05:07 2015 +0100 @@ -6,7 +6,7 @@ # Parse the rhythm file and return a list of Bar objects Piece = [] -from parameter_setter import timesigBase +from parameter_setter import timeSignatureBase comment_sign = '#' @@ -98,9 +98,9 @@ #def checkTimesig(input): -# TESTING -line = 't{4/4} q{1,0,0,1,0,0,1,0,0,0,1,0,0.8,0,0,0} t{2/4} # This is a comment' -# print discardSpaces(discardComments(line)) -print line[line.find('{')+1:line.find('}')] -#print readRhythm("rhythmbase/testrhythm.txt") +# # TESTING +# line = 't{4/4} q{1,0,0,1,0,0,1,0,0,0,1,0,0.8,0,0,0} t{2/4} # This is a comment' +# # print discardSpaces(discardComments(line)) +# print line[line.find('{')+1:line.find('}')] +# #print readRhythm("rhythmbase/testrhythm.txt")