changeset 50:e71028851131

updating latex and bug fixes to main py files
author christopherh <christopher.harte@eecs.qmul.ac.uk>
date Mon, 27 Apr 2015 09:51:15 +0100
parents af3f32cebf8c
children a1575e27916d
files SMC2015latex/conclusion.tex SMC2015latex/dataset.tex SMC2015latex/framework.tex SMC2015latex/syncopation_toolkit.tex Syncopation models/synpy/LHL.py Syncopation models/synpy/PRS.py Syncopation models/synpy/music_objects.py Syncopation models/synpy/parameter_setter.py Syncopation models/synpy/readmidi.py Syncopation models/synpy/syncopation.py
diffstat 10 files changed, 245 insertions(+), 157 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SMC2015latex/conclusion.tex	Mon Apr 27 09:51:15 2015 +0100
@@ -0,0 +1,2 @@
+\section{Conclusion}
+\label{sec:conclusion}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SMC2015latex/dataset.tex	Mon Apr 27 09:51:15 2015 +0100
@@ -0,0 +1,2 @@
+\section{Data Set}
+\label{sec:data}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SMC2015latex/framework.tex	Mon Apr 27 09:51:15 2015 +0100
@@ -0,0 +1,97 @@
+\section{Framework}
+
+\begin{figure}[t]
+\centering
+\includegraphics[width=0.6\columnwidth]{images/framework.pdf}
+\caption{Module hierarchy in the synpy toolkit: The top-level module provides a simple interface for the user to test different syncopation models. Musical constructs such as bars, velocity and note sequences, notes and time signatures are defined in the `music objects' module while support for common procedures such as sequence concatenation and subdivision is provided in `basic functions'. Models and file reading components can be interchanged as required by the user.\label{fig:framework}}
+\end{figure}
+
+\begin{figure}
+\footnotesize{
+\begin{minted}[frame=single,framesep=10pt]{python}
+T{4/4} # time signature
+TPQ{4} # ticks per quarternote
+# Bar 1
+Y{(0,3,2),(3,1,1),(6,2,2),(10,2,1),(12,4,1)}
+# Bar 2
+V{1,0,0,0.5,0,0,1,0,0,0,0.5,0,0.5,0,0,0}
+\end{minted}
+}
+\caption{Example rhythm annotation \code{.rhy} file containing two bars of the Son Clave rhythm. The first is expressed as a note sequence with resolution of four ticks per quarternote; the second is the same rhythm expressed as a velocity sequence (see section~\ref{sec:background}.}
+\label{ta:clave} 
+\end{figure}
+\begin{figure}
+\footnotesize{
+\begin{minted}[frame=single,framesep=10pt]{python}
+>>>from synpy import *
+>>>import synpy.PRS as model
+>>>calculate_syncopation(model, "clave.rhy")
+{'bars_with_valid_output': [0, 1],
+ 'mean_syncopation_per_bar': 8.625,
+ 'model_name': 'PRS',
+ 'number_of_bars': 2,
+ 'number_of_bars_not_measured': 0,
+ 'source': 'clave.rhy',
+ 'summed_syncopation': 17.25,
+ 'syncopation_by_bar': [8.625, 8.625]}
+\end{minted}
+}
+\caption{To use the library, the top level \code{synpy} module is imported along with a model (in this example Pressing \cite{pressing}); calling \code{calculate\_syncopation()} gives the syncopation results as shown. 
+\label{ta:example} }
+\end{figure}
+
+The architecture of the toolkit is relatively simple (see Figure~\ref{fig:framework}); syncopation values are calculated for each bar in a given source of rhythm data with the user specifying which model to use and supplying any special parameters that are required.  Output can optionally be saved directly to XML or JSON files. Sources of rhythm data can be the name of a file containing rhythm data or a bar or list of bar objects as defined in section~\ref{sec:?}.   Where a model is unable to calculate a value for a given rhythm pattern, a “None” value is recorded for that bar and the indices of unmeasured bars reported in the output.  
+
+Musical constructs such as bars, velocity and note sequences, notes and time signatures are defined in the `music objects' module with support for common procedures such as sequence concatenation and subdivision being provided in `basic functions'.  Two file reader modules are currently provided; one for reading standard MIDI files and one for reading plain text rhythm annotation \code{.rhy} files. These modules open their respective file types and return a list of bar objects that the syncopation models can process.  
+
+The system architecture has been designed to allow new models to be added easily.   Models have a common interface, exposing a single function that will return the syncopation value for a bar of music.  Optional parameters may be supplied as a Python dictionary if the user wishes to specify settings different from the those given in the literature for a specific model.
+
+
+
+% \section{MIDI Input}\label{sec:midi}
+
+% \cite{Taylor89MusicTheory}
+
+% \section{Text Input}\label{sec:textinput}
+
+% \begin{table*}
+% \small{
+% \begin{minted}[frame=single,framesep=10pt]{console}
+% <piece>             ::=  [<comment-lines>] <timesig> <line> | <piece> <line>
+
+% <comment-lines>     ::= <comment> "\n" | <comment-lines> <comment> "\n"
+
+% <line>              ::= [<barlist>] [<comment>] "\n"
+
+% <comment>           ::= "#" <comment-text>
+
+% <barlist>           ::= <time-info> | [<time-info>] <bar> | <barlist> <bar>
+
+% <time-info>         ::= [<timesig>] [<ticks-per-quarter>] [<tempo>] 
+
+% <tempo>             ::= "QPM{" <digits> "}"
+
+% <ticks-per-quarter> ::= "TPQ{" <digits> "}"
+
+% <timesig>           ::= "T{" <digit> "/" <digit> "}"
+
+% <bar>               ::= "V{" <velocity-sequence> "}" | "Y{" <note-sequence> "}"
+
+% <note-sequence>     ::= <note> | <note-sequence> "," <note>
+
+% <note>              ::= "(" <digits> "," <digits> "," <digits> ")"
+
+% <velocity-sequence> ::= <decimal> | <velocity-sequence> "," <decimal>
+
+% <decimal>           ::= "0" | "1" | "0." <digits>
+
+% <digits>            ::= <digit> | <digits> <digit>
+
+% <digit>             ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+% \end{minted}
+% }
+% \caption{Syntax of rhythm text format Backus-Naur Form}
+% \label{ta:BNF} 
+% \end{table*}
+
+
--- a/SMC2015latex/syncopation_toolkit.tex	Mon Apr 27 09:46:18 2015 +0100
+++ b/SMC2015latex/syncopation_toolkit.tex	Mon Apr 27 09:51:15 2015 +0100
@@ -11,6 +11,8 @@
 \usepackage{cite}
 \usepackage{minted}
 
+\newcommand{\code}[1]{{\small\texttt{#1}}}
+
 %%%%%%%%%%%%%%%%%%%%%%%% Some useful packages %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%% See related documentation %%%%%%%%%%%%%%%%%%%%%%%%%%
 %\usepackage{amsmath} % popular packages from Am. Math. Soc. Please use the 
@@ -138,95 +140,24 @@
 \end{abstract}
 %
 
-\section{Introduction}\label{sec:introduction}
+\input{introduction}
+
+\input{background}
+
+\input{framework}
+
+\input{dataset}
+
+\input{conclusion}
+
+
 
 % \url{http://www.maynoothuniversity.ie/smc15}.
 
-\input{sections/backgroundLP}
 
 
-\section{MIDI Input}\label{sec:midi}
 
-\cite{Taylor89MusicTheory}
 
-\section{Text Input}\label{sec:textinput}
-
-\begin{table*}
-\small{
-\begin{minted}[frame=single,framesep=10pt]{console}
-<piece>             ::=  [<comment-lines>] <timesig> <line> | <piece> <line>
-
-<comment-lines>     ::= <comment> "\n" | <comment-lines> <comment> "\n"
-
-<line>              ::= [<barlist>] [<comment>] "\n"
-
-<comment>           ::= "#" <comment-text>
-
-<barlist>           ::= <time-info> | [<time-info>] <bar> | <barlist> <bar>
-
-<time-info>         ::= [<timesig>] [<ticks-per-quarter>] [<tempo>] 
-
-<tempo>             ::= "QPM{" <digits> "}"
-
-<ticks-per-quarter> ::= "TPQ{" <digits> "}"
-
-<timesig>           ::= "T{" <digit> "/" <digit> "}"
-
-<bar>               ::= "V{" <velocity-sequence> "}" | "Y{" <note-sequence> "}"
-
-<note-sequence>     ::= <note> | <note-sequence> "," <note>
-
-<note>              ::= "(" <digits> "," <digits> "," <digits> ")"
-
-<velocity-sequence> ::= <decimal> | <velocity-sequence> "," <decimal>
-
-<decimal>           ::= "0" | "1" | "0." <digits>
-
-<digits>            ::= <digit> | <digits> <digit>
-
-<digit>             ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
-\end{minted}
-}
-\caption{Syntax of rhythm text format Backus-Naur Form}
-\label{ta:BNF} 
-\end{table*}
-
-
-\begin{table}
-\footnotesize{
-\begin{minted}[frame=single,framesep=10pt]{python}
-T{4/4} # time signature
-TPQ{4} # ticks per quarternote
-# Bar 1
-Y{(0,3,2),(3,1,1),(6,2,2),(10,2,1),(12,4,1)}
-# Bar 2
-V{1,0,0,0.5,0,0,1,0,0,0,0.5,0,0.5,0,0,0}
-\end{minted}
-}
-\caption{Example rhythm annotation file containing two bars of the Son Clave rhythm. The first is expressed as a note sequence with resolution of four ticks per quarternote; the second is the same rhythm expressed as a velocity sequence.}
-\label{ta:clave} 
-\end{table}
-
-
-\begin{table}
-\footnotesize{
-\begin{minted}[frame=single,framesep=10pt]{python}
->>>from syncopation import *
->>>import PRS as model
->>>calculate_syncopation(model, "clave.rhy")
-{'bars_with_valid_output': [0, 1],
- 'mean_syncopation_per_bar': 8.625,
- 'model_name': 'PRS',
- 'number_of_bars': 2,
- 'number_of_bars_not_measured': 0,
- 'source': 'clave.rhy',
- 'summed_syncopation': 17.25,
- 'syncopation_by_bar': [8.625, 8.625]}
-\end{minted}
-}
-\caption{Syntax of rhythm text format Backus-Naur Form}
-\label{ta:clave} 
-\end{table}
 
 
 
@@ -278,14 +209,6 @@
 
 
 
-
-
-
-
-\section{Conclusions}
-
-some conclusions
-
 %
 \begin{acknowledgments}
 You may acknowledge people, projects, 
--- a/Syncopation models/synpy/LHL.py	Mon Apr 27 09:46:18 2015 +0100
+++ b/Syncopation models/synpy/LHL.py	Mon Apr 27 09:51:15 2015 +0100
@@ -6,37 +6,42 @@
 from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category
 from parameter_setter import are_parameters_valid
 
-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.
+# Each terminal node contains two properties: its node type (note or rest) and its metrical weight.
 class Node:
 	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(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level):
+def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level, Lmax):
 	# If matching to a Note type, add to terminal nodes
+	output = list()
 	if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)):	
-		terminalNodes.append(Node('N',metricalWeight))
+		output.append(Node('N',metricalWeight))
 
 	# If matching to a Rest type, add to terminal nodes
 	elif binarySequence == repeat([0],len(binarySequence)):					
-		terminalNodes.append(Node('R',metricalWeight))
+		output.append(Node('R',metricalWeight))
+
+	elif level+1 == Lmax:
+		print "WARNING: LHL tree recursion descended to Lmax, returning a note node but result will not be fully accurate.  Check the rhythm pattern under test and/or specify larger Lmax to rectify the problem."
+		output.append(Node('N',metricalWeight))
 
 	# Keep subdividing by the subdivisor of the next level
-	else:													
+	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)
-
+			output = output + recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1, Lmax)
+	
+	return output
 
 def get_syncopation(bar, parameters = None):
-	del terminalNodes[:]
 	syncopation = None
+	naughtyglobal = 0
 
 	binarySequence = bar.get_binary_sequence()
 	subdivisionSequence = bar.get_subdivision_sequence()
@@ -44,9 +49,12 @@
 	# LHL can only measure monorhythms
 	if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
 		print 'Warning: LHL model detects polyrhythms so returning None.'
+	elif bar.is_empty():
+		print 'LHL model detects empty bar so returning -1.'
+		syncopation = -1
 	else:
 		# set defaults
-		Lmax = 5
+		Lmax = 10
 		weightSequence = range(0,-Lmax-1,-1)
 		# if parameters are specified by users, check their validities and update parameters if valid		
 		if parameters!= None:
@@ -58,25 +66,34 @@
 		if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence):
 			print 'Error: the given parameters are not valid.'
 		else:
