csong@0: ''' csong@0: Author: Chunyang Song csong@0: Institution: Centre for Digital Music, Queen Mary University of London csong@0: ''' csong@0: csong@1: from basic_functions import repeat, subdivide, ceiling, get_min_timeSpan csong@1: csong@1: def get_cost(seq,next_seq): csong@1: seq = get_min_timeSpan(seq) # converting to the minimum time-span format csong@1: csong@1: if seq[1:] == repeat([0],len(seq)-1): # null prototype csong@1: cost = 0 csong@1: elif seq == repeat([1],len(seq)): # filled prototype csong@1: cost = 1 csong@1: elif seq[0] == 1 and seq[-1] == 0: # run1 prototype csong@1: cost = 2 csong@1: elif seq[0] == 1 and (next_seq == None or next_seq[0] == 0): # run2 prototype csong@1: cost = 2 csong@1: elif seq[0] == 1 and seq[-1] == 1 and next_seq != None and next_seq[0] == 1: # upbeat prototype csong@1: cost = 3 csong@1: elif seq[0] == 0: # syncopated prototype csong@1: cost = 5 csong@1: csong@1: return cost csong@1: csong@1: # This function calculates the syncopation value (cost) for the sequence with the postbar_seq for a certain level. csong@1: def syncopation_perlevel(sub_seqs, num_subs): csong@1: total = 0 csong@1: for l in range(num_subs): csong@1: total = total + get_cost(sub_seqs[l], sub_seqs[l+1]) csong@1: normalised = float(total)/num_subs csong@1: csong@1: return normalised csong@1: csong@1: # This function calculates the overall syncopation value for a bar of sequence.. csong@1: def get_syncopation(seq,subdivision_seq, postbar_seq, rhythm_category): csong@1: syncopation = None csong@1: if rhythm_category == 'poly': csong@1: print 'Error: PRS model cannot deal with polyrhythms.' csong@0: else: csong@1: syncopation = 0 csong@0: csong@1: current_num_subs = 1 # the initial number of sub-sequences at a certain metrical level csong@1: for subdivisor in subdivision_seq: csong@1: # the number of sub-sequence at the current level is product of all the subdivisors up to the current level csong@1: current_num_subs = current_num_subs * subdivisor csong@1: # recursion stops when the length of sub-sequence is less than 2 csong@1: if len(seq)/current_num_subs >= 2: csong@1: # generate sub-sequences and append the next bar sequence csong@1: sub_seqs = subdivide(ceiling(seq), current_num_subs) csong@1: sub_seqs.append(postbar_seq) csong@1: # adding syncopation at each metrical level to the total syncopation csong@1: syncopation += syncopation_perlevel(sub_seqs, current_num_subs) csong@1: else: csong@1: break csong@0: csong@1: return syncopation