Mercurial > hg > syncopation-dataset
changeset 14:6b6f8e3d7262
updating lhl and prs
author | csong <csong@eecs.qmul.ac.uk> |
---|---|
date | Fri, 03 Apr 2015 17:10:57 +0100 |
parents | 7d94ba423c04 |
children | 4fb9c00e4ef0 |
files | Syncopation models/LHL.py Syncopation models/PRS.py |
diffstat | 2 files changed, 94 insertions(+), 61 deletions(-) [+] |
line wrap: on
line diff
--- a/Syncopation models/LHL.py Fri Apr 03 16:18:00 2015 +0100 +++ b/Syncopation models/LHL.py Fri Apr 03 17:10:57 2015 +0100 @@ -3,65 +3,85 @@ Institution: Centre for Digital Music, Queen Mary University of London ''' -from BasicFuncs import concatenate, repeat, subdivide, ceiling +from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category -terminal_nodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order +terminalNodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight. class Node: - def __init__(self,node_type,metrical_weight): - self.node_type = node_type - self.metrical_weight = metrical_weight + def __init__(self,nodeType,metricalWeight): + self.nodeType = nodeType + self.metricalWeight = metricalWeight # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order. -def recursive_tree(seq, subdivision_seq, weight_seq, metrical_weight, level): - if seq == concatenate([1],repeat([0],len(seq)-1)): # If matching to a Note type, add to terminal nodes - terminal_nodes.append(Node('N',metrical_weight)) +def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level): + # If matching to a Note type, add to terminal nodes + if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)): + terminalNodes.append(Node('N',metricalWeight)) - elif seq == repeat([0],len(seq)): # If matching to a Rest type, add to terminal nodes - terminal_nodes.append(Node('R',metrical_weight)) + # If matching to a Rest type, add to terminal nodes + elif binarySequence == repeat([0],len(binarySequence)): + terminalNodes.append(Node('R',metricalWeight)) - else: # Keep subdividing by the subdivisor of the next level - sub_seq = subdivide(seq, subdivision_seq[level+1]) - sub_weight_seq = concatenate([metrical_weight],repeat([weight_seq[level+1]],subdivision_seq[level+1]-1)) - for a in range(len(sub_seq)): - recursive_tree(sub_seq[a], subdivision_seq, weight_seq, sub_weight_seq[a], level+1) + # Keep subdividing by the subdivisor of the next level + else: + subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1]) + subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1)) + for a in range(len(subBinarySequences)): + recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1) -# This function calculate syncoaption score for LHL model. -def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category): +def get_syncopation(bar, weightSequence = None, LMax = None): + ''' + The get_syncopation function calculates syncopation value . + ''' +#def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category): syncopation = None - if rhythm_category == 'poly': - print 'Error: LHL model cannot deal with polyrhythms.' + + binarySequence = bar.get_binary_sequence() + subdivisionSequence = bar.get_subdivision_sequence() + + if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': + print 'Warning: LHL model detects polyrhythms so returning None.' else: + if weightSequence == None: + if LMax == None: + LMax = 5 + weightSequence = range(0,-LMax,-1) + # If there is rhythm in previous bar, process its tree structure - if prebar_seq != None: - recursive_tree(ceiling(prebar_seq), subdivision_seq, weight_seq, weight_seq[0],0) + if bar.get_previous_bar() != None: + prebarBinarySequence = bar.get_previous_bar().get_binary_sequence() + recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) # Only keep the last note-type node - while terminal_nodes[-1].node_type != 'N': - del terminal_nodes[-1] - del terminal_nodes[0:-1] + while terminalNodes[-1].node_type != 'N': + del terminalNodes[-1] + del terminalNodes[0:-1] # For the rhythm in the current bar, process its tree structure and store the terminal nodes - recursive_tree(ceiling(seq), subdivision_seq, weight_seq, weight_seq[0],0) + recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) - # for t in terminal_nodes: + # for t in terminalNodes: # print '<', t.node_type, t.metrical_weight, '>' - # Search for the NR pairs that contribute to syncopation, add the weight-difference to the NR_pair_syncopation list - NR_pair_syncopation = [] - for i in range(len(terminal_nodes)-1,0,-1): - if terminal_nodes[i].node_type == 'R': + # 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': for j in range(i-1, -1, -1): - if (terminal_nodes[j].node_type == 'N') & (terminal_nodes[i].metrical_weight >= terminal_nodes[j].metrical_weight): - NR_pair_syncopation.append(terminal_nodes[i].metrical_weight - terminal_nodes[j].metrical_weight) + if (terminalNodes[j].node_type == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight): + NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight) break - #print NR_pair_syncopation + #print NRpairSyncopation - # If no syncopation, the value is -1; otherwise, sum all the local syncopation values stored in NR_pair_syncopation list - if len(NR_pair_syncopation) != 0: - syncopation = sum(NR_pair_syncopation) - elif len(terminal_nodes) != 0: + # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list + if len(NRpairSyncopation) != 0: + syncopation = sum(NRpairSyncopation) + # If no syncopation, the value is -1; + elif len(terminalNodes) != 0: syncopation = -1 return syncopation + +
--- a/Syncopation models/PRS.py Fri Apr 03 16:18:00 2015 +0100 +++ b/Syncopation models/PRS.py Fri Apr 03 17:10:57 2015 +0100 @@ -3,54 +3,67 @@ Institution: Centre for Digital Music, Queen Mary University of London ''' -from BasicFuncs import repeat, subdivide, ceiling, get_min_timeSpan +from basic_functions import repeat, subdivide, ceiling, get_min_timeSpan, get_rhythm_category -def get_cost(seq,next_seq): - seq = get_min_timeSpan(seq) # converting to the minimum time-span format +def get_cost(sequence,nextSequence): + sequence = get_min_timeSpan(sequence) # converting to the minimum time-span format - if seq[1:] == repeat([0],len(seq)-1): # null prototype + if sequence[1:] == repeat([0],len(sequence)-1): # null prototype cost = 0 - elif seq == repeat([1],len(seq)): # filled prototype + elif sequence == repeat([1],len(sequence)): # filled prototype cost = 1 - elif seq[0] == 1 and seq[-1] == 0: # run1 prototype + elif sequence[0] == 1 and sequence[-1] == 0: # run1 prototype cost = 2 - elif seq[0] == 1 and (next_seq == None or next_seq[0] == 0): # run2 prototype + elif sequence[0] == 1 and (nextSequence == None or nenextSequencext_seq[0] == 0): # run2 prototype cost = 2 - elif seq[0] == 1 and seq[-1] == 1 and next_seq != None and next_seq[0] == 1: # upbeat prototype + elif sequence[0] == 1 and sequence[-1] == 1 and nextSequence != None and nextSequence[0] == 1: # upbeat prototype cost = 3 - elif seq[0] == 0: # syncopated prototype + elif sequence[0] == 0: # syncopated prototype cost = 5 return cost # This function calculates the syncopation value (cost) for the sequence with the postbar_seq for a certain level. -def syncopation_perlevel(sub_seqs, num_subs): +def syncopation_perlevel(subSequences): total = 0 - for l in range(num_subs): - total = total + get_cost(sub_seqs[l], sub_seqs[l+1]) - normalised = float(total)/num_subs + for l in range(len(subSequences)-1): + total = total + get_cost(subSequences[l], subSequences[l+1]) + normalised = float(total)/(len(subSequences)-1) return normalised -# This function calculates the overall syncopation value for a bar of sequence.. -def get_syncopation(seq,subdivision_seq, postbar_seq, rhythm_category): +#def get_syncopation(seq,subdivision_seq, postbar_seq, rhythm_category): +def get_syncopation(bar, weightSequence = None, LMax = None): + ''' + The get_syncopation function calculates the overall syncopation value for a bar of sequence. + ''' syncopation = None - if rhythm_category == 'poly': - print 'Error: PRS model cannot deal with polyrhythms.' + + binarySequence = bar.get_binary_sequence() + subdivisionSequence = bar.get_subdivision_sequence() + + if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': + print 'Warning: PRS model detects polyrhythms so returning None.' else: syncopation = 0 - current_num_subs = 1 # the initial number of sub-sequences at a certain metrical level - for subdivisor in subdivision_seq: + 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 = 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 - current_num_subs = current_num_subs * subdivisor + numberOfSubSeqs = numberOfSubSeqs * subdivisor # recursion stops when the length of sub-sequence is less than 2 - if len(seq)/current_num_subs >= 2: + if len(binarySequence)/numberOfSubSeqs >= 2: # generate sub-sequences and append the next bar sequence - sub_seqs = subdivide(ceiling(seq), current_num_subs) - sub_seqs.append(postbar_seq) + subSequences = subdivide(ceiling(binarySequence), numberOfSubSeqs) + subSequences.append(nextbarBinarySequence) # adding syncopation at each metrical level to the total syncopation - syncopation += syncopation_perlevel(sub_seqs, current_num_subs) + syncopation += syncopation_perlevel(subSequences) else: break