-			# If there is rhythm in previous bar, process its tree structure
+			
+			# For the rhythm in the current bar, process its tree structure and store the terminal nodes 
+			terminalNodes = recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0, Lmax)
+			
+			# save the terminal nodes on the current bar so that 
+			# the next bar can access them...
+			bar.LHLterminalNodes = terminalNodes
+
+			# If there is rhythm in the previous bar and we've already processed it 
 			prevbar =  bar.get_previous_bar()
-			if prevbar != None and not prevbar.is_empty():
-				prebarBinarySequence = prevbar.get_binary_sequence()
-				recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
-				
-				if len(terminalNodes)>0:
+			if prevbar != None and prevbar.is_empty() != True:
+				# get its LHL tree if it has one
+				try:
+					prevbarNodes = prevbar.LHLterminalNodes
+				except AttributeError:
+					prevbarNodes = []
+
+				# find the final note node in the previous bar:
+				if len(prevbarNodes)>0:
+					i = len(prevbarNodes) - 1
 					# Only keep the last note-type node
-					while terminalNodes[-1].nodeType != '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(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
+					while prevbarNodes[i].nodeType != 'N' and i>=0:
+						i = i-1
+					# prepend the note to the terminal node list for this bar
+					terminalNodes = [ prevbarNodes[i] ] + terminalNodes
+						
 			
