from smnp.note.pitch import NotePitch class Note: def __init__(self, note, octave, duration, dot = False): if octave is None: octave = 4 if duration is None: duration = 4 if type(note) == str: self.note = NotePitch.toPitch(note) else: self.note = note self.octave = octave self.duration = duration self.dot = dot def toFrequency(self, tuning): return tuning[self.note] * 2 ** self.octave def transpose(self, interval): origIntRepr = self._intRepr() transposedIntRepr = origIntRepr + interval return Note._fromIntRepr(transposedIntRepr, self.duration, self.dot) def withDuration(self, duration): return Note(self.note, self.octave, duration, self.dot) def withOctave(self, octave): 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}{'.' if self.dot else ''}]" def __repr__(self): return self.__str__() def __eq__(self, other): return self.note == other.note and self.octave == other.octave and self.duration == other.duration and self.dot == other.dot def __hash__(self): return hash(self.__str__()) @staticmethod def checkInterval(a, b): return b._intRepr() - a._intRepr() @staticmethod def range(a, b): return [Note._fromIntRepr(x) for x in range(a._intRepr(), b._intRepr()+1)] @staticmethod def _fromIntRepr(intRepr, duration = 4, dot = False): note = NotePitch(intRepr % len(NotePitch)) octave = int(intRepr / len(NotePitch)) return Note(note, octave, duration, dot)