MuseParse/classes/ObjectHierarchy/ItemClasses/Directions.py
import string
import random
from MuseParse.classes.ObjectHierarchy.ItemClasses import BaseClass
class Text(BaseClass.Base):
"""
A class representing any kind of text
# Optional inputs
- font: the font to use. If this isn't in the list of fonts in lilypond, a random one will be picked.
- size: font size to use
- text: the actual text to display
"""
def __init__(self, **kwargs):
BaseClass.Base.__init__(self)
if "font" in kwargs and kwargs["font"] is not None:
self.font = kwargs["font"]
if "size" in kwargs and kwargs["size"] is not None:
self.size = kwargs["size"]
if "text" in kwargs and kwargs["text"] is not None:
self.text = kwargs["text"]
else:
self.text = ""
def get(self):
"""
method to fetch all contents as a list
:return: list
"""
ret_list = []
if hasattr(self, "font"):
ret_list.append(self.font)
if hasattr(self, "size"):
ret_list.append(self.size)
if hasattr(self, "text"):
ret_list.append(self.text)
return ret_list
def toLily(self):
'''
Method which converts the object instance and its attributes to a string of lilypond code
:return: str of lilypond code
'''
lilystring = ""
if hasattr(self, "size"):
try:
size = float(self.size)
lilystring += "\\abs-fontsize #" + str(self.size) + " "
except:
lilystring += "\\" + str(self.size) + " "
if hasattr(self, "font"):
fonts_available = ["sans", "typewriter", "roman"]
if self.font in fonts_available:
lilystring += "\\" + self.font + " "
else:
rand = random.Random()
selected = rand.choice(fonts_available)
lilystring += "\\" + selected + " "
valid = False
for char in self.text:
if char in string.ascii_letters or char in [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9"]:
if not hasattr(self, "noquotes"):
lilystring += "\""
lilystring += self.text
if not hasattr(self, "noquotes"):
lilystring += "\" "
valid = True
break
else:
valid = False
if not valid:
lilystring = ""
return lilystring
class CreditText(Text):
"""
Class which represents credits - anything which is to go at the bottom of the page, like copyrights,
authors etc. Essentially the same as text except it can be positioned
# Optional inputs
- x: the x position of the text
- y: the y position of the text
- justify: left/right
- valign: vertical alignment - top/bottom
- page: unused, but the page to put this text on
"""
def __init__(self, **kwargs):
font = None
size = None
text = None
if "font" in kwargs:
font = kwargs["font"]
if "size" in kwargs:
size = kwargs["size"]
if "text" in kwargs:
text = kwargs["text"]
if "x" in kwargs:
if kwargs["x"] is not None:
self.x = kwargs["x"]
if "y" in kwargs:
if kwargs["y"] is not None:
self.y = kwargs["y"]
if "size" in kwargs:
if kwargs["size"] is not None:
self.size = kwargs["size"]
if "justify" in kwargs:
if kwargs["justify"] is not None:
self.justify = kwargs["justify"]
if "valign" in kwargs:
if kwargs["valign"] is not None:
self.valign = kwargs["valign"]
if "page" in kwargs:
if kwargs["page"] is not None:
self.page = kwargs["page"]
Text.__init__(self, font=font, size=size, text=text)
def toLily(self):
lily = ""
if hasattr(self, "justify"):
options = {
"right": "\\fill-line {\n\\null \n\override #'(baseline-skip . 4)\n\override #'(line-width . 40) {",
"center": "\\fill-line { \n \\center-column {\n"}
if self.justify in options:
lily += options[self.justify]
if hasattr(self, "valign"):
option = {"top": "UP", "bottom": "DOWN"}
lily += "\general-align #Y #" + option[self.valign] + "\n "
lily += Text.toLily(self)
if hasattr(self, "justify"):
options = {"right": "\n}\n\t}\n\\null\\null", "center": "\n}\n}"}
if self.justify in options:
lily += options[self.justify]
return lily
class Lyric(Text):
"""
Text class representing lyrics. Unused because needs readjustment in order to fit lyrics into Lilypond's output.
Essentially the same as text but 1 additional input
# Optional input
- syllabic: whether this lyric is meant to fit syllables to each diff note
"""
def __init__(self, **kwargs):
font = None
text = None
size = None
if "font" in kwargs:
font = kwargs["font"]
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "syllabic" in kwargs:
self.syllabic = kwargs["syllabic"]
Text.__init__(self, text=text, font=font, size=size)
class Direction(Text):
"""
Class representing directions - see sub classes for what these generally are. This class is used for
regular text directions such as "andante" or "cantabile"
# Optional inputs
- placement: above or below the bar
"""
def __init__(self, **kwargs):
text = None
size = None
font = None
if "placement" in kwargs:
if kwargs["placement"] is not None:
self.placement = kwargs["placement"]
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
Text.__init__(self, text=text, size=size, font=font)
def toLily(self):
textLilyString = Text.toLily(self)
symbol = ""
return_val = " "
if hasattr(self, "placement"):
if self.placement == "above":
symbol = "^"
if self.placement == "below":
symbol = "_"
if self.placement == "none":
symbol = ""
else:
symbol = "^"
if len(textLilyString) > 0:
return_val += symbol + "\\markup { " + textLilyString + " }"
return return_val
class RehearsalMark(Direction):
"""
Class representing rehearsal marks like A in a box above a bar.
Same as direction, except that text - generally "A" or "C" is used to figure out which number mark lilypond is expecting.
"""
def toLily(self):
text = " \mark "
if self.text == "":
text += "\default"
else:
try:
index = string.ascii_lowercase.index(self.text.lower()) + 1
text += "#" + str(index)
except:
text += "\default"
return text
class Forward(Direction):
"""
Probably an unused class - forwards arent what I thought they were.
"""
def __init__(self, **kwargs):
text = None
size = None
font = None
placement = None
if "duration" in kwargs:
self.duration = kwargs["duration"]
if "type" in kwargs:
self.type = kwargs["type"]
if "placement" in kwargs:
if kwargs["placement"] is not None:
placement = kwargs["placement"]
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
Direction.__init__(
self,
placement=placement,
text=text,
size=size,
font=font)
def toLily(self):
lilystring = "percent repeat"
return_list = [lilystring]
if hasattr(self, "duration"):
if self.duration is None:
self.duration = 2
return_list.append(int(self.duration))
return return_list
class RepeatSign(Direction):
"""
Class representing coda symbols and DC symbols.
"""
def __init__(self, **kwargs):
text = None
size = None
font = None
placement = None
self.noquotes = True
if "type" in kwargs:
if kwargs["type"] is not None:
self.type = kwargs["type"]
text = "\musicglyph #\"scripts." + self.type + "\""
if "placement" in kwargs:
if kwargs["placement"] is not None:
self.sym_placement = kwargs["placement"]
placement = "none"
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
Direction.__init__(
self,
placement=placement,
text=text,
size=size,
font=font)
def toLily(self):
return " \mark " + Direction.toLily(self)
class Line(Direction):
"""
Class representing lines over the bar, such as brackets or braces. Essentially I think this is a stub to be sub classed
so don't instantiate line on its own without some modification.
"""
def __init__(self, **kwargs):
text = None
size = None
font = None
placement = None
if "placement" in kwargs:
placement = kwargs["placement"]
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
if "type" in kwargs:
if kwargs["type"] is not None:
self.type = kwargs["type"]
Direction.__init__(
self,
text=text,
size=size,
font=font,
placement=placement)
class OctaveShift(Line):
"""
Class representing specifically octave shifts
# Optional inputs
- amount: the amount to shift up/down octaves. Int, generally 8 or 15 depending on whether 1 or 2
- type: type of shift - up/down.
"""
def __init__(self, **kwargs):
placement = None
text = None
font = None
size = None
type = None
if "amount" in kwargs:
if kwargs["amount"] is not None:
self.amount = kwargs["amount"]
if "placement" in kwargs:
placement = kwargs["placement"]
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
if "type" in kwargs:
if kwargs["type"] is not None:
type = kwargs["type"]
Line.__init__(
self,
text=text,
type=type,
size=size,
font=font,
placement=placement)
def toLily(self):
return_val = "\n\ottava #"
multiplier = 1
octave = 0
if hasattr(self, "type"):
if self.type == "up":
return_val += "-"
if hasattr(self, "amount"):
if self.amount == 8:
octave = 1
if self.amount == 15:
octave = 2
else:
octave = 1
return_val += str(octave) + "\n"
if hasattr(self, "type"):
if self.type == "stop":
return_val = "\n\ottava #0"
return return_val
class WavyLine(Line):
"""
Class representing a wavy line, such as the one used for an extended trill marking
"""
def toLily(self):
if not hasattr(self, "type"):
text = "\start"
else:
text = "\\" + self.type
return text + "TrillSpan"
class Pedal(Line):
"""
A piano pedal marker class.
# Optional inputs
- line: bool representing whether or not to display a line
- type: start/stop
"""
def __init__(self, **kwargs):
text = None
size = None
font = None
type = None
placement = None
if "line" in kwargs:
if kwargs["line"] is not None:
self.line = kwargs["line"]
if "placement" in kwargs:
placement = kwargs["placement"]
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
if "type" in kwargs:
type = kwargs["type"]
Line.__init__(
self,
type=type,
text=text,
size=size,
font=font,
placement=placement)
def toLily(self):
return_val = ""
if (hasattr(self, "type") and self.type != "stop") or not hasattr(
self, "type"):
if hasattr(self, "line"):
if not self.line:
return_val += "\n\set Staff.pedalSustainStyle = #'text\n"
return_val += "\sustain"
if hasattr(self, "type"):
if self.type == "stop":
return_val += "Off\n"
if self.type == "change":
return_val += "Off\sustainOn\n"
elif self.type == "start":
return_val += "On\n"
else:
return_val += "On\n"
return return_val
class Bracket(Line):
def __init__(self, **kwargs):
text = None
size = None
font = None
type = None
placement = None
if "number" in kwargs:
if kwargs["number"] is not None:
self.number = kwargs["number"]
if "ltype" in kwargs:
if kwargs["ltype"] is not None:
self.lineType = kwargs["ltype"]
if "elength" in kwargs:
if kwargs["elength"] is not None:
self.endLength = kwargs["elength"]
if "lineEnd" in kwargs:
if kwargs["lineEnd"] is not None:
self.lineEnd = kwargs["lineEnd"]
if "placement" in kwargs:
placement = kwargs["placement"]
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
if "type" in kwargs:
type = kwargs["type"]
Line.__init__(
self,
type=type,
text=text,
size=size,
font=font,
placement=placement)
def toLily(self):
lilystring = ""
style_line = ""
if hasattr(self, "lineType"):
if self.lineType == "solid":
lilystring = "\\override TextSpanner.dash-fraction = 1.0 \n"
elif self.lineType == "dashed":
lilystring = "\\override TextSpanner.dash-fraction = 0.5 \n"
if hasattr(self, "type"):
if self.type == "stop":
lilystring = "\n\\stopTextSpan\n"
elif self.type == "start":
lilystring = "\n\\startTextSpan\n"
return lilystring
class Metronome(Direction):
"""
Class representing a metronome mark, which can be a combination of <note> = <number per minute> and text
# Optional inputs
- beat: the beat marker. I.e <beat> = <bpm>
- min: the number of beats per minute.
- secondBeat: in place of min, could also have this representing another beat. Like crotchet = quaver
- text: the text to display with the metronome mark
attributes:
- parentheses: this could also be optionally set later to indicate whether or not to put parentheses round the mark.
bool.
"""
def __init__(self, **kwargs):
size = None
font = None
text = None
if "secondBeat" in kwargs:
self.secondBeat = kwargs["secondBeat"]
if "beat" in kwargs:
self.beat = kwargs["beat"]
if "min" in kwargs:
self.min = kwargs["min"]
if "text" in kwargs:
if isinstance(kwargs["text"], str):
text = kwargs["text"]
elif kwargs["text"] is not None:
text = kwargs["text"].text
if "size" in kwargs:
size = kwargs["text"]
if "font" in kwargs:
font = kwargs["font"]
Text.__init__(self, text=text, size=size, font=font)
if "parentheses" in kwargs:
if kwargs["parentheses"] is not None:
self.parentheses = kwargs["parentheses"]
else:
self.parentheses = False
def toLily(self):
return_val = " \\tempo "
converter = {
"eighth": 8,
"quarter": 4,
"half": 2,
"whole": 1,
"long": "longa",
"breve": "\\breve",
"32nd": 32}
if hasattr(self, "parentheses"):
if self.parentheses and self.text == "" and not hasattr(
self,
"secondBeat"):
return_val += "\"\" "
if self.text != "":
return_val += "\"" + self.text + "\" "
if hasattr(self, "beat") and hasattr(self, "min"):
if self.beat == "long":
return_val += "\\"
return_val += str(converter[self.beat]) + "=" + str(self.min)
elif hasattr(self, "secondBeat") and hasattr(self, "beat"):
return_val += "\markup {\n\t\concat {\n\t\t"
if hasattr(self, "parentheses") and self.parentheses:
return_val += "("
return_val += "\n\t\t\t\smaller \general-align #Y #DOWN \\note #\""
return_val += str(
converter[
self.beat]) + "\" #1\n\t\t\t\t\" = \"\n\t\t\t\t\smaller \general-align #Y #DOWN \\note #\""
return_val += str(converter[self.secondBeat]) + "\" #1\n\t\t"
if hasattr(self, "parentheses") and self.parentheses:
return_val += ")"
return_val += "\n\t}\n}"
else:
return_val = ""
return return_val
def get_detail(self):
ret_list = self.get()
if hasattr(self, "beat"):
ret_list.append(self.beat)
if hasattr(self, "min"):
ret_list.append(self.min)
return ret_list
class Dynamic(Direction):
"""
Dynamic marking class
# Optional inputs
- mark: the mark to use in the dynamic
"""
def __init__(self, **kwargs):
placement = None
size = None
font = None
text = None
if "mark" in kwargs:
self.mark = kwargs["mark"]
text = self.mark
if "text" in kwargs:
text = kwargs["text"]
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
if "placement" in kwargs:
placement = kwargs["placement"]
Direction.__init__(self, placement=placement,
font=font,
size=size,
text=text)
def toLily(self):
return_val = "\\"
if hasattr(self, "mark") and len(self.mark) < 6:
special_marks = [
"ppppp",
"pppp",
"ppp",
"pp",
"p",
"mp",
"mf",
"f",
"ff",
"fff",
"ffff",
"fffff",
"fp",
"sf",
"sff",
"sp",
"spp",
"sfz",
"rfz"]
if self.mark in special_marks:
return_val += self.mark
else:
return_val = ""
else:
return_val = ""
return return_val
class Wedge(Dynamic):
"""
Wedge - i.e crescendo line or decrescendo line
# Optional inputs
- type: crescendo/diminuendo/stop. In Lilypond stop is an option because every wedge must end somewhere,
and this gives an indication to stop the wedge at x position.
"""
def __init__(self, **kwargs):
placement = None
self.type = None
if "placement" in kwargs:
placement = kwargs["placement"]
if "type" in kwargs:
self.type = kwargs["type"]
Dynamic.__init__(self, placement=placement, text=self.type)
def toLily(self):
return_val = "\\"
if hasattr(self, "type"):
if self.type == "crescendo":
return_val += "<"
if self.type == "diminuendo":
return_val += ">"
if self.type == "stop":
return_val += "!"
return return_val
class Slur(Direction):
"""
Slur class
# Optional inputs
- type: start/stop
"""
def __init__(self, **kwargs):
placement = None
size = None
font = None
if "size" in kwargs:
size = kwargs["size"]
if "font" in kwargs:
font = kwargs["font"]
if "placement" in kwargs:
placement = kwargs["placement"]
if "type" in kwargs:
if kwargs["type"] is not None:
self.type = kwargs["type"]
Direction.__init__(self, placement=placement,
font=font,
size=size)
def toLily(self):
return_val = ""
if hasattr(self, "type"):
if self.type == "start":
return_val += "("
if self.type == "stop":
return_val += ")"
return return_val