annotate Process/SymbolConversion.py @ 2:46fb79167a61 tip

Main Code
author Victor Padilla <victor.padilla.mc@gmail.com>
date Mon, 04 May 2015 22:56:18 +0200
parents
children
rev   line source
victor@2 1 '''
victor@2 2 Created on 10/11/2014
victor@2 3
victor@2 4 @organization: Lancaster University & University of Leeds
victor@2 5 @version: 1.0
victor@2 6 Created on 11/12/2014
victor@2 7
victor@2 8 @author: Victor Padilla
victor@2 9 @contact: v.padilla@lancaster.ac.uk
victor@2 10
victor@2 11 Functions related to convert music21 output
victor@2 12 to symbols for aligning and voting
victor@2 13 '''
victor@2 14 from music21 import note
victor@2 15 from music21 import chord
victor@2 16 from music21 import meter
victor@2 17 from music21 import key
victor@2 18 from music21 import stream
victor@2 19 from music21 import tie
victor@2 20 from music21 import bar
victor@2 21 from music21 import harmony
victor@2 22 from music21 import clef
victor@2 23 class SymbolConversion:
victor@2 24
victor@2 25
victor@2 26 def __getSymbolMesure(self,symbol):
victor@2 27 '''
victor@2 28 Detects if it is a barline symbol and gets the first element
victor@2 29 '''
victor@2 30 if isinstance(symbol,list):
victor@2 31 if symbol[0].find('!')!=-1:
victor@2 32 return symbol
victor@2 33
victor@2 34 def convertM21(self,symbolArray):
victor@2 35 '''
victor@2 36 Converts one Array of symbols to music21
victor@2 37
victor@2 38 usage:
victor@2 39
victor@2 40 outVote=vote.vote(omr_symbolsAlign)
victor@2 41 #apply voices if it is needed
victor@2 42
victor@2 43 outVote=sc.setVoices(outVote)
victor@2 44 #convert to music21
victor@2 45 resultS2=sc.convertM21(outVote)
victor@2 46
victor@2 47 '''
victor@2 48
victor@2 49 sOut=stream.Score()
victor@2 50 sPart=stream.Part()
victor@2 51 measureIndex=1
victor@2 52 measure=stream.Measure()
victor@2 53 measure.number=measureIndex
victor@2 54 voicesLength=8
victor@2 55 for v in range(voicesLength):
victor@2 56 voice=stream.Voice()
victor@2 57 voice.id=v
victor@2 58 measure.append(voice)
victor@2 59 indexS=0
victor@2 60
victor@2 61 for symbol in symbolArray:
victor@2 62 mytie=""
victor@2 63 realDuration=None
victor@2 64 s=symbol
victor@2 65
victor@2 66 if isinstance(s,list):
victor@2 67 s=s[0]
victor@2 68 if s.find('TS:')!=-1:
victor@2 69 ts=meter.TimeSignature(s[3:])
victor@2 70
victor@2 71 measure.append(ts)
victor@2 72 if s.find('KS:')!=-1:
victor@2 73 k=key.KeySignature(int(s[3:]))
victor@2 74
victor@2 75 measure.append(k)
victor@2 76 if s.find('CL:')!=-1:
victor@2 77 c=clef.clefFromString(str(s[3:]))
victor@2 78
victor@2 79 measure.append(c)
victor@2 80 if s.find('N:')!=-1:
victor@2 81 try:
victor@2 82 if isinstance(symbol,list):
victor@2 83 realDuration=symbol[1]
victor@2 84 mytie=symbol[2]
victor@2 85
victor@2 86 sep=s.index("_")
victor@2 87 duration=s[sep+1:]
victor@2 88 #*************************************
victor@2 89 #duration vs realDuration for triplets
victor@2 90 if realDuration!=None:
victor@2 91 duration=realDuration
victor@2 92 #*************************************
victor@2 93 if(float(duration)>0):
victor@2 94 n=note.Note(s[2:sep],quarterLength=float(duration))
victor@2 95 if symbol[5]!=None:
victor@2 96 n.color=symbol[5]
victor@2 97 if mytie!="":
victor@2 98 n.tie=tie.Tie(mytie)
victor@2 99 if len(symbol)>6:#voices
victor@2 100 measure.voices[symbol[6]].append(n)
victor@2 101 else:
victor@2 102 measure.append(n)
victor@2 103 except:
victor@2 104 print "error"+s
victor@2 105
victor@2 106 if s.find('R:')!=-1:
victor@2 107 try:
victor@2 108 if isinstance(symbol,list):
victor@2 109 realDuration=symbol[1]
victor@2 110 mytie=symbol[2]
victor@2 111 duration=s[2:]
victor@2 112 #*************************************
victor@2 113 #duration vs realDuration for triplets
victor@2 114 if realDuration!=None:
victor@2 115 duration=realDuration
victor@2 116 #*************************************
victor@2 117 n=note.Rest(quarterLength=float(duration))
victor@2 118 if symbol[5]!=None:
victor@2 119 n.color=symbol[5]
victor@2 120 if len(symbol)>6:#voices
victor@2 121 measure.voices[symbol[6]].append(n)
victor@2 122 else:
victor@2 123 measure.append(n)
victor@2 124 except:
victor@2 125 print "error"+s
victor@2 126
victor@2 127 if s.find('C:')!=-1:
victor@2 128 notes=s.split("[:")
victor@2 129 cPitch=[]
victor@2 130 for n in notes:
victor@2 131 if n!='C:':
victor@2 132 sep=n.index("_")
victor@2 133 duration=n[sep+1:]
victor@2 134 pitch= n[0:sep]
victor@2 135 cPitch.append(pitch)
victor@2 136 c=chord.Chord(cPitch)
victor@2 137 c.duration.quarterLength=float(duration)
victor@2 138 if symbol[5]!=None:
victor@2 139 c.color=symbol[5]
victor@2 140 if mytie!="":
victor@2 141 c.tie=tie.Tie(mytie)
victor@2 142
victor@2 143 if len(symbol)>6:#voices
victor@2 144 measure.voices[symbol[6]].append(c)
victor@2 145 else:
victor@2 146 measure.append(c)
victor@2 147
victor@2 148 if s.find('!')!=-1:
victor@2 149 if isinstance(symbol,list):
victor@2 150 barType= symbol[1]
victor@2 151 barRepeat= symbol[2]
victor@2 152 if barType!="":
victor@2 153 try:
victor@2 154 mybartype=bar.styleToMusicXMLBarStyle(barType)
victor@2 155 myBar=bar.Barline(style=mybartype)
victor@2 156 measure.rightBarline=myBar
victor@2 157 except:
victor@2 158 print "error barline"
victor@2 159
victor@2 160 if barRepeat!="":
victor@2 161 try:
victor@2 162 myBar=bar.Repeat(direction=barRepeat)
victor@2 163 if barRepeat=="start":
victor@2 164 measure.leftBarline=myBar
victor@2 165 if barRepeat=="end":
victor@2 166 measure.rightBarline=myBar
victor@2 167 except:
victor@2 168 print "error barline"
victor@2 169 sPart.append(measure)
victor@2 170 measureIndex+=1
victor@2 171 measure=stream.Measure()
victor@2 172 measure.number=measureIndex
victor@2 173 for v in range(voicesLength):
victor@2 174 voice=stream.Voice()
victor@2 175 voice.id=v
victor@2 176 measure.append(voice)
victor@2 177
victor@2 178 indexS+=1
victor@2 179
victor@2 180 sOut.append(sPart)
victor@2 181 return sOut
victor@2 182
victor@2 183
victor@2 184
victor@2 185
victor@2 186 def __orderChord(self,mychord):
victor@2 187 '''
victor@2 188 Private function that returns a chord ordered
victor@2 189 in a string from lower to higher
victor@2 190 '''
victor@2 191 midi=[]
victor@2 192 midi2=[]
victor@2 193 orderC=[]
victor@2 194 for n in mychord:
victor@2 195 if isinstance(n,note.Note):
victor@2 196 midi.append(n.midi)
victor@2 197 midi2.append(n.midi)
victor@2 198
victor@2 199 while len(midi)>0:
victor@2 200 indexMin=midi2.index(min(midi))
victor@2 201 indexPop=midi.index(min(midi))
victor@2 202 orderC.append(mychord[indexMin])
victor@2 203 midi.pop(indexPop)
victor@2 204
victor@2 205 myOrderChord=chord.Chord(orderC)
victor@2 206 myOrderChord.duration.quarterLength=mychord.duration.quarterLength
victor@2 207 return myOrderChord
victor@2 208
victor@2 209
victor@2 210 def __getKeyOffset(self,item):
victor@2 211 '''
victor@2 212 Private function that returns the offset of one item
victor@2 213 '''
victor@2 214 return item['offset']
victor@2 215
victor@2 216 def __removeDuplicates(self,input_raw):
victor@2 217 '''
victor@2 218 Private function to remove duplicates in the string input
victor@2 219 '''
victor@2 220 seen = set()
victor@2 221 new_l = []
victor@2 222 for d in input_raw:
victor@2 223 t = tuple(d.items())
victor@2 224 if t not in seen:
victor@2 225 seen.add(t)
victor@2 226 new_l.append(d)
victor@2 227
victor@2 228 return new_l
victor@2 229
victor@2 230
victor@2 231 def getElementsFromMeasureOrderByOffset(self,measure):
victor@2 232 '''
victor@2 233 Returns the symbols of a measure ordered by offset
victor@2 234 '''
victor@2 235 offset=measure.flat.offsetMap
victor@2 236 offset_n=self.__removeDuplicates(offset)
victor@2 237 sorted_offset=sorted(offset_n,key=self.__getKeyOffset)
victor@2 238 return sorted_offset
victor@2 239
victor@2 240 def __swapSymbols(self,s1,s2):
victor@2 241 '''
victor@2 242 Swap the s1,s2 symbols
victor@2 243 '''
victor@2 244 inter=s1
victor@2 245 s1=s2
victor@2 246 s2=inter
victor@2 247 return s1,s2
victor@2 248
victor@2 249 def orderSymbolsByPitch(self,symbols):
victor@2 250 '''
victor@2 251 Orders the symbol string from lower to high if they have
victor@2 252 the same offset
victor@2 253 '''
victor@2 254 for i in range(len(symbols)-1):
victor@2 255 for j in range(i,i+2):
victor@2 256 pitch_i=0
victor@2 257 pitch_j=0
victor@2 258 if(symbols[i]['offset']==symbols[j]['offset']):
victor@2 259 if isinstance(symbols[i]['element'],note.Note):
victor@2 260 pitch_i=symbols[i]['element'].pitch.midi
victor@2 261 if isinstance(symbols[j]['element'],note.Note):
victor@2 262 pitch_j=symbols[j]['element'].pitch.midi
victor@2 263
victor@2 264 if pitch_j>pitch_i:#higher pitch first
victor@2 265 symbols[i],symbols[j]=self.__swapSymbols(symbols[i],symbols[j])
victor@2 266
victor@2 267 if pitch_j==pitch_i and pitch_j>0:#longest first if equal pitch
victor@2 268 if symbols[i]['element'].duration<symbols[j]['element'].duration:
victor@2 269 symbols[i],symbols[j]=self.__swapSymbols(symbols[i],symbols[j])
victor@2 270
victor@2 271 if isinstance(symbols[j]['element'],note.Rest):#rest first
victor@2 272 symbols[i],symbols[j]=self.__swapSymbols(symbols[i],symbols[j])
victor@2 273
victor@2 274 return symbols
victor@2 275
victor@2 276 def getRepetitionMarks(self,measure):
victor@2 277 '''
victor@2 278 Returns the repetition marks symbol from a measure
victor@2 279 '''
victor@2 280 symbols=[]
victor@2 281 for barline in measure.getElementsByClass(bar.Barline):
victor@2 282 symbol={'voiceIndex': None, 'element': barline, 'endTime': 0.0, 'offset': barline.offset}
victor@2 283 symbols.append(symbol)
victor@2 284 return symbols
victor@2 285
victor@2 286 def getTS(self,measure):
victor@2 287 '''
victor@2 288 Returns the time signature symbol from a measure
victor@2 289 '''
victor@2 290 symbols=[]
victor@2 291 for ts in measure.getElementsByClass(meter.TimeSignature):
victor@2 292 symbol={'voiceIndex': None, 'element': ts, 'endTime': 0.0, 'offset': ts.offset}
victor@2 293 symbols.append(symbol)
victor@2 294 return symbols
victor@2 295
victor@2 296 def removeTS(self,symbols):
victor@2 297 '''
victor@2 298 Removes the time signature from the symbols array
victor@2 299 '''
victor@2 300 for symbol in symbols:
victor@2 301 s=symbol['element']
victor@2 302 if 'TimeSignature' in s.classes:
victor@2 303 symbols.pop(symbols.index(symbol))
victor@2 304 break
victor@2 305 return symbols
victor@2 306
victor@2 307 def filterOMR(self,omr,idPart):
victor@2 308 '''
victor@2 309 Removes elements from the music21 input as text, slurs and expressions (p, mp, f...)
victor@2 310
victor@2 311 Returns the omr filtered and the symbols array converted
victor@2 312
victor@2 313 '''
victor@2 314 omr_filtered=stream.Stream()
victor@2 315 omr_symbols=[]
victor@2 316 #for single parts
victor@2 317 print "Partes=",len(omr.parts)
victor@2 318 if len(omr.parts)==1:
victor@2 319 idPart=0
victor@2 320 if len(omr.parts)==0:
victor@2 321 idPart=0
victor@2 322 mypart=omr
victor@2 323 if len(omr.parts)>=1:
victor@2 324 if(int(idPart)>=len(omr.parts)):
victor@2 325 print "error in OMR"
victor@2 326 return [],[]
victor@2 327 mypart=omr.parts[int(idPart)]
victor@2 328
victor@2 329
victor@2 330
victor@2 331 isFirstClef=True
victor@2 332 indexMes=0
victor@2 333 print idPart
victor@2 334 for measure in mypart.getElementsByClass(stream.Measure):
victor@2 335 indexMes+=1
victor@2 336 symbols=self.getElementsFromMeasureOrderByOffset(measure.semiFlat)#key signature time signature and clef are missing if not flat
victor@2 337 symbols=self.orderSymbolsByPitch(symbols)
victor@2 338 symbolsRepetition=self.getRepetitionMarks(measure)
victor@2 339 symbolsTS=self.getTS(measure)
victor@2 340 symbols=self.removeTS(symbols)
victor@2 341 symbols=symbolsTS+symbols+symbolsRepetition
victor@2 342
victor@2 343 newMeasure=stream.Measure()
victor@2 344 styleBarline=""
victor@2 345 directionRepeat=""
victor@2 346 strClef=""
victor@2 347
victor@2 348 for symbol in symbols:
victor@2 349 #symbol={'voiceIndex': 0, 'element': <music21.note.Note C>, 'endTime': 1.0, 'offset': 0.0}
victor@2 350 s=symbol['element']
victor@2 351 if 'TimeSignature' in s.classes:
victor@2 352 newMeasure.append(s)
victor@2 353 str0="TS:"+str(s.numerator)+"/"+str(s.denominator)
victor@2 354 omr_symbols.append([str0,None,None,symbol['offset'],symbol['endTime'],None])
victor@2 355
victor@2 356 elif 'KeySignature' in s.classes:
victor@2 357 newMeasure.append(s)
victor@2 358 str0="KS:"+str(s.sharps)
victor@2 359 omr_symbols.append([str0,None,None,symbol['offset'],symbol['endTime'],None])
victor@2 360
victor@2 361 elif 'Clef' in s.classes:
victor@2 362 newMeasure.append(s)
victor@2 363 strClef="CL:"+str(s.sign)
victor@2 364 if isFirstClef:
victor@2 365 omr_symbols.append([strClef,None,None,symbol['offset'],symbol['endTime'],None])
victor@2 366 strClef=""
victor@2 367 isFirstClef=False
victor@2 368
victor@2 369 elif 'Note' in s.classes:
victor@2 370 newMeasure.append(s)
victor@2 371 mytype=s.duration.type
victor@2 372 duration=note.duration.convertTypeToQuarterLength(mytype)
victor@2 373 realDuration=s.duration.quarterLength
victor@2 374 if realDuration==duration+duration/2: #dot case
victor@2 375 duration=realDuration
victor@2 376 n="N:"+s.pitch.nameWithOctave+"_"+str(duration)
victor@2 377 # Ties case
victor@2 378 mytie=""
victor@2 379 if s.tie!=None:
victor@2 380 mytie=s.tie.type
victor@2 381
victor@2 382 if float(realDuration)>0:
victor@2 383 omr_symbols.append([n,realDuration,mytie,symbol['offset'],symbol['endTime'],s.color] )
victor@2 384
victor@2 385 elif 'Rest' in s.classes:
victor@2 386 newMeasure.append(s)
victor@2 387 mytype=s.duration.type
victor@2 388 if mytype!="complex":
victor@2 389 duration=note.duration.convertTypeToQuarterLength(mytype)
victor@2 390 else:
victor@2 391 duration=s.duration.quarterLength
victor@2 392 realDuration=s.duration.quarterLength
victor@2 393 if realDuration==duration+duration/2: #dot case
victor@2 394 duration=realDuration
victor@2 395 n="R:"+str(duration)
victor@2 396 # realDuration=s.duration.quarterLength
victor@2 397 omr_symbols.append([n,realDuration,False,symbol['offset'],symbol['endTime'],s.color])
victor@2 398
victor@2 399 elif 'Chord' in s.classes:
victor@2 400 if type(s) is not harmony.ChordSymbol:
victor@2 401 newMeasure.append(s)
victor@2 402 mytype=s.duration.type
victor@2 403 duration=note.duration.convertTypeToQuarterLength(mytype)
victor@2 404 realDuration=s.duration.quarterLength
victor@2 405 if realDuration==duration+duration/2: #dot case
victor@2 406 duration=realDuration
victor@2 407 chord="C:"
victor@2 408 sOrder=self.__orderChord(s)
victor@2 409 for n in sOrder:
victor@2 410 chord+="[:"+n.pitch.nameWithOctave+"_"+str(duration)
victor@2 411
victor@2 412
victor@2 413
victor@2 414 # Ties case
victor@2 415 mytie=""
victor@2 416 if s.tie!=None:
victor@2 417 mytie=s.tie.type
victor@2 418 omr_symbols.append([chord,realDuration,mytie,symbol['offset'],symbol['endTime'],s.color])
victor@2 419
victor@2 420 elif 'Barline' in s.classes:
victor@2 421 styleBarline=s.style
victor@2 422 try:
victor@2 423 directionRepeat=s.direction
victor@2 424 except:
victor@2 425 directionRepeat=""
victor@2 426
victor@2 427
victor@2 428 omr_symbols.append(['!',styleBarline,directionRepeat,symbol['offset'],symbol['endTime'],None])
victor@2 429 if strClef!="":
victor@2 430 omr_symbols.append([strClef,None,None,0,0,None])
victor@2 431 omr_filtered.append(newMeasure)
victor@2 432 return omr_filtered,omr_symbols
victor@2 433
victor@2 434 def removeExtraTies(self,arraySymbols):
victor@2 435 '''
victor@2 436 Removes the non logical ties from the symbol array
victor@2 437
victor@2 438 '''
victor@2 439 for s in arraySymbols:
victor@2 440 if isinstance(s,list):
victor@2 441 mainSymbol=s[0]
victor@2 442 if mainSymbol.find('N:')!=-1:
victor@2 443 tie1=s[2]
victor@2 444 if arraySymbols.index(s)<len(arraySymbols):
victor@2 445 sNext=arraySymbols[arraySymbols.index(s)+1]
victor@2 446 if isinstance(sNext,list):
victor@2 447 mainSymbol2=sNext[0]
victor@2 448 if mainSymbol2.find('N:')!=-1:
victor@2 449 tie2=sNext[2]
victor@2 450 if tie1=='start' and tie2!='end':
victor@2 451 s[2]=''
victor@2 452
victor@2 453 return arraySymbols
victor@2 454
victor@2 455
victor@2 456 def setVoices(self,strSymbols):
victor@2 457 '''
victor@2 458 Divides each measure in voices, if it is necessary.
victor@2 459
victor@2 460 The output is the symbol string using voices
victor@2 461
victor@2 462 '''
victor@2 463 quarters=self.__getTimeSignatureQuarters(strSymbols)
victor@2 464 measures=self.__chopMeasures(strSymbols)
victor@2 465 newString=[]
victor@2 466 for measure in measures:
victor@2 467 newMeasure=self.divideMeasureinVoices(measure,quarters)
victor@2 468 for s in newMeasure:
victor@2 469 newString.append(s)
victor@2 470 return newString
victor@2 471
victor@2 472 def __getTimeSignatureQuarters(self,strSymbols):
victor@2 473 '''
victor@2 474 returns the number of quarters of the first time signature found
victor@2 475 '''
victor@2 476 quarters=4 #4/4 by default
victor@2 477 for s in strSymbols:
victor@2 478 if isinstance(s,list):
victor@2 479 s=s[0]
victor@2 480 if s.find('TS:')!=-1:
victor@2 481 ts=s[3:]
victor@2 482 timeSig=ts.split("/")
victor@2 483 num=int(timeSig[0])
victor@2 484 den=int(timeSig[1])
victor@2 485 quarters=(4/den)*num
victor@2 486 return quarters
victor@2 487
victor@2 488 def __chopMeasures(self,strSymbols):
victor@2 489 '''
victor@2 490 Divides the symbol string in measures
victor@2 491 '''
victor@2 492 strMeasures=[]
victor@2 493 strMeasure=[]
victor@2 494 for s in strSymbols:
victor@2 495 strMeasure.append(s)
victor@2 496 bar=self.__getSymbolMesure(s)
victor@2 497 if bar!=None:
victor@2 498 strMeasures.append(strMeasure)
victor@2 499 strMeasure=[]
victor@2 500 return strMeasures
victor@2 501
victor@2 502
victor@2 503 def isNoteRest(self,symbol):
victor@2 504 '''
victor@2 505 Returns true if the symbol is note, rest or chord
victor@2 506 '''
victor@2 507 s=symbol
victor@2 508 if isinstance(s,list):
victor@2 509 if s[0].find('N:')!=-1:
victor@2 510 return True
victor@2 511 if s[0].find('R:')!=-1:
victor@2 512 return True
victor@2 513 if s[0].find('C:')!=-1:
victor@2 514 return True
victor@2 515 return False
victor@2 516 return False
victor@2 517
victor@2 518 def divideMeasureinVoices(self,strMeasure,quarters):
victor@2 519 '''
victor@2 520 If the length of each measure in the string is higher than quarters,
victor@2 521 adjusting to voices
victor@2 522
victor@2 523 '''
victor@2 524 newMeasure=[]
victor@2 525 duration=0
victor@2 526 #if duration is higher than time signatura
victor@2 527 for s in strMeasure:
victor@2 528 if self.isNoteRest(s):
victor@2 529 if s[1]!=None:
victor@2 530 try:
victor@2 531 duration+=s[1]
victor@2 532 except:
victor@2 533 pass
victor@2 534 # voices only if needed
victor@2 535 if duration<=quarters:
victor@2 536 return strMeasure
victor@2 537
victor@2 538
victor@2 539 for s in strMeasure:
victor@2 540 if not self.isNoteRest(s):
victor@2 541 if self.__getSymbolMesure(s)==None:
victor@2 542 newMeasure.append(s)
victor@2 543 voiceslength=8
victor@2 544 for v in range(voiceslength-1):
victor@2 545 offset=0.0
victor@2 546 firstNote=False
victor@2 547 for s in strMeasure:
victor@2 548 if self.isNoteRest(s):
victor@2 549 if len(s)<7:#not voice yet
victor@2 550 offsetNote=s[3]
victor@2 551 if firstNote==False:
victor@2 552 offset=offsetNote
victor@2 553 firstNote=True
victor@2 554 if offsetNote>0:
victor@2 555 rest=[]
victor@2 556 rest.append("R:"+str(offsetNote))
victor@2 557 rest.append(offsetNote)
victor@2 558 rest.append(False)
victor@2 559 rest.append(0)
victor@2 560 rest.append(offsetNote)
victor@2 561 rest.append(None)
victor@2 562 rest.append(v)
victor@2 563 newMeasure.append(rest)
victor@2 564 if(offset==offsetNote):
victor@2 565 s.append(v)
victor@2 566 newMeasure.append(s)
victor@2 567 offset=s[4]
victor@2 568
victor@2 569
victor@2 570 for s in strMeasure:
victor@2 571 if self.__getSymbolMesure(s)!=None:
victor@2 572 newMeasure.append(s)
victor@2 573
victor@2 574
victor@2 575 return newMeasure