annotate Syncopation models/LHL.py @ 1:b2da092dc2e0

The consolidated syncopation software. Have finished individual model and basic functions. Need to revise the coding in main.py, and add rhythm-input interface.
author Chunyang Song <csong@eecs.qmul.ac.uk>
date Sun, 05 Oct 2014 21:52:41 +0100
parents 76ce27beba95
children 031e2ccb1fb6
rev   line source
csong@0 1 '''
csong@0 2 Author: Chunyang Song
csong@0 3 Institution: Centre for Digital Music, Queen Mary University of London
csong@1 4 '''
csong@0 5
csong@1 6 from basic_functions import concatenate, repeat, subdivide, ceiling
csong@0 7
csong@1 8 terminal_nodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order
csong@0 9
csong@1 10 # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight.
csong@1 11 class Node:
csong@1 12 def __init__(self,node_type,metrical_weight):
csong@1 13 self.node_type = node_type
csong@1 14 self.metrical_weight = metrical_weight
csong@0 15
csong@1 16 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order.
csong@1 17 def recursive_tree(seq, subdivision_seq, weight_seq, metrical_weight, level):
csong@1 18 if seq == concatenate([1],repeat([0],len(seq)-1)): # If matching to a Note type, add to terminal nodes
csong@1 19 terminal_nodes.append(Node('N',metrical_weight))
csong@0 20
csong@1 21 elif seq == repeat([0],len(seq)): # If matching to a Rest type, add to terminal nodes
csong@1 22 terminal_nodes.append(Node('R',metrical_weight))
csong@0 23
csong@1 24 else: # Keep subdividing by the subdivisor of the next level
csong@1 25 sub_seq = subdivide(seq, subdivision_seq[level+1])
csong@1 26 sub_weight_seq = concatenate([metrical_weight],repeat([weight_seq[level+1]],subdivision_seq[level+1]-1))
csong@1 27 for a in range(len(sub_seq)):
csong@1 28 recursive_tree(sub_seq[a], subdivision_seq, weight_seq, sub_weight_seq[a], level+1)
csong@0 29
csong@1 30 # This function calculate syncoaption score for LHL model.
csong@1 31 def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category):
csong@1 32 syncopation = None
csong@1 33 if rhythm_category == 'poly':
csong@1 34 print 'Error: LHL model cannot deal with polyrhythms.'
csong@1 35 else:
csong@1 36 # If there is rhythm in previous bar, process its tree structure
csong@1 37 if prebar_seq != None:
csong@1 38 recursive_tree(ceiling(prebar_seq), subdivision_seq, weight_seq, weight_seq[0],0)
csong@1 39
csong@1 40 # Only keep the last note-type node
csong@1 41 while terminal_nodes[-1].node_type != 'N':
csong@1 42 del terminal_nodes[-1]
csong@1 43 del terminal_nodes[0:-1]
csong@0 44
csong@1 45 # For the rhythm in the current bar, process its tree structure and store the terminal nodes
csong@1 46 recursive_tree(ceiling(seq), subdivision_seq, weight_seq, weight_seq[0],0)
csong@1 47
csong@1 48 # for t in terminal_nodes:
csong@1 49 # print '<', t.node_type, t.metrical_weight, '>'
csong@0 50
csong@1 51 # Search for the NR pairs that contribute to syncopation, add the weight-difference to the NR_pair_syncopation list
csong@1 52 NR_pair_syncopation = []
csong@1 53 for i in range(len(terminal_nodes)-1,0,-1):
csong@1 54 if terminal_nodes[i].node_type == 'R':
csong@1 55 for j in range(i-1, -1, -1):
csong@1 56 if (terminal_nodes[j].node_type == 'N') & (terminal_nodes[i].metrical_weight >= terminal_nodes[j].metrical_weight):
csong@1 57 NR_pair_syncopation.append(terminal_nodes[i].metrical_weight - terminal_nodes[j].metrical_weight)
csong@1 58 break
csong@1 59 #print NR_pair_syncopation
csong@0 60
csong@1 61 # If no syncopation, the value is -1; otherwise, sum all the local syncopation values stored in NR_pair_syncopation list
csong@1 62 if len(NR_pair_syncopation) != 0:
csong@1 63 syncopation = sum(NR_pair_syncopation)
csong@1 64 elif len(terminal_nodes) != 0:
csong@1 65 syncopation = -1
csong@0 66
csong@1 67 return syncopation