Beispiel #1
0
    def realise(self, audio):
        # TODO do multiple channels at the same time?

        # when given a single gain for multiple channels, apply it to all of them
        if len(self.amps) == 1 and audio.num_channels > 1:
            amps = self.amps * audio.num_channels
        else:
            amps = self.amps

        for (i, amp) in enumerate(amps):
            # TODO shouldn't this just affect a copy of audio????
            # above comment was previously for the line:
            # audio.audio = self.size*audio.audio
            if isnumber(amp):
                audio.audio[i, :] *= amp
            elif isinstance(amp, Curve):
                vals = amp.flatten(audio.sample_rate)
                # TODO view or copy?
                # TODO what if curve duration doesn't match signal?
                # or can we have curve duration extracted from signal? automatically matching it
                # should we just stretch the last value of curve?
                # should we define curve.conform?
                # also what if curve is too long?
                audio.audio[i, 0:amp.num_samples(audio.sample_rate)] *= vals
                audio.audio[
                    i, amp.num_samples(audio.sample_rate):] *= amp.endpoint()
            else:
                raise TypeError("Unsupported amplitude type")
Beispiel #2
0
    def __ror__(self, other):
        if other == 0:
            return self

        if isnumber(other):
            return Silence(duration=other)._concat(self)

        raise TypeError(
            "Signal can only be concatted to other signals, or to 0.")
Beispiel #3
0
    def realise(self, audio):
        # or maybe we can string some monos together and apply same panning for all?
        assert audio.num_channels == 1, "panning is from mono to multi"

        if isnumber(self.pan):
            dBs = self.scheme(self.pan)
        elif isinstance(self.pan, Curve):
            dBs = self.scheme(self.pan.flatten(audio.sample_rate))

        audio.from_mono(len(dBs))

        for (i, dB) in enumerate(dBs):
            if isnumber(dB):
                audio.audio[i, :] *= DB_to_Linear(dB)
            else:  # paramterization
                audio.audio[i, :len(dB)] *= DB_to_Linear(dB)
                audio.audio[i, len(dB):] *= DB_to_Linear(
                    self.scheme(self.pan.endpoint())[i])
Beispiel #4
0
 def __or__(self, other):
     # concat with number is casted to prolongation of the final value
     # TODO this is one of the few points inconsistent with Signal!
     if isnumber(other):
         other = Constant(value=self.endpoint(), duration=other)
     
     c = CompoundCurve()
     
     if isinstance(self, CompoundCurve):
         c.curves += self.curves
     else:
         c.curves += [self]
     
     if isinstance(other, CompoundCurve):
         c.curves += other.curves
     else:
         c.curves += [other]
     
     return c
Beispiel #5
0
    def realise(self, audio):
        # should we make this inherit from amplitude? like Triangle/Sine relation?

        # when given a single gain for multiple channels, apply it to all of them
        if len(self.dBs) == 1 and audio.num_channels > 1:
            dBs = self.dBs * audio.num_channels
        else:
            dBs = self.dBs

        for (i, dB) in enumerate(dBs):
            if isnumber(dB):
                audio.audio[i, :] *= DB_to_Linear(dB)
            elif isinstance(dB, Curve):
                vals = DB_to_Linear(dB.flatten(audio.sample_rate))
                audio.audio[i, 0:dB.num_samples(audio.sample_rate)] *= vals
                audio.audio[
                    i, dB.num_samples(audio.sample_rate):] *= DB_to_Linear(
                        dB.endpoint())
            else:
                raise TypeError("Unsupported amplitude type")
Beispiel #6
0
    def _apply(self, transform):
        assert not isinstance(
            transform, BiTransform), "can't apply BiTransform, use concat."

        if transform is None:
            return self

        if isnumber(transform):
            return self._amplitude(transform)

        if iscallable(transform) and not isinstance(transform, Transform):
            # if transform is a function receiving a signal and returning a signal,
            # masquerading as a Transform. Use @transform decorator for those
            return transform(self)

        s = self.copy()  # TODO is this needed?
        # it is, so we can reuse the same base signal multiple times
        if isinstance(transform, TransformChain):
            s.transforms.extend(transform.transforms)
        else:
            s.transforms.append(transform)
        return s
Beispiel #7
0
    def _mix(self, other):
        # mixing with constant number is interpreted as DC
        # TODO use @singledispatchmethod for this?
        if isnumber(other):
            # TODO not all Signals define self.duration!
            # This looks like a case for duration inference
            # luckily this isn't actually a very useful feature
            # (though it may be for Curve?)
            other = other * DC(duration=self.duration)

        s = Mix()

        if not self.transforms and isinstance(self, Mix):
            s.signals += self.signals
        else:
            s.signals += [self]

        if not other.transforms and isinstance(other, Mix):
            s.signals += other.signals
        else:
            s.signals += [other]

        return s
Beispiel #8
0
    def _concat(self, other):
        # TODO why is this before mix?
        # TODO consider enabling for negative other,
        # thus shifting a sequence forward(backward? Chinese) in time
        # TODO possibly better way to implement than using Silence
        if other is None:
            return self

        if isnumber(other):
            other = Silence(duration=other)

        s = Sequence()
        # use isinstance(self, Sequence) instead? more semantic
        # TODO write this as overloading of Sequence operators instead?
        if not self.transforms and isinstance(self, Sequence):
            s.sequence += self.sequence
        else:
            s.sequence += [self]

        if isinstance(other, BiTransform):  # if concatting BiTransform
            s.sequence[-1] = s.sequence[-1]._apply(other.L)
            s.sequence += [other.R]
            return s

        if isinstance(s.sequence[-1],
                      Transform):  # if coming out of BiTransform
            t = s.sequence.pop()
        else:
            t = None

        if not other.transforms and isinstance(other, Sequence):
            other.sequence[0] = other.sequence[0]._apply(t)
            s.sequence += other.sequence
        else:
            s.sequence += [other._apply(t)]

        return s
Beispiel #9
0
 def _amplitude(self, number):
     assert isnumber(number)
     return self * Amplitude(number)