from . import SAMPLE_RATE
from .signal import ConstantSignal, Signal
__all__ = ('Note',)
numty = (int, float)
[docs]
class Note(Signal):
"""
An abstraction over the signal base class to add timing information.
The idea is that a note has a signal and then the value that that signal should be
used as, in beats, in addition to the length of a beat.
All the binary operators on Sample objects now work with beats instead of seconds.
"""
def __init__(self, src, value, beat):
"""
:param src: The signal to use as a source for the note
:param value: The value of the note in beats
:param beat: The length of a beat in samples
"""
self.src = ConstantSignal.wrap(src)
self.value = value
self.beat = beat
self.duration = self.src.duration
self.pure = self.src.pure
def amplitude(self, frame):
return self.src.amplitude(frame)
def __add__(self, other):
if other == 0:
return self
return Note(self.src + other.src, max(self.value, other.value), other.beat)
def __mul__(self, other):
if type(other) in numty:
return Note(self.src * other, self.value, self.beat)
if type(other) is not Note:
return Note(self.src * other, self.value, self.beat)
return Note(self.src * other.src, max(self.value, other.value), other.beat)
def __neg__(self):
return Note(-self.src, self.value, self.beat)
def __rshift__(self, other):
if type(other) not in numty:
raise TypeError("Can't shift by %s" % repr(other))
realshift = other * self.beat / SAMPLE_RATE
return Note(self.src >> realshift, self.value + other, self.beat)
def __and__(self, other):
return self + (other >> self.value)
def __mod__(self, other):
if type(other) not in numty:
raise TypeError("Can't loop by %s" % repr(other))
if other == 0:
other = self.value
return Note(self.src % (other * self.beat / SAMPLE_RATE), float('inf'), self.beat)