-			# for t in terminalNodes:
-			# 	print '<', t.nodeType, t.metricalWeight, '>'
-
-			# Search for the NR pairs that contribute to syncopation,then add the weight-difference to the NRpairSyncopation list
+			# 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].nodeType == 'R':
@@ -84,7 +101,6 @@
 						if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight):
 							NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight)
 							break
-			#print NRpairSyncopation
 
 			# If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list	
 			if len(NRpairSyncopation) != 0:
--- a/Syncopation models/synpy/PRS.py	Mon Apr 27 09:46:18 2015 +0100
+++ b/Syncopation models/synpy/PRS.py	Mon Apr 27 09:51:15 2015 +0100
@@ -38,12 +38,14 @@
 def get_syncopation(bar, parameters = None):
 	syncopation = None
 
-	binarySequence = bar.get_binary_sequence()
+	binarySequence = velocity_sequence_to_min_timespan(bar.get_binary_sequence())
 	subdivisionSequence = bar.get_subdivision_sequence()
 
 	# PRS does not handle polyrhythms
 	if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
 		print 'Warning: PRS model detects polyrhythms so returning None.'
+	elif bar.is_empty():
+		print 'Warning: PRS model detects empty bar so returning None.'
 	else:
 		syncopation = 0
 
--- a/Syncopation models/synpy/music_objects.py	Mon Apr 27 09:46:18 2015 +0100
+++ b/Syncopation models/synpy/music_objects.py	Mon Apr 27 09:51:15 2015 +0100
@@ -120,8 +120,10 @@
 	for note in noteSequence:
 		
 		interOnsetInterval = note.startTime - previousNoteStartTime	
