christopher@45: ''' christopher@45: Author: Chunyang Song christopher@45: Institution: Centre for Digital Music, Queen Mary University of London christopher@45: christopher@45: ''' christopher@45: christopher@45: from basic_functions import get_note_indices, repeat, velocity_sequence_to_min_timespan christopher@45: christopher@45: # To find the nearest power of 2 equal to or less than the given number christopher@45: def round_down_power_2(number): christopher@45: i = 0 christopher@45: if number > 0: christopher@45: while pow(2,i) > number or number >= pow(2,i+1): christopher@45: i = i+1 christopher@45: power2 = pow(2,i) christopher@45: else: christopher@45: print 'Error: numbers that are less than 1 cannot be rounded down to its nearest power of two.' christopher@45: power2 = None christopher@45: return power2 christopher@45: christopher@45: # To find the nearest power of 2 equal to or more than the given number christopher@45: def round_up_power_2(number): christopher@45: i = 0 christopher@45: while pow(2,i) < number: christopher@45: i = i + 1 christopher@45: return pow(2,i) christopher@45: christopher@45: # To examine whether start_time is 'off-beat' christopher@45: def start_time_offbeat_measure(startTime, c_n): christopher@45: measure = 0 christopher@45: if startTime % c_n != 0: christopher@45: measure = 2 christopher@45: return measure christopher@45: christopher@45: # To examine whether end_time is 'off-beat' christopher@45: def end_time_offbeat_measure(endTime, c_n): christopher@45: measure = 0 christopher@45: if endTime % c_n != 0: christopher@45: measure = 1 christopher@45: return measure christopher@45: christopher@45: def get_syncopation(bar, parameters = None): christopher@45: syncopation = None christopher@45: christopher@45: # KTH only deals with simple-duple meter where the number of beats per bar is a power of two. christopher@45: numerator = bar.get_time_signature().get_numerator() christopher@45: if numerator != round_down_power_2(numerator): christopher@45: print 'Warning: KTH model detects non simple-duple meter so returning None.' christopher@45: else: christopher@45: # retrieve note-sequence and next bar's note-sequence christopher@45: noteSequence = bar.get_note_sequence() christopher@45: #for note in noteSequence: christopher@45: # print note.to_string() christopher@45: #print 'barlength',bar.get_bar_ticks() christopher@45: christopher@45: nextbarNoteSequence = None christopher@45: if bar.get_next_bar() != None: christopher@45: nextbarNoteSequence = bar.get_next_bar().get_note_sequence() christopher@45: christopher@45: # convert note sequence to its minimum time-span representation so that the later calculation can be faster christopher@45: # noteSequence = note_sequence_to_min_timespan(noteSequence) christopher@45: # find delta_t christopher@45: Tmin = len(velocity_sequence_to_min_timespan(bar.get_velocity_sequence())) christopher@45: #print 'Tmin',Tmin christopher@45: T = round_up_power_2(Tmin) christopher@45: #print 'T',T christopher@45: deltaT = float(bar.get_bar_ticks())/T christopher@45: #print 'delta',deltaT christopher@45: christopher@45: christopher@45: # calculate syncopation note by note christopher@45: syncopation = 0 christopher@45: christopher@45: for note in noteSequence: christopher@45: c_n = round_down_power_2(note.duration/deltaT) christopher@45: #print 'd', note.duration christopher@45: #print 'c_n', c_n christopher@45: endTime = note.startTime + note.duration christopher@45: #print float(note.startTime)/deltaT, float(endTime)/deltaT christopher@45: syncopation = syncopation + start_time_offbeat_measure(float(note.startTime)/deltaT,c_n) + end_time_offbeat_measure(float(endTime)/deltaT,c_n) christopher@45: christopher@45: christopher@45: return syncopation christopher@45: christopher@45: # # To calculate syncopation value of the sequence in the given time-signature. christopher@45: # def get_syncopation(seq, timesig, postbar_seq): christopher@45: # syncopation = 0 christopher@45: christopher@45: # numerator = int(timesig.split("/")[0]) christopher@45: # if numerator == round_down_power_2(numerator): # if is a binary time-signature christopher@45: # # converting to minimum time-span format christopher@45: # seq = get_min_timeSpan(seq) christopher@45: # if postbar_seq != None: christopher@45: # postbar_seq = get_min_timeSpan(postbar_seq) christopher@45: christopher@45: # # 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 christopher@45: # sf = round_up_power_2(len(seq)) christopher@45: christopher@45: # # retrieve all the indices of all the notes in this sequence christopher@45: # note_indices = get_note_indices(seq) christopher@45: christopher@45: # for i in range(len(note_indices)): christopher@45: # # Assuming start_time is the index of this note, end_time is the index of the following note christopher@45: # start_time = note_indices[i]*sf/float(len(seq)) christopher@45: christopher@45: # 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 christopher@45: # if postbar_seq != None and postbar_seq != repeat([0],len(postbar_seq)): christopher@45: # next_index = get_note_indices(postbar_seq)[0]+len(seq) christopher@45: # end_time = next_index*sf/float(len(seq)) christopher@45: # else: # or if the next bar is none or full rest, end_time is the end of this sequence. christopher@45: # end_time = sf christopher@45: # else: christopher@45: # end_time = note_indices[i+1]*sf/float(len(seq)) christopher@45: christopher@45: # duration = end_time - start_time christopher@45: # c_n = round_down_power_2(duration) christopher@45: # syncopation = syncopation + start(start_time,c_n) + end(end_time,c_n) christopher@45: # else: christopher@45: # print 'Error: KTH model can only deal with binary time-signature, e.g. 2/4 and 4/4. ' christopher@45: # syncopation = None christopher@45: christopher@45: # return syncopation