Add dots to notes duration

This commit is contained in:
Bartłomiej Pluta
2019-07-01 09:19:11 +02:00
parent e47c783d27
commit 611317c890
5 changed files with 26 additions and 13 deletions

View File

@@ -203,6 +203,7 @@ def createEnvironment():
'changeOctave': changeOctave, 'changeOctave': changeOctave,
'wait': waitForSound, 'wait': waitForSound,
'read': read, 'read': read,
'debug': lambda args, env: print(args),
'exit': exit 'exit': exit
} }

26
Note.py
View File

@@ -55,16 +55,14 @@ class NotePitch(Enum):
raise SyntaxException(None, f"Note '{string}' does not exist") raise SyntaxException(None, f"Note '{string}' does not exist")
class Note: class Note:
def __init__(self, note, octave = 4, duration = 4): def __init__(self, note, octave = 4, duration = 4, dot = False):
if type(note) == str: if type(note) == str:
self.note = NotePitch.toPitch(note) self.note = NotePitch.toPitch(note)
else: else:
self.note = note self.note = note
self.octave = octave self.octave = octave
self.duration = duration self.duration = duration
self.dot = dot
def hash(self):
return f"{self.note.value}{self.octave}{self.duration}"
def toFrequency(self): def toFrequency(self):
return self.note.toFrequency() * 2 ** self.octave return self.note.toFrequency() * 2 ** self.octave
@@ -72,28 +70,34 @@ class Note:
def transpose(self, interval): def transpose(self, interval):
origIntRepr = self._intRepr() origIntRepr = self._intRepr()
transposedIntRepr = origIntRepr + interval transposedIntRepr = origIntRepr + interval
return Note._fromIntRepr(transposedIntRepr, self.duration) return Note._fromIntRepr(transposedIntRepr, self.duration, self.dot)
def withDuration(self, duration): def withDuration(self, duration):
return Note(self.note, self.octave, duration) return Note(self.note, self.octave, duration, self.dot)
def withOctave(self, octave): def withOctave(self, octave):
return Note(self.note, octave, self.duration) return Note(self.note, octave, self.duration, self.dot)
def withDot(self):
return Note(self.note, self.octave, self.duration, True)
def withoutDot(self):
return Note(self.note, self.octave, self.duration, False)
def _intRepr(self): def _intRepr(self):
return self.octave * len(NotePitch) + self.note.value return self.octave * len(NotePitch) + self.note.value
def __str__(self): def __str__(self):
return f"{self.note}({self.octave}')[{self.duration}]" return f"{self.note}({self.octave}')[{self.duration}{'.' if self.dot else ''}]"
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()
@staticmethod @staticmethod
def _fromIntRepr(intRepr, duration=4): def _fromIntRepr(intRepr, duration = 4, dot = False):
note = NotePitch(intRepr % len(NotePitch)) note = NotePitch(intRepr % len(NotePitch))
octave = int(intRepr / len(NotePitch)) octave = int(intRepr / len(NotePitch))
return Note(note, octave, duration) return Note(note, octave, duration, dot)
@staticmethod @staticmethod
@@ -102,7 +106,7 @@ class Note:
@staticmethod @staticmethod
def range(a, b): def range(a, b):
return [Note._fromIntRepr(x, 4) for x in range(a._intRepr(), b._intRepr()+1)] return [Note._fromIntRepr(x) for x in range(a._intRepr(), b._intRepr()+1)]
def intervalToString(interval): def intervalToString(interval):
octaveInterval = int(abs(interval) / len(NotePitch)) octaveInterval = int(abs(interval) / len(NotePitch))

View File

@@ -22,6 +22,7 @@ def parseNote(input, parent):
consumedChars += 1 consumedChars += 1
octave = 4 octave = 4
duration = 4 duration = 4
dot = False
if consumedChars < len(value) and value[consumedChars] in ('b', '#'): if consumedChars < len(value) and value[consumedChars] in ('b', '#'):
notePitch += value[consumedChars] notePitch += value[consumedChars]
consumedChars += 1 consumedChars += 1
@@ -35,8 +36,11 @@ def parseNote(input, parent):
durationString += value[consumedChars] durationString += value[consumedChars]
consumedChars += 1 consumedChars += 1
duration = int(durationString) duration = int(durationString)
if consumedChars < len(value) and value[consumedChars] == '.':
dot = True
consumedChars += 1
return NoteLiteralNode(Note(notePitch, octave, duration), token.pos) return NoteLiteralNode(Note(notePitch, octave, duration, dot), token.pos)
def parseComma(input, parent): def parseComma(input, parent):
token = input.pop(0) token = input.pop(0)

View File

@@ -26,6 +26,7 @@ def playList(notes, env):
def playNote(note, bpm): def playNote(note, bpm):
frequency = note.toFrequency() frequency = note.toFrequency()
duration = 60 * 4 / note.duration / bpm duration = 60 * 4 / note.duration / bpm
duration *= 1.5 if note.dot else 1
sine(frequency, duration) sine(frequency, duration)
def sine(frequency, duration): def sine(frequency, duration):

View File

@@ -138,6 +138,9 @@ def tokenizeNote(input, current, line):
while current+consumedChars < len(input) and re.match(r'\d', input[current+consumedChars]): while current+consumedChars < len(input) and re.match(r'\d', input[current+consumedChars]):
value += input[current+consumedChars] value += input[current+consumedChars]
consumedChars += 1 consumedChars += 1
if current+consumedChars < len(input) and input[current+consumedChars] == '.':
value += input[current+consumedChars]
consumedChars += 1
return (consumedChars, Token(TokenType.NOTE, value, (line, current))) return (consumedChars, Token(TokenType.NOTE, value, (line, current)))
return (0, None) return (0, None)