-		velocitySequence += [0]*(interOnsetInterval-1)	
-		velocitySequence += [note.velocity]
+		#ignore note if it is part of a chord...
+		if interOnsetInterval!=0:
+			velocitySequence += [0]*(interOnsetInterval-1)	
+			velocitySequence += [note.velocity]
 
 		previousNoteStartTime = note.startTime
 
@@ -150,6 +152,21 @@
 			self.append(localbar)
 			barList.remove(localbar)
 
+	def to_string(self, sequenceType="y"):
+		
+		output = ""
+
+		for bar in self:
+			prev = bar.get_previous_bar()
+
+			params = "t"+sequenceType
+
+			if prev!=None and prev.get_time_signature()==bar.get_time_signature():
+				params = "-"+params	
+			
+			output += " " + bar.to_string(params)
+
+		return output
 
 class Bar:
 	def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None):
@@ -216,17 +233,22 @@
 		else:
 			return True
 
-	def to_string(self, sequenceType=None):
-		output = "t{"+self.timeSignature.to_string()+"}"
-		prev = self.get_previous_bar()
-		if prev!=None:
-			if prev.get_time_signature()==self.get_time_signature():
-				output=""
+	def to_string(self, sequenceType="ty"):
+		
+		# prev = self.get_previous_bar()
+		# if prev!=None:
+		# 	if prev.get_time_signature()==self.get_time_signature():
+		# 		output=""
+		output = ""
 
