csong@1: ''' csong@1: Author: Chunyang Song csong@1: Institution: Centre for Digital Music, Queen Mary University of London csong@1: csong@1: ''' csong@1: ## Problems! Note indices, post bar csong@1: csong@2: from BasicFuncs import get_min_timeSpan, get_note_indices, repeat csong@1: csong@1: # To find the nearest power of 2 equal to or less than the given number csong@1: def roundDownPower2(number): csong@1: i = 0 csong@1: if number > 0: csong@1: while pow(2,i) > number or number >= pow(2,i+1): csong@1: i = i+1 csong@1: power2 = pow(2,i) csong@1: else: csong@1: print 'Error: numbers that are less than 1 cannot be rounded down to its nearest power of two.' csong@1: power2 = None csong@1: return power2 csong@1: csong@1: # To find the nearest power of 2 equal to or more than the given number csong@1: def roundUpPower2(number): csong@1: i = 0 csong@1: while pow(2,i) < number: csong@1: i = i + 1 csong@1: return pow(2,i) csong@1: csong@1: # To examine whether start_time is 'off-beat' csong@1: def start(start_time, c_n): csong@1: s = 0 csong@1: if start_time % c_n != 0: csong@1: s = 2 csong@1: return s csong@1: csong@1: # To examine whether end_time is 'off-beat' csong@1: def end(end_time, c_n): csong@1: s = 0 csong@1: if end_time % c_n != 0: csong@1: s = 1 csong@1: return s csong@1: csong@1: # To calculate syncopation value of the sequence in the given time-signature. csong@1: def get_syncopation(seq, timesig, postbar_seq): csong@1: syncopation = 0 csong@1: csong@1: numerator = int(timesig.split("/")[0]) csong@1: if numerator == roundDownPower2(numerator): # if is a binary time-signature csong@1: # converting to minimum time-span format csong@1: seq = get_min_timeSpan(seq) csong@1: if postbar_seq != None: csong@1: postbar_seq = get_min_timeSpan(postbar_seq) csong@1: csong@1: # 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 csong@1: sf = roundUpPower2(len(seq)) csong@1: csong@1: # retrieve all the indices of all the notes in this sequence csong@1: note_indices = get_note_indices(seq) csong@1: csong@1: for i in range(len(note_indices)): csong@1: # Assuming start_time is the index of this note, end_time is the index of the following note csong@1: start_time = note_indices[i]*sf/float(len(seq)) csong@1: csong@1: 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 csong@1: if postbar_seq != None and postbar_seq != repeat([0],len(postbar_seq)): csong@1: next_index = get_note_indices(postbar_seq)[0]+len(seq) csong@1: end_time = next_index*sf/float(len(seq)) csong@1: else: # or if the next bar is none or full rest, end_time is the end of this sequence. csong@1: end_time = sf csong@1: else: csong@1: end_time = note_indices[i+1]*sf/float(len(seq)) csong@1: csong@1: duration = end_time - start_time csong@1: c_n = roundDownPower2(duration) csong@1: syncopation = syncopation + start(start_time,c_n) + end(end_time,c_n) csong@1: else: csong@1: print 'Error: KTH model can only deal with binary time-signature, e.g. 2/4 and 4/4. ' csong@1: syncopation = None csong@1: csong@1: return syncopation