From 611317c89082c9d54128500af0adb2d5c2c7b929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Mon, 1 Jul 2019 09:19:11 +0200 Subject: [PATCH] Add dots to notes duration --- Environment.py | 1 + Note.py | 28 ++++++++++++++++------------ Parser.py | 6 +++++- Synth.py | 1 + Tokenizer.py | 3 +++ 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Environment.py b/Environment.py index b35b6b8..43b4547 100644 --- a/Environment.py +++ b/Environment.py @@ -203,6 +203,7 @@ def createEnvironment(): 'changeOctave': changeOctave, 'wait': waitForSound, 'read': read, + 'debug': lambda args, env: print(args), 'exit': exit } diff --git a/Note.py b/Note.py index 890ad10..8b737d6 100644 --- a/Note.py +++ b/Note.py @@ -55,16 +55,14 @@ class NotePitch(Enum): raise SyntaxException(None, f"Note '{string}' does not exist") class Note: - def __init__(self, note, octave = 4, duration = 4): + def __init__(self, note, octave = 4, duration = 4, dot = False): if type(note) == str: self.note = NotePitch.toPitch(note) else: self.note = note self.octave = octave - self.duration = duration - - def hash(self): - return f"{self.note.value}{self.octave}{self.duration}" + self.duration = duration + self.dot = dot def toFrequency(self): return self.note.toFrequency() * 2 ** self.octave @@ -72,28 +70,34 @@ class Note: def transpose(self, interval): origIntRepr = self._intRepr() transposedIntRepr = origIntRepr + interval - return Note._fromIntRepr(transposedIntRepr, self.duration) + return Note._fromIntRepr(transposedIntRepr, self.duration, self.dot) def withDuration(self, duration): - return Note(self.note, self.octave, duration) + return Note(self.note, self.octave, duration, self.dot) 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): return self.octave * len(NotePitch) + self.note.value 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): return self.__str__() @staticmethod - def _fromIntRepr(intRepr, duration=4): + def _fromIntRepr(intRepr, duration = 4, dot = False): note = NotePitch(intRepr % len(NotePitch)) octave = int(intRepr / len(NotePitch)) - return Note(note, octave, duration) + return Note(note, octave, duration, dot) @staticmethod @@ -102,7 +106,7 @@ class Note: @staticmethod 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): octaveInterval = int(abs(interval) / len(NotePitch)) diff --git a/Parser.py b/Parser.py index 4520f11..65d753f 100644 --- a/Parser.py +++ b/Parser.py @@ -22,6 +22,7 @@ def parseNote(input, parent): consumedChars += 1 octave = 4 duration = 4 + dot = False if consumedChars < len(value) and value[consumedChars] in ('b', '#'): notePitch += value[consumedChars] consumedChars += 1 @@ -35,8 +36,11 @@ def parseNote(input, parent): durationString += value[consumedChars] consumedChars += 1 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): token = input.pop(0) diff --git a/Synth.py b/Synth.py index 13fca9f..e985ebd 100644 --- a/Synth.py +++ b/Synth.py @@ -26,6 +26,7 @@ def playList(notes, env): def playNote(note, bpm): frequency = note.toFrequency() duration = 60 * 4 / note.duration / bpm + duration *= 1.5 if note.dot else 1 sine(frequency, duration) def sine(frequency, duration): diff --git a/Tokenizer.py b/Tokenizer.py index dd2799d..7329b94 100644 --- a/Tokenizer.py +++ b/Tokenizer.py @@ -138,6 +138,9 @@ def tokenizeNote(input, current, line): while current+consumedChars < len(input) and re.match(r'\d', input[current+consumedChars]): value += input[current+consumedChars] 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 (0, None)