-		if sequenceType==None or sequenceType=="v":
+		if "-t" not in sequenceType:
+			output = "t{"+self.timeSignature.to_string()+"}"
+
+		if "v" in sequenceType:
 			output += "v{"+self.get_velocity_sequence().to_string()+"}"
 		else:
 			output += "y{"+self.get_note_sequence().to_string()+"}"
+
 		return output
 
 
--- a/Syncopation models/synpy/parameter_setter.py	Mon Apr 27 09:46:18 2015 +0100
+++ b/Syncopation models/synpy/parameter_setter.py	Mon Apr 27 09:51:15 2015 +0100
@@ -10,19 +10,19 @@
 # {'key': time-signature} :  
 # {'value': [subdivision-sequence, theoretical beat-level represented by index in the subdivision-sequence list]}
 timeSignatureBase = {
-	'2/2': [[1,2,2,2,2,2],1],
-	'3/2': [[1,3,2,2,2,2],1],
-	'4/2': [[1,2,2,2,2,2],1],
-	'2/4': [[1,2,2,2,2,2],1],
-	'3/4': [[1,3,2,2,2,2],1],
-	'4/4': [[1,2,2,2,2,2],2],
-	'5/4': [[1,5,2,2,2,2],1],
-	'7/4': [[1,7,2,2,2,2],1],
-	'3/8': [[1,3,2,2,2,2],1],
-	'5/8': [[1,5,2,2,2,2],1],
-	'6/8': [[1,2,3,2,2,2],1],
-	'9/8': [[1,3,3,2,2,2],1],
-	'12/8':[[1,2,2,3,2,2],2],	
+	'2/2': [[1,2,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'3/2': [[1,3,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'4/2': [[1,2,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'2/4': [[1,2,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'3/4': [[1,3,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'4/4': [[1,2,2,2,2,2,2,2,2,2,2,2,2,2],2],
+	'5/4': [[1,5,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'7/4': [[1,7,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'3/8': [[1,3,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'5/8': [[1,5,2,2,2,2,2,2,2,2,2,2,2,2],1],
+	'6/8': [[1,2,3,2,2,2,2,2,2,2,2,2,2,2],1],
+	'9/8': [[1,3,3,2,2,2,2,2,2,2,2,2,2,2],1],
+	'12/8':[[1,2,2,3,2,2,2,2,2,2,2,2,2,2],2],	
 }
 
 
--- a/Syncopation models/synpy/readmidi.py	Mon Apr 27 09:46:18 2015 +0100
+++ b/Syncopation models/synpy/readmidi.py	Mon Apr 27 09:51:15 2015 +0100
@@ -94,7 +94,7 @@
 		return timesig
 
 
-	def get_time_signature(timeList,barStartTime, barEndTime, currentTimeSignature = None):
+	def get_time_signature(timeList,barStartTime, barLength, ticksPerQuarter, currentTimeSignature = None):
 		
 		timesig = None
 		i=0
@@ -104,12 +104,15 @@
 			# before the end of the current bar
 			event = timeList[i]
 			i = i + 1
-			if event.time>=barEndTime:
+			if event.time>=barStartTime+barLength:
 				break
 
 			if event.type=="TIME_SIGNATURE" and event.time>=barStartTime:
 				timesig = midi_event_to_time_signature(event)
 				event.type = "USED_TIME_SIGNATURE"
+				barLength = calculate_bar_ticks(timesig.get_numerator(), 
+												timesig.get_denominator(), 
+												ticksPerQuarter)
 	
 		if timesig==None:
 			if currentTimeSignature==None:
@@ -117,7 +120,7 @@
 			else:
 				timesig = currentTimeSignature
 
-		return timesig	
+		return timesig,barLength	
 
 	def get_tempo(timeList,barStartTime, barEndTime, currentTempo = None):
 		
@@ -168,7 +171,7 @@
 	barlength = calculate_bar_ticks(timesig.get_numerator(), timesig.get_denominator(), ticksPerQuarter)
 	# initialise time for start and end of current bar
 	barStartTime = 0
-	barEndTime = barlength
+	barEndTime = 0# barlength
 	
 
 	# initialise bars list
@@ -181,7 +184,10 @@
 		#create a local note sequence to build a bar
 		currentNotes = NoteSequence()
 
-		timesig = get_time_signature(timeList,barStartTime, barEndTime, timesig)
+		[timesig,barlength] = get_time_signature(timeList,barStartTime, barlength, ticksPerQuarter, timesig)
+		
+		barEndTime = barEndTime + barlength
+
 		tempo = get_tempo(timeList,barStartTime, barEndTime, tempo)
 		
 
@@ -202,8 +208,6 @@
 
 		barStartTime = barEndTime
 
-		barEndTime = barEndTime + barlength
-
 	return bars
 
 		
@@ -231,10 +235,18 @@
 					note = Note(event.time,endEvent.time-event.time,event.velocity)
 					#alter the type of this end event so it can't be linked to another note on
 					endEvent.type = "DUMMY"
-					#add the note to the list
-					noteslist.append(note)
+					
+					#if this note starts at the same time as the previous one
+					# replace the previous one if this has longer duration
+					if len(noteslist)>0 and note.startTime==noteslist[-1].startTime:
+						if note.duration>noteslist[-1].duration:
+							noteslist[-1]=note
+					# otherwise add the note to the list
+					else:
+						noteslist.append(note)
 					#found the end of the note so break out of the local loop
 					break
+				localindex = localindex+1
 
 	return noteslist
 
--- a/Syncopation models/synpy/syncopation.py	Mon Apr 27 09:46:18 2015 +0100
+++ b/Syncopation models/synpy/syncopation.py	Mon Apr 27 09:51:15 2015 +0100
@@ -21,7 +21,9 @@
  		barlist = source
  		sourceType = "bar list"
  	elif isinstance(source, Bar):
- 		barlist = BarList().append(source)
+ 		barlist = BarList()
+ 		barlist.append(source)
+ 		print barlist
  		sourceType = "single bar"
 	elif isinstance(source, basestring):
 		#treat source as a filename
@@ -43,13 +45,19 @@
 	discardedlist = []
 	includedlist = []
 
+
 	if barlist!=None:
 		for bar in barlist:
-			if not bar.is_empty():
-				barSyncopation = sync_perbar_permodel(model, bar, parameters)
-			else:
-				barSyncopation = None
-				print 'Bar %d cannot be measured because it is empty, returning None.' % barlist.index(bar)
+			print 'processing bar %d' % (barlist.index(bar)+1)
+
+			barSyncopation = sync_perbar_permodel(model, bar, parameters)
+			
+
+			# if not bar.is_empty():
+			# 	barSyncopation = sync_perbar_permodel(model, bar, parameters)
+			# else:
+			# 	barSyncopation = None
+			# 	print 'Bar %d cannot be measured because it is empty, returning None.' % barlist.index(bar)
 			
 			barResults.append(barSyncopation)
 			if barSyncopation != None:
@@ -59,13 +67,16 @@
 			else:
 				barsDiscarded += 1
 				discardedlist.append(barlist.index(bar))
-				print 'Model could not measure bar %d, returning None.' % barlist.index(bar)
+				print 'Model could not measure bar %d, returning None.' % (barlist.index(bar)+1)
 
 		import WNBD
 		if model is WNBD:
 			total =  total / numberOfNotes
 
-		average = total / (len(barResults)-barsDiscarded)
+		if len(barResults)>barsDiscarded:
+			average = total / (len(barResults)-barsDiscarded)
+		else:
+			average = total
 
 	output = {
  			"model_name":model.__name__ , 
@@ -75,6 +86,7 @@
  			"number_of_bars":len(barResults), 
  			"number_of_bars_not_measured":barsDiscarded, 
  			"bars_with_valid_output":includedlist, 
+ 			"bars_without_valid_output":discardedlist, 
  			"syncopation_by_bar":barResults
  			}