changeset 29:7a1730bbf15a

updating files with new text reading code
author christopherh <christopher.harte@eecs.qmul.ac.uk>
date Sun, 12 Apr 2015 22:37:56 +0100
parents 5de1cb45c145
children d9ac6e0d1daf
files Syncopation models/basic_functions.py Syncopation models/music_objects.py Syncopation models/rhythm_parser.py Syncopation models/rhythmbase/clave.txt Syncopation models/text_bnf_syntax.txt
diffstat 5 files changed, 144 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/Syncopation models/basic_functions.py	Sun Apr 12 22:34:35 2015 +0100
+++ b/Syncopation models/basic_functions.py	Sun Apr 12 22:37:56 2015 +0100
@@ -94,6 +94,7 @@
 
 # convert a velocity sequence to its minimum time-span representation
 def velocity_sequence_to_min_timespan(velocitySequence):
+	from music_objects import VelocitySequence
 	minTimeSpanVelocitySeq = [1]
 	for divisors in find_divisor(len(velocitySequence)):
 		segments = subdivide(velocitySequence,divisors)
@@ -103,8 +104,9 @@
 				minTimeSpanVelocitySeq.append(s[0])
 			if sum(minTimeSpanVelocitySeq) == sum(velocitySequence):
 				break
-	return minTimeSpanVelocitySeq
+	return VelocitySequence(minTimeSpanVelocitySeq)
 
+"""
 # convert a note sequence to its minimum time-span representation
 def note_sequence_to_min_timespan(noteSequence):
 	from music_objects import note_sequence_to_velocity_sequence
@@ -129,7 +131,7 @@
 		note.duration = note.duration/delta_t
 
 	return noteSequence
-
+"""
 
 # get_note_indices returns all the indices of all the notes in this velocity_sequence
 def get_note_indices(velocitySequence):
--- a/Syncopation models/music_objects.py	Sun Apr 12 22:34:35 2015 +0100
+++ b/Syncopation models/music_objects.py	Sun Apr 12 22:37:56 2015 +0100
@@ -1,5 +1,5 @@
 
-from basic_functions import ceiling, string_to_sequence, calculate_bar_ticks
+from basic_functions import ceiling, string_to_sequence, calculate_bar_ticks, velocity_sequence_to_min_timespan
 import parameter_setter 
 import rhythm_parser 
 
@@ -35,7 +35,7 @@
 			self.string_to_note_sequence(noteSequenceString)
 
 	def string_to_note_sequence(self, noteSequenceString):
-		noteSequenceString = rhythm_parser.discardSpaces(noteSequenceString)
+		noteSequenceString = rhythm_parser.discard_spaces(noteSequenceString)
 		# try:
 			# Turning "(1,2,3),(4,5,6),(7,8,9)" into ["1,2,3","4,5,6,","7,8,9"]
 		listStrings = noteSequenceString[1:-1].split("),(")
@@ -50,15 +50,18 @@
 
 # VelocitySequence is a list of float numbers
 class VelocitySequence(list):
-	def __init__(self, velocitySequenceString = None):
-		if velocitySequenceString != None:
-			self.string_to_velocity_sequence(velocitySequenceString)
+	def __init__(self, velocitySequence = None):
+		if velocitySequence != None:
+			if isinstance(velocitySequence,basestring):
+				self.string_to_velocity_sequence(velocitySequence)
+			elif isinstance(velocitySequence, list):
+				self+=velocitySequence
 
 	def string_to_velocity_sequence(self,inputString):
 		self.extend(string_to_sequence(inputString))
 
 	def to_string(self):
-		return str(self)[1:-1].replace(" ","")
+		return str(velocity_sequence_to_min_timespan(self))[1:-1].replace(" ","")
 
 
 def velocity_sequence_to_note_sequence(velocitySequence, nextbarVelocitySequence = None):
@@ -112,7 +115,7 @@
 		velocitySequence += [0]*(noteSequence[-1].duration-1)
 
 	# normalising velocity sequence between 0-1
-	velocitySequence = [float(v)/max(velocitySequence) for v in velocitySequence]
+	velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence])
 
 	return velocitySequence
 
@@ -124,6 +127,12 @@
 			self[-1].set_next_bar(bar)
 		super(BarList, self).append(bar)
 
+	def concat(self, barList):
+		while(len(barList)!=0):
+			localbar = barList[0]
+			self.append(localbar)
+			barList.remove(localbar)
+
 
 class Bar:
 	def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None):
@@ -181,6 +190,13 @@
 	def get_bar_ticks(self):
 		return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq)
 
+	def to_string(self, sequenceType=None):
+		if sequenceType==None or sequenceType=="v":
+			output = "v{"+self.get_velocity_sequence().to_string()+"}"
+		else:
+			output = "y{"+self.get_note_sequence().to_string()+"}"
+		return output
+
 
 class TimeSignature():
 	def __init__(self, inputString):
--- a/Syncopation models/rhythm_parser.py	Sun Apr 12 22:34:35 2015 +0100
+++ b/Syncopation models/rhythm_parser.py	Sun Apr 12 22:37:56 2015 +0100
@@ -4,18 +4,18 @@
 '''
 
 # Parse the rhythm file and return a list of Bar objects
-Piece = []
+#Piece = []
 
 from parameter_setter import timeSignatureBase
-
+from music_objects import *
 
 comment_sign = '#'
-def discardComments(line):
+def discard_comments(line):
 	if comment_sign in line:
 		line = line[0:line.find(comment_sign)]
 	return line
 
-def discardSpaces(line):
+def discard_spaces(line):
 	line = line.replace(" ", '').replace("\t", '')
 	return line
 
@@ -29,78 +29,108 @@
 		print 'Rhythmic information needs to be enclosed by "{" and "}"'
 
 
-current_timesig = ''
-current_timesigValue = []
-def process(line):
-	try:
-		if 't' in line:
-			current_timesig = extractInfo(line)
-			if current_timesig in timesigBase:
-				current_timesigValue = timesigBase[current_timesig]
+
+def read_rhythm(fileName):
+	fileContent = file(fileName)
+
+	barList = BarList()
+
+	tempo=None
+	timeSignature=None
+	ticksPerQuarter=None
+
+	# for each line in the file, parse the line and add any 
+	# new bars to the main bar list for the piece
+	for line in fileContent:
+		
+		# ignore the line if it's only a comment
+		if is_comment(line) or line=="\n":
+			continue
+
+		# if time signature has not yet been set then it should be the first 
+		# thing we find in a file after the comments at the top
+		if timeSignature==None:
+			(field, line) = get_next_field(line)
+			# if there is a valid field, it should be a time signature
+			if field!=None:
+				[fieldname,value] = field
+				if fieldname=="t":
+					timeSignature = TimeSignature(value)
+				else:
+					print 'Error, first field in the file should set the time signature.'
+
+		# parse the line
+		(newbarlist, tempo, timeSignature, ticksPerQuarter) = parse_line(line, timeSignature,  tempo, ticksPerQuarter)
+		
+		# if we found some bars in this line then add them to the overall bar list
+		if len(newbarlist)>0:
+			barList.concat(newbarlist)
+
+	return barList
+
+def is_comment(line):
+	if discard_spaces(line)[0]=="#":
+		return True
+	else:
+		return False
+
+def parse_line(line,  timeSignature=None, tempo=None, ticksPerQuarter=None):
+	
+	#strip the line of spaces and comments
+	line = discard_spaces(discard_comments(line)).replace("\n","")
+	
+	bars = BarList()
+
+	#work through each field in the line
+	while len(line)>0:
+		(field, line) = get_next_field(line)
+
+		if field!=None:
+			
+			[fieldname, value] = field
+			
+			if fieldname.lower() == "v":
+				#velocity sequence
+				bar = Bar(VelocitySequence(value),timeSignature, ticksPerQuarter, tempo)	
+				bars.append(bar)
+
+			elif fieldname.lower() == "y":
+				#note sequence	
+				bar = Bar(NoteSequence(value), timeSignature, ticksPerQuarter, tempo)	
+				bars.append(bar)
+
+			elif fieldname.lower() == "t":
+				#time signature
+				timeSignature = TimeSignature(value)
+			
+			elif fieldname.lower() == "tpq":
+				#ticks per quarter
+				ticksPerQuarter = int(value)
+			
+			elif fieldname.lower() == "qpm":
+				#tempo
+				tempo = int(value)
+			
 			else:
-				raise NoTimesigError(current_timesig)
-		
-		elif 'v' in line:
-			if current_timesig == '':
-				raise InitialTimesigError(line)
-			else:
-				rhythmString = extractInfo(line)
-				rhythm_seq = map(int,rhythmString.split(','))
-				Piece.append(Bar(rhythm_seq, current_timesigValue[0], current_timesigValue[1]))
-		
-		else:
-			raise SymbolError(line)
+				print 'Unrecognised field type: "' + fieldname + '"'
 	
-	except InitialTimesigError:
-		print 'The initial time-signature is not given.'
-	except NoTimesigError:
-		print 'The time-signature is not recognised.'
-	except SymbolError:
-		print 'Unrecognised symbol.'
+	return bars, tempo, timeSignature, ticksPerQuarter
 
 
-def readRhythm(fileName):
-	try:
-		f = file(fileName)
-		
-		# Clean up each line by discarding comments and spaces; extract time-signature or sequence information
-		isfinished = False
-		while(not isfinished):
-			line = f.readline()
-			if len(line) == 0:
-				isfinished = True
-			else:
-				cleanline = discardSpaces(discardComments(line))
-				process(cleanline)
+def get_next_field(line):
+	index = line.find("}")
+	field = None
+	if index>=0:
+		fieldtext = line[:index]
+		line = line[index+1:]
+		field = fieldtext.split("{")
+	else:
+		print 'Error, incorrect syntax: "'+line+'"'
+		#raise RhythmSyntaxError(line)
 
-		# Extract time-signature and rhythm sequence information
+	return field,line
 
-	except IOError as e:
-		print "I/O error({0}): {1}".format(e.errno, e.strerror)
-	except:
-		print 'Unexpected error.'#, sys.exc_info()[0]
 
-# To check the 
-def isInfoValid(info):
-	# If two parts of information is not seperated by ;
-	# if 't' in info and 'q' in info:
-	# 	print 'Error: time-signature and rhythm sequence needs ";" to seperate. Please check this rhythm file: %s.' %fileName
-	# 	Piece = None
-	# 	break
-	# elif '{' not in info and '}' not in info:
-	# 	print 'Error: information needs to be enclosed by "{ }". Please check this rhythm file: %s.' %fileName
-	# 	Piece = None
-	# 	break				
-	# else:
-	return True			
 
-# To check whether the given time-signature is existed; if not then requires user to add in the new time-signature
-#def checkTimesig(input):
 
 
-# # TESTING
-# line = 't{4/4}	q{1,0,0,1,0,0,1,0,0,0,1,0,0.8,0,0,0} t{2/4} # This is a comment'
-# # print discardSpaces(discardComments(line))
-# print line[line.find('{')+1:line.find('}')]
-# #print readRhythm("rhythmbase/testrhythm.txt")
-
--- a/Syncopation models/rhythmbase/clave.txt	Sun Apr 12 22:34:35 2015 +0100
+++ b/Syncopation models/rhythmbase/clave.txt	Sun Apr 12 22:37:56 2015 +0100
@@ -1,3 +1,12 @@
-t{4/4};q{1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0}
-q{1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0}
-t{3/4};q{1,1,1}
\ No newline at end of file
+#this is a comment too
+
+t{4/4}qpm{100}v{1,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0} # this is a comment
+v{1,0,0,1,0,0, 1,0,0,0,1,0, 1,0,0,0}
+TPQ{1000}
+t{3/4}
+
+#this is a comment
+ v{1,1,1} qpm{120} v{1,0,1,0,1,0}
+
+
+ y{(1,2,3),(3,2,3),(4,2,2)}
\ No newline at end of file
--- a/Syncopation models/text_bnf_syntax.txt	Sun Apr 12 22:34:35 2015 +0100
+++ b/Syncopation models/text_bnf_syntax.txt	Sun Apr 12 22:37:56 2015 +0100
@@ -1,11 +1,15 @@
 
-<piece> ::=   <timesig> <line> | <piece> <line>
+<piece> ::=  [<comment-lines>] <timesig> <line> | <piece> <line>
+
+<comment-lines> ::= <comment> "\n" | <comment-lines> <comment> "\n"
 
 <tempo> ::= "QPM{" <digits> "}"
 
 <ticks per quarter> ::= "TPQ{" <digits> "}"
 
-<line> ::= [<barlist>] ["#" <comment-text>] "\n"
+<line> ::= [<barlist>] [<comment>] "\n"
+
+<comment> ::= "#" <comment-text>
 
 <barlist> ::= <time-info> | [<time-info>] <bar> | <barlist> <bar>