diff --git a/Field_D_SupportingClasses.py b/Field_D_SupportingClasses.py
index f89690e..08b86eb 100644
--- a/Field_D_SupportingClasses.py
+++ b/Field_D_SupportingClasses.py
@@ -5,6 +5,8 @@
# check out www.github.com/dan-field/Text2SATB for info and rights #
####################################################################
+import prompt
+import lxml.etree as tree
class DF_Syllables:
def __init__(self):
@@ -45,8 +47,7 @@ def b(self, word):
adjusted_ending = self.breakDownFromBack(rest, ending)
adjusted_endLength = 0
for syllable in adjusted_ending:
- for letter in syllable:
- adjusted_endLength += 1
+ adjusted_endLength = len(syllable)
if adjusted_endLength > endLength:
rest = rest[:len(rest)+endLength-adjusted_endLength]
restBrokenDown = self.r(rest)
@@ -149,7 +150,7 @@ def breakDownFromBack(self, word, suffix):
# now check for 'e' endings (on the whole word, or the word with suffix removed, as applicable)
if w[-1] == "e": # last letter is 'e'
if w[-2] not in self.vowels and w[-3] in self.vowels_y: # second-last is consonant and third-last is vowel
- ending = word[-3]+word[-2]+word[-1] # this is a Vowel-Consonant-e ending
+
if w[-4] not in self.vowels and len(w) == 4: # it's cons-vowel-cons-'e' so it's a single syllable (note the 'le' ending has already been dealt with in the 'searchSuffix' function)
if suffix == "":
return [word]
@@ -456,20 +457,24 @@ def __init__(self):
lineText = []
inputText = []
infile = None
- usrFileName = raw_input("please enter the filename of the text input file, e.g. 'mypoem.txt'\n: ")
- try:
- infile = open(usrFileName, "r")
- except (OSError, IOError):
- infile = None
- print "\nThere was an issue attempting to open the file."
- print "Please double-check your filename; "+usrFileName+"\n"
- print "Note your input text file must be in the same"
- print "folder as the Python files."
- return
+
+ while infile is None:
+ usrFileName = prompt.string("please enter the filename of the text input file, e.g. 'mypoem.txt': ")
+
+ try:
+ infile = open(usrFileName, "r")
+ except (OSError, IOError):
+ infile = None
+ print("\nThere was an issue attempting to open the file.")
+ print("Please double-check your filename; "+usrFileName+"\n")
+ print("Note your input text file must be in the same")
+ print("folder as the Python files.")
+
if infile is not None:
for line in infile.readlines():
inputText.append(line)
infile.close()
+
# The input file has been read, and all of the text is in 'inputText'
lineText.append("---BREAK---") # this will be used to signify a new verse
noted = True # this is a flag to avoid multiple 'new verse' indications in a row
@@ -526,11 +531,11 @@ def __init__(self):
syllables[-1] = syllables[-1]+punctuation # add the punctuation back on where it came from
if punctuation in ".;:!?*": # these punctuation marks will create new lines
self.lastWord = True # this will be the last word in this line
- positions = range(len(syllables)) # start an 'empty' list with as many members as there are syllables in the word
+ positions = list(range(len(syllables))) # start an 'empty' list with as many members as there are syllables in the word
if len(positions) == 1: # this means there's only one syllable in the word
positions[0] = "single" # this follows the MusicXML 'syllabic' convention
else: # there are two or more syllables in the word
- for index, position in enumerate(positions):
+ for index, _ in enumerate(positions):
if index == 0: # first syllable
positions[index] = "begin"
elif index == len(positions)-1: # last syllable
@@ -553,13 +558,13 @@ def provideScrabbleScores(self):
return self.scrabbleScores
def provideTitle(self):
- usrTitle = raw_input("please enter a Title for the work\n: ")
+ usrTitle = prompt.string("please enter a Title for the work: ")
if usrTitle == "":
usrTitle = None
return usrTitle
def provideLyricist(self):
- usrLyricist = raw_input("please enter the Lyricist's name\n: ")
+ usrLyricist = prompt.string("please enter the Lyricist's name: ")
if usrLyricist == "":
usrLyricist = None
return usrLyricist
@@ -627,7 +632,7 @@ def __init__(self, verses, positions, scores):
def planHarmonicStructure(self):
# looks at the incoming verse structure and generates a chord sequence
# Try to keep the chord references numeric/relative for easy adaptation
- key = 0 # number zero will represent the 'home' key
+
verseKey = 0
verseKeys = []
lineKey = 0
@@ -646,7 +651,7 @@ def planHarmonicStructure(self):
# but if there are more than 240 syllables, it goes back to zero and starts over again
verseKey += keyshift
verseKeys.append(verseKey)
- for i, line in enumerate(verse): # similarly, we might change key from line to line using the same sort of logic
+ for i, _ in enumerate(verse): # similarly, we might change key from line to line using the same sort of logic
if i == 0: # first line
lineKey = verseKey # first line of each verse is in the verse's key
elif index == len(self.verses)-1 and i == len(self.verses[index])-1: # this is the last line of the last verse
@@ -671,7 +676,7 @@ def determineChordSequence(self):
for i, line in enumerate(verse):
chordBase[index].append([])
chordType[index].append([])
- for j, syllable in enumerate(line):
+ for j, _ in enumerate(line):
cycleMove = 0
chordComplexity = 0
# we want to set a chord degree and type that reflects the Scrabble score of the word
@@ -811,7 +816,7 @@ def getBassPart(self, homeKey):
count = 0
barNo = -1
for i, line in enumerate(verse):
- for j, syllable in enumerate(line):
+ for j, _ in enumerate(line):
keyRef = self.chordPlan[index][i]
chordDegree = self.chordBase[index][i][j] # this is just the step number - it needs to be converted to a chromatic degree number
chordDegree = self.convertChordDegree(chordDegree)
@@ -828,7 +833,7 @@ def getBassPart(self, homeKey):
differences = [abs(loose_target - float(note)) for note in bassTargets]
closest = differences.index(min(differences))
thisNote = bassTargets[closest] # pick the bass note that is closest to the comfortable mid point
- thisDuration = 4
+
# we have all the info we need to start assembling the Bass part
if count%16 == 0: # the previous bar is full
bassNotes[index].append([])
@@ -842,7 +847,6 @@ def getBassPart(self, homeKey):
bassPositions[index][barNo].append(self.positions[index][i][j])
if len(self.durations[index][i][j]) == 1: # the note does not cross a barline
L = self.durations[index][i][j][0]
- R = self.sylRests[index][i][j][0]
bassRhythms[index][barNo].append(L)
bassTies[index][barNo].append(None)
count += L
@@ -895,7 +899,7 @@ def getTenorPart(self, homeKey):
count = 0
barNo = -1
for i, line in enumerate(verse):
- for j, syllable in enumerate(line):
+ for j, _ in enumerate(line):
keyRef = self.chordPlan[index][i]
chordDegree = self.chordBase[index][i][j] # this is just the step number - it needs to be converted to a chromatic degree number
chordDegree = self.convertChordDegree(chordDegree)
@@ -914,7 +918,7 @@ def getTenorPart(self, homeKey):
differences = [abs(loose_target - float(note)) for note in tenTargets]
closest = differences.index(min(differences))
thisNote = tenTargets[closest] # pick the tenor note that is closest to the comfortable mid point
- thisDuration = 4
+
# we have all the info we need to start assembling the Tenor part
if count%16 == 0: # the previous bar is full
tenNotes[index].append([])
@@ -1030,7 +1034,7 @@ def getAltoPart(self, homeKey):
count = 0
barNo = -1
for i, line in enumerate(verse):
- for j, syllable in enumerate(line):
+ for j, _ in enumerate(line):
keyRef = self.chordPlan[index][i]
chordDegree = self.chordBase[index][i][j] # this is just the step number - it needs to be converted to a chromatic degree number
chordDegree = self.convertChordDegree(chordDegree)
@@ -1049,7 +1053,7 @@ def getAltoPart(self, homeKey):
differences = [abs(loose_target - float(note)) for note in altoTargets]
closest = differences.index(min(differences))
thisNote = altoTargets[closest] # pick the alto note that is closest to the comfortable mid point
- thisDuration = 4
+
# we have all the info we need to start assembling the Alto part
if count%16 == 0: # the previous bar is full
altoNotes[index].append([])
@@ -1189,9 +1193,7 @@ def getSopPart(self, homeKey):
shiftedScale = []
for note in scale:
shiftedScale.append(homeKey+keyRef+note)
- sopScaleTargets = self.buildFullRange(shiftedScale, self.rangeSop[0], self.rangeSop[1])
- if i == len(verse)-1 and j == len(line)-1:
- sopScaleTargets = sopChordTargets
+
# LOOSE TARGET needs to be modified so that it's a melody note -------------------------------
loose_target = 70.4 # seek out a comfortable mid-point in the soprano range
if chordType == 0:
@@ -1201,7 +1203,7 @@ def getSopPart(self, homeKey):
differences = [abs(loose_target - float(note)) for note in sopChordTargets]
closest = differences.index(min(differences))
thisNote = sopChordTargets[closest] # pick the soprano note that is closest to the comfortable mid point
- thisDuration = 4
+
# we have all the info we need to start assembling the Soprano part
if count%16 == 0: # the previous bar is full
sopNotes[index].append([])
@@ -1268,7 +1270,6 @@ def getSopPart(self, homeKey):
self.sopLatestNote = thisNote
else:
L = self.durations[index][i][j][0]
- R = self.sylRests[index][i][j][0]
sopRhythms[index][barNo].append(L)
sopTies[index][barNo].append(None)
sopNotes[index][barNo].append(thisNote)
@@ -1324,9 +1325,7 @@ def getLinesAndSyllables(self, verses):
for verse in verses:
resultVerse = []
for line in verse:
- syllableCount = 0
- for syllable in line:
- syllableCount += 1
+ syllableCount = len(line)
resultVerse.append(syllableCount)
resultSong.append(resultVerse)
return resultSong
@@ -1587,325 +1586,244 @@ def __init__(self, usrTitle=None, progID=None, usrAuthor=None):
self.measureNo = 0
self.voice = 1 # 1 Soprano, 2 Alto, 3 Tenor, 4 Bass
self.flats = True # assumes black notes should be written as flats - will need to be updated once a 'key' functionality is added
- usrFileName = raw_input("please enter a name for the output file\n: ")
+ usrFileName = prompt.string("please enter a name for the output file: ")
self.fileName = usrFileName+".musicxml"
- try:
- self.file = open(self.fileName, "w")
- except (OSError, IOError):
- self.file = None
- print "\nThere was an issue with the file operation."
- print "Please double-check your filename.\n"
- print "Note the MusicXML file will attempt to save in the"
- print "same folder as the Python files; please ensure you"
- print "have write permission for that folder."
- return
- self.file.write('\n')
- self.file.write('\n')
- self.file.write('\n')
- self.file.write(' \n')
- self.file.write(' '+str(self.Title)+'\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' '+str(self.progID)+'\n')
- self.file.write(' '+str(self.Author)+'\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' Soprano\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' Alto\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' Tenor\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' Bass\n')
- self.file.write(' \n')
- self.file.write(' \n')
+
+ # building up the xml tree
+ self.root = tree.Element('score-partwise', attrib={'version':'3.1'})
+ work = tree.SubElement(self.root, 'work')
+ tree.SubElement(work, 'work-title').text = self.Title
+
+ # author
+ ident = tree.SubElement(self.root,'identification')
+ tree.SubElement(ident, 'creator', attrib={'type':'composer'}).text = self.progID
+ tree.SubElement(ident, 'creator', attrib={'type':'lyricist'}).text = self.Author
+
+ # part list
+ part_list = tree.SubElement(self.root, 'part-list')
+ score_info = {'P1':'Soprano', 'P2':'Alto', 'P3':'Tenor', 'P4':'Bass'}.items()
+ for score_id, score_type in score_info:
+ score_part = tree.SubElement(part_list, 'score-part', attrib={'id': score_id})
+ tree.SubElement(score_part, 'part-name').text = score_type
+
+ # this writes a section
+ # returns a tuple with the part and the current measure
+ def startSection(self, section):
+ if self.root is not None:
+
+ part_id = str(section['part_id'])
+ clef_sign = str(section['clef_sign'])
+ clef_line = str(section['clef_line'])
+
+ part = tree.SubElement(self.root, 'part', attrib={'id': part_id})
+ measure = tree.SubElement(part, 'measure', attrib={'number': str(self.measureNo)})
+ attributes = tree.SubElement(measure, 'attributes')
+ tree.SubElement(attributes, 'divisions').text = str(self.DIVISIONS)
+
+ key = tree.SubElement(attributes, 'key')
+ tree.SubElement(key, 'fifths').text = '-3'
+
+ time = tree.SubElement(attributes, 'time')
+ tree.SubElement(time, 'beats').text = '4'
+ tree.SubElement(time, 'beat-type').text = '4'
+
+ clef = tree.SubElement(attributes, 'clef', attrib= {'number': '1'})
+ tree.SubElement(clef, 'sign').text = clef_sign
+ tree.SubElement(clef, 'line').text = clef_line
+
+ # tenors get an octave change?
+ if part_id == 'P3':
+ tree.SubElement(clef, 'clef-octave-change').text = '-1'
+
+ return (part, measure)
def startSoprano(self):
- if self.file is not None:
- self.measureNo = 0
- self.voice = 1
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' '+str(self.DIVISIONS)+'\n')
- self.file.write(' \n')
- self.file.write(' -3\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' G\n')
- self.file.write(' 2\n')
- self.file.write(' \n')
- self.file.write(' \n')
+ self.measureNo = 0
+ self.voice = 1
+
+ # writing the soprano elements to the xml tree
+ section = {}
+ section['part_id'] = 'P1'
+ section['clef_sign'] = 'G'
+ section['clef_line'] = '2'
+ return self.startSection(section)
+
def startAlto(self):
- if self.file is not None:
- self.measureNo = 0
- self.voice = 2
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' '+str(self.DIVISIONS)+'\n')
- self.file.write(' \n')
- self.file.write(' -3\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' G\n')
- self.file.write(' 2\n')
- self.file.write(' \n')
- self.file.write(' \n')
+ self.measureNo = 0
+ self.voice = 2
+
+ # writing the alto elements to the xml tree
+ section = {}
+ section['part_id'] = 'P2'
+ section['clef_sign'] = 'G'
+ section['clef_line'] = '2'
+ return self.startSection(section)
def startTenor(self):
- if self.file is not None:
- self.measureNo = 0
- self.voice = 3
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' '+str(self.DIVISIONS)+'\n')
- self.file.write(' \n')
- self.file.write(' -3\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' G\n')
- self.file.write(' 2\n')
- self.file.write(' -1\n')
- self.file.write(' \n')
- self.file.write(' \n')
+ self.measureNo = 0
+ self.voice = 3
+
+ # writing the tenor elements to the xml tree
+ section = {}
+ section['part_id'] = 'P3'
+ section['clef_sign'] = 'G'
+ section['clef_line'] = '2'
+ return self.startSection(section)
def startBass(self):
- if self.file is not None:
- self.measureNo = 0
- self.voice = 4
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' '+str(self.DIVISIONS)+'\n')
- self.file.write(' \n')
- self.file.write(' -3\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' F\n')
- self.file.write(' 4\n')
- self.file.write(' \n')
- self.file.write(' \n')
-
- def endPart(self):
- if self.file is not None:
- self.file.write(' \n')
- self.file.write(' light-heavy\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
+ self.measureNo = 0
+ self.voice = 4
+
+ # writing the bass elements to the xml tree
+ section = {}
+ section['part_id'] = 'P4'
+ section['clef_sign'] = 'F'
+ section['clef_line'] = '4'
+ return self.startSection(section)
+
+ def endPart(self, measure):
+ barline = tree.SubElement(measure, 'barline', attrib={'location': 'right'})
+ tree.SubElement(barline, 'bar-style').text = 'light-heavy'
def endXMLFile(self):
- if self.file is not None:
- self.file.write('\n')
- self.file.close()
-
- def addMeasure(self):
- if self.file is not None:
- self.file.write(' \n')
- self.measureNo += 1
- self.file.write(' \n')
-
- def addMeasureDbl(self):
- if self.file is not None:
- self.file.write(' \n')
- self.measureNo += 1
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' light-light\n')
- self.file.write(' \n')
-
- def addMeasureKeyChange(self, newKey):
- if self.file is not None:
- self.file.write(' \n')
- self.measureNo += 1
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' light-light\n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' '+str(newKey)+'\n')
- self.file.write(' \n')
- self.file.write(' \n')
-
- def addNote(self, MIDI_No, duration=None, lyric=None, position=None, tie=None): # duration: 4 = crotchet, 16 = semi-breve
- if self.file is not None:
- if duration is None:
- duration = 4 # default to a crotchet
- if lyric is None:
- lyric = "" # default to no text
- note_type, dotted, tiedToMinim = self.MIDI.Duration2Type(duration)
- self.file.write(' \n')
+ string = tree.tostring(self.root, encoding = 'UTF-8', pretty_print = True, standalone = False, doctype = '')
+
+ try:
+ with open(self.fileName, "wb") as text_file:
+ text_file.write(string)
+ except (OSError, IOError):
+ print("\nThere was an issue with the file operation.")
+ print("Please double-check your filename and folder permissions.\n")
+
+
+ # takes in the current part
+ # returns the new measure
+ def addMeasure(self, part):
+ self.measureNo += 1
+ measure = tree.SubElement(part, 'measure', attrib={'number':str(self.measureNo)})
+ return measure
+
+ # takes in the current part
+ # returns the new measure
+ def addMeasureDbl(self, part):
+ self.measureNo += 1
+ measure = tree.SubElement(part, 'measure',attrib={'number': str(self.measureNo)})
+ barline = tree.SubElement(measure, 'barline', attrib={'location':'left'})
+ tree.SubElement(barline, 'bar-style').text = 'light-light'
+
+ return measure
+
+ def addNote(self, measure, MIDI_No, duration=None, lyric=None, position=None, tie=None): # duration: 4 = crotchet, 16 = semi-breve
+ if duration is None:
+ duration = 4 # default to a crotchet
+ if lyric is None:
+ lyric = "" # default to no text
+ note_type, dotted, tiedToMinim = self.MIDI.Duration2Type(duration)
+
+ note = tree.SubElement(measure, 'note')
+
+ if MIDI_No != "RRR":
+ octave, step, alter = self.MIDI.MIDI2Note(MIDI_No, self.flats)
+
+ pitch = tree.SubElement(note, 'pitch')
+ tree.SubElement(pitch, 'step').text = str(step)
+
+ if alter != 0:
+ tree.SubElement(pitch, 'alter').text = str(alter)
+
+ tree.SubElement(pitch, 'octave').text = str(octave)
+ else:
+ tree.SubElement(note, 'rest')
+
+ if tiedToMinim is False:
+ tree.SubElement(note, 'duration').text = str(duration)
+ else:
+ tree.SubElement(note, 'duration').text = str(duration - 8)
+
+ tree.SubElement(note, 'voice').text = str(self.voice)
+ tree.SubElement(note, 'type').text = note_type
+
+ if dotted is True:
+ tree.SubElement(note, 'dot')
+
+ if tie is not None and tiedToMinim is False:
+ notations = tree.SubElement(note, 'notations')
+ tree.SubElement(notations, 'tied', attrib={'type': str(tie)})
+
+ if tiedToMinim is True:
+ notations = tree.SubElement(note, 'notations')
+
+ if tie == "stop":
+ tree.SubElement(notations, 'tied', attrib={'type': 'stop'})
+
+ tree.SubElement(notations, 'tied', attrib={'type': 'start'})
+
+ lyric_node = tree.SubElement(note, 'lyric')
+
+ if position is not None:
+ tree.SubElement(lyric_node, 'syllabic').text = str(position)
+
+ tree.SubElement(lyric_node, 'text').text = lyric
+
+ if tiedToMinim is True:
+ note = tree.SubElement(measure, 'note')
if MIDI_No != "RRR":
- octave, step, alter = self.MIDI.MIDI2Note(MIDI_No, self.flats)
- self.file.write(' \n')
- self.file.write(' '+str(step)+'\n')
+
+ pitch = tree.SubElement(note, 'pitch')
+ tree.SubElement(pitch, 'step').text = str(step)
+
if alter != 0:
- self.file.write(' '+str(alter)+'\n')
- self.file.write(' '+str(octave)+'\n')
- self.file.write(' \n')
- else:
- self.file.write(' \n')
- if tiedToMinim is False:
- self.file.write(' '+str(duration)+'\n')
+ tree.SubElement(pitch, 'alter').text = str(alter)
+
+ tree.SubElement(pitch, 'octave').text = str(octave)
else:
- self.file.write(' '+str(duration-8)+'\n')
- self.file.write(' '+str(self.voice)+'\n')
- self.file.write(' '+str(note_type)+'\n')
- if dotted is True:
- self.file.write(' \n')
- if tie is not None and tiedToMinim is False:
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- if tiedToMinim is True:
- self.file.write(' \n')
- if tie == "stop":
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
- if position is not None:
- self.file.write(' '+str(position)+'\n')
- self.file.write(' '+str(lyric)+'\n')
- self.file.write(' \n')
- self.file.write(' \n')
- if tiedToMinim is True:
- self.file.write(' \n')
- if MIDI_No != "RRR":
- self.file.write(' \n')
- self.file.write(' '+str(step)+'\n')
- if alter != 0:
- self.file.write(' '+str(alter)+'\n')
- self.file.write(' '+str(octave)+'\n')
- self.file.write(' \n')
- else:
- self.file.write(' \n')
- self.file.write(' 8\n')
- self.file.write(' '+str(self.voice)+'\n')
- self.file.write(' half\n')
- self.file.write(' \n')
- self.file.write(' \n')
- if tie == "start":
- self.file.write(' \n')
- self.file.write(' \n')
- self.file.write(' \n')
-
-
- def backOneBar(self):
- if self.file is not None:
- self.file.write(' \n')
- self.file.write(' '+str(int(self.DIVISIONS*4))+'\n')
- self.file.write(' \n')
+ tree.SubElement(note, 'rest')
+
+ tree.SubElement(note, 'duration').text = '8'
+ tree.SubElement(note, 'voice').text = str(self.voice)
+ tree.SubElement(note, 'type').text = 'half'
- def writeSop(self, notes, durations, lyrics=None, positions=None, ties=None):
- self.startSoprano()
+ notations = tree.SubElement(note, 'notations')
+ tree.SubElement(notations, 'tied', attrib={'type':'stop'})
+ if tie == "start":
+ tree.SubElement(notations, 'tied', attrib={'tied':'start'})
+
+ def writeSection(self, part, measure, notes, durations, lyrics=None, positions=None, ties=None):
for Vindex, verse in enumerate(notes):
for Bindex, bar in enumerate(verse):
if Bindex == len(verse)-1 and Vindex != len(notes)-1: # it's the last bar of the verse but not the last verse
- self.addMeasureDbl()
+ measure = self.addMeasureDbl(part)
elif Bindex == len(verse)-1 and Vindex == len(notes)-1: # this is the very last bar; don't add a new bar
pass
elif Bindex != 0:
- self.addMeasure()
+ measure = self.addMeasure(part)
if lyrics is not None and positions is not None and ties is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex], positions[Vindex][Bindex][Nindex], ties[Vindex][Bindex][Nindex])
+ for Nindex, _ in enumerate(bar):
+ self.addNote(measure, bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex], positions[Vindex][Bindex][Nindex], ties[Vindex][Bindex][Nindex])
elif lyrics is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex])
+ for Nindex, _ in enumerate(bar):
+ self.addNote(measure, bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex])
else:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex])
- self.endPart()
+ for Nindex, _ in enumerate(bar):
+ self.addNote(measure, bar[Nindex], durations[Vindex][Bindex][Nindex])
+ self.endPart(measure)
+
+ def writeSop(self, notes, durations, lyrics=None, positions=None, ties=None):
+ part, measure = self.startSoprano()
+ self.writeSection(part, measure, notes, durations, lyrics, positions, ties)
def writeAlto(self, notes, durations, lyrics=None, positions=None, ties=None):
- self.startAlto()
- for Vindex, verse in enumerate(notes):
- for Bindex, bar in enumerate(verse):
- if Bindex == len(verse)-1 and Vindex != len(notes)-1: # it's the last bar of the verse but not the last verse
- self.addMeasureDbl()
- elif Bindex == len(verse)-1 and Vindex == len(notes)-1: # this is the very last bar; don't add a new bar
- pass
- elif Bindex != 0:
- self.addMeasure()
- if lyrics is not None and positions is not None and ties is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex], positions[Vindex][Bindex][Nindex], ties[Vindex][Bindex][Nindex])
- elif lyrics is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex])
- else:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex])
- self.endPart()
+ part, measure = self.startAlto()
+ self.writeSection(part, measure, notes, durations, lyrics, positions, ties)
def writeTenor(self, notes, durations, lyrics=None, positions=None, ties=None):
- self.startTenor()
- for Vindex, verse in enumerate(notes):
- for Bindex, bar in enumerate(verse):
- if Bindex == len(verse)-1 and Vindex != len(notes)-1: # it's the last bar of the verse but not the last verse
- self.addMeasureDbl()
- elif Bindex == len(verse)-1 and Vindex == len(notes)-1: # this is the very last bar; don't add a new bar
- pass
- elif Bindex != 0:
- self.addMeasure()
- if lyrics is not None and positions is not None and ties is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex], positions[Vindex][Bindex][Nindex], ties[Vindex][Bindex][Nindex])
- elif lyrics is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex])
- else:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex])
- self.endPart()
+ part, measure = self.startTenor()
+ self.writeSection(part, measure, notes, durations, lyrics, positions, ties)
def writeBass(self, notes, durations, lyrics=None, positions=None, ties=None):
- self.startBass()
- for Vindex, verse in enumerate(notes):
- for Bindex, bar in enumerate(verse):
- if Bindex == len(verse)-1 and Vindex != len(notes)-1: # it's the last bar of the verse but not the last verse
- self.addMeasureDbl()
- elif Bindex == len(verse)-1 and Vindex == len(notes)-1: # this is the very last bar; don't add a new bar
- pass
- elif Bindex != 0:
- self.addMeasure()
- if lyrics is not None and positions is not None and ties is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex], positions[Vindex][Bindex][Nindex], ties[Vindex][Bindex][Nindex])
- elif lyrics is not None:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex], lyrics[Vindex][Bindex][Nindex])
- else:
- for Nindex, note in enumerate(bar):
- self.addNote(bar[Nindex], durations[Vindex][Bindex][Nindex])
- self.endPart()
+ part, measure = self.startBass()
+ self.writeSection(part, measure, notes, durations, lyrics, positions, ties)
def MIDI2Fifths(self, MIDI_Key):
MIDI_Key = int(MIDI_Key)