Пример #1
0
def play():

    # in example 14 we showed how to nest patterns in ways that are easier
    # to conceptualize.  For instance, these patterns play in order, and we
    # call that a movement.  However, it's often tedious to specify things
    # that replay again and again.  To do make this easy, we have a new
    # selector to introduce - Repeatedly!

    output = Performance(bpm=240, stop_seconds=100)

    scale_choices = Endlessly([scale("D minor")])
    source = ScaleSource(scales=scale_choices)

    pattern1 = Roman(symbols=Repeatedly("1 2 3 4".split(), cycles=2))
    pattern2 = Roman(symbols="4 3 2 1".split())
    movement1 = Ordered(sources=[pattern1, pattern2])

    pattern3 = Roman(symbols=Repeatedly("1 4 1 4 1 5 1 5".split(), cycles=2))
    pattern4 = Roman(symbols="I IV V I".split())
    movement2 = Ordered(sources=[pattern3, pattern4])

    suite = Ordered(sources=[movement1, movement2], channel=1)

    source.send_to(suite)

    # for this example, we won't do anything crazy with transpositions or anything.

    suite.send_to(output)

    conductor = Conductor(signal=[source], performance=output)
    conductor.start()
Пример #2
0
def play():

    # in example 14 we showed how to nest patterns in ways that are easier
    # to conceptualize.  For instance, these patterns play in order, and we
    # call that a movement.  However, it's often tedious to specify things
    # that replay again and again.  To do make this easy, we have a new
    # selector to introduce - Repeatedly!


    output = Performance(bpm=240, stop_seconds=100)

    scale_choices = Endlessly([scale("D minor")])
    source = ScaleSource(scales=scale_choices)

    pattern1 = Roman(symbols=Repeatedly("1 2 3 4".split(), cycles=2))
    pattern2 = Roman(symbols="4 3 2 1".split())
    movement1 = Ordered(sources=[pattern1, pattern2])

    pattern3 = Roman(symbols=Repeatedly("1 4 1 4 1 5 1 5".split(), cycles=2))
    pattern4 = Roman(symbols="I IV V I".split())
    movement2 = Ordered(sources=[pattern3, pattern4])

    suite = Ordered(sources=[movement1, movement2], channel=1)

    source.send_to(suite)

    # for this example, we won't do anything crazy with transpositions or anything.

    suite.send_to(output)

    conductor = Conductor(signal=[source], performance=output)
    conductor.start()
Пример #3
0
def play():

    # in example 13 we showed the use of Ordered to trigger
    # one pattern after another.  As programs grow, it might be nice
    # to group them conceptually in a larger composition.

    # This is a demo that shows how Ordered can nest to not work only
    # with basic patterns, but also larger movements.

    # The idea is this: Generators stack!

    # Like before, we're setting stop seconds to 100 seconds but this composition
    # will complete due to the sources being exhausted first, which is the point.

    output = Performance(bpm=240, stop_seconds=100)

    for scale_name in ["C major", "D minor"]:

        scale_choices = Endlessly([scale(scale_name)])
        source = ScaleSource(scales=scale_choices)

        pattern1 = Roman(symbols="1 2 3 4 5 6 7".split())
        pattern2 = Roman(symbols="i ii iii iv v v vii".split())
        movement1 = Ordered(sources=[pattern1, pattern2])

        pattern3 = Roman(symbols="7 6 5 4 3 2 1".split())
        pattern4 = Roman(symbols="vii vi v iv iii ii i".split())
        movement2 = Ordered(sources=[pattern3, pattern4])
        movement2_transposer = Transpose(octaves=Endlessly([-2]))
        movement2.send_to(movement2_transposer)

        suite = Ordered(sources=[movement1, movement2], channel=1)

        source.send_to(suite)
        output.listens_to([movement1, movement2_transposer])

        # BONUS TIP: we technically don't have to have just one conductor invocation, if it
        # keeps it simple.

        conductor = Conductor(signal=[source], performance=output)
        conductor.start()
Пример #4
0
class Scene(object):

    def __init__(self, bpm=None, scale=None, pre_fx=None, post_fx=None, patterns=None, bar_count=None):

        self.scale = scale
        self.bpm = None
        self.pre_fx = pre_fx
        self.post_fx = post_fx
        self.patterns = patterns
        self.bar_count = bar_count
        self._factory = None # set up by scenes.py
        self._scale_source = ScaleSource(scales=core_scale(self.scale))
        self._output = None
        self._players = dict()


    def to_data(self):
        result = dict(
            scale = self.scale,
            bpm = self.bpm,
            pre_fx = self.pre_fx,
            post_fx = self.post_fx,
            patterns = self.patterns,
            bar_count = self.bar_count
        )
        #if self.pre_fx:
        #    for (k,v) in self.pre_fx.items():
        #        result['pre_fx'][k] = v.to_data()
        #if self.post_fx:
        #    for (k,v) in self.post_fx.items():
        #        result['post_fx'][k] = v.to_data()
        #if self.patterns:
        #    for (k,v) in self.patterns.items():
        #        result['patterns'][k] = v.to_data()
        return result

    def build(self):

        self._build_output()
        self._build_fx_chains()
        self._build_players()
        self._build_interconnects()

    def _build_output(self):

        # FIXME: the system uses stop_seconds to cap a scene at a given number of seconds
        # but we are really more interested in beats.  We probably want to attach a new timer
        # instance to the output to make this work instead, until then stop_seconds is hard coded
        # for DEBUG only and should be removed.  This should use defaults/scene_max_bars and bars on
        # the scene object.

        if self.bpm is None:
            self.bpm = self._factory.defaults['bpm']
        self._output = Performance(bpm=self.bpm, stop_seconds = 10)

    def _build_fx_chains(self):
        for (chain_name, bus) in self._factory.fx_buses.items():
            previous = None
            nodes = bus.nodes()
            for item in nodes:
                if previous is not None:
                    previous.sends = []
                    previous.send_to(item)
                previous = item

    def _build_players(self):

        for (instrument_name, pattern_list) in self.patterns.items():

            instrument = self._factory.instruments[instrument_name]
            channel = instrument.channel
            notation = instrument.notation
            sources = []

            print("PATTERN LIST= %s" % pattern_list)
            if isinstance(pattern_list, str):
                pattern_list = [ pattern_list ]

            for pattern_name in pattern_list:

                pattern = self._factory.patterns.get(pattern_name, None)
                if pattern is None:
                    raise Exception("pattern not found: %s" % pattern_name)

                real_pattern = None

                if notation == 'roman':
                    real_pattern = Roman(symbols=pattern)
                    print("RP=%s" % pattern)
                elif notation == 'literal':
                    real_pattern = Literal(symbols=pattern)
                else:
                    raise Exception("unknown notation type for instrument: %s" % instrument_name)

                sources.append(real_pattern)

            self._players[instrument_name] = Ordered(sources=sources)

    def _stitch_fx_chain(self, assignments, instrument_name, from_node, to_node):

        # SHOULD BE REMOVABLE
        #if assignments is None or instrument_name not in assignments:
        #    return

        fx_chain_name = assignments[instrument_name]
        if fx_chain_name not in self._factory.fx_buses:
            # FIXME: typed exceptions everywhere to make it easier for higher level apps
            raise Exception("fx bus not found: %s" % fx_chain_name)

        fx_chain = self._factory.fx_buses[fx_chain_name].nodes()

        # FIXME: BOOKMARK: I think need to implement COPY methods here as reuse of the same chain may cause
        # some interestingness... maybe.  Nodes should return copies of the objects (?)

        head = fx_chain[0]
        tail = fx_chain[-1]
        print("FROM %s to %s" % (from_node, head))
        print("AND FROM %s to %s" % (tail, to_node))
        from_node.send_to(head)
        tail.send_to(to_node)

    def _build_interconnects(self):

        for (instrument_name, player) in self._players.items():
            # FIXME: all of this stuff should use python standard logging
            print("---")
            print("CONFIGURING INSTRUMENT CHAIN: %s" % instrument_name)
            print(dir(player))


            player = self._players[instrument_name]
            #import pdb; pdb.set_trace()

            # TODO: consider whether it makes sense for a FxBus to connect to another FxBus
            # ignoring for now.

            if self.pre_fx is None or instrument_name not in self.pre_fx:
                # connect directly to source
                print("PRE DIRECT CONNECT")
                self._scale_source.send_to(self._players[instrument_name])
            else:
                # ensure prefx is coupled to source and tail is coupled to output
                print("PRE CONNECT")
                self._stitch_fx_chain(self.pre_fx, instrument_name, self._scale_source, player)

            instrument = self._factory.instruments[instrument_name]
            channel_assign = Channel(channel=instrument.channel)
            player.send_to(channel_assign)

            if self.post_fx is None or instrument_name not in self.post_fx:
                # connect directly to output
                print("POST DIRECT CONNECT")
                channel_assign.send_to(self._output)
            else:
                # ensure player is coupled to head of post fx and tail is coupled to output
                print("POST CONNECT")
                self._stitch_fx_chain(self.post_fx, instrument_name, channel_assign, self._output)

    def get_signals(self):
        return [ self._scale_source ]

    def get_output(self):
        return self._output
Пример #5
0
def play():

    # in example 15 we show how to drift between different patterns.

    # so far, we've mostly been showing patterns inside a scale, because
    # that sounds good for melodic instruments.  Not everything lives
    # inside a scale though - accidentals etc.  Transpose and the arp
    # can move by semitones to overcome that.

    # however, when dealing with drum kits, the scale is pretty much never
    # relevant

    # Usually these things trigger with something like C3 for a kick drum, D4
    # for a Tom, and so on -- but it varies by drumkit.

    # Having a transpose or scale change in there would
    # mess it all up.

    # Here's an example of switching through some drum patterns, and it also
    # fires multiple types of drum hits on a single channel.

    # when setting this example up, put any synth you want on MIDI channel 2,
    # but on MIDI channel 1 put some kind of drumkit.  You may need to change
    # the MIDI note names to make it sound right

    K = "F4"
    H = "A4"
    C = "Bb4"

    output = Performance(bpm=120, stop_seconds=15)

    melody_trigger = ScaleSource(scales=scale("D minor"))
    melody = Roman(symbols=Endlessly("1 - - - - 2 - - - -".split()), channel=1)

    drum_trigger = Subdivide(splits=4,
                             channel=2)  # gimme 16th notes for the drum tracks

    # kick drum on the quarter notes
    kicks = Literal(symbols=Endlessly([
        K, None, None, None, K, None, None, None, K, None, None, None, K, None,
        None, None
    ]))

    # hihat on the 8th notes every other bar
    # but wait one bar before starting that up.
    hihat = Ordered(sources=Endlessly([
        Literal(symbols="- - - - - - - - - - - - - - - -".split()),
        Literal(symbols=Endlessly([
            H, None, H, None, H, None, H, None, H, None, H, None, H, None, H,
            None
        ]))
    ]))

    # cymbals on the half notes
    cymbals = Literal(symbols=Endlessly([
        C, None, None, None, None, None, None, C, None, None, None, None, None,
        None
    ]))

    melody_trigger.send_to(melody)
    drum_trigger.send_to([kicks, hihat, cymbals])
    output.listens_to([melody, kicks, hihat, cymbals])

    conductor = Conductor(signal=[melody_trigger, drum_trigger],
                          performance=output)
    conductor.start()
Пример #6
0
def play():

    # so far what we've done has been mostly theoretical.
    # to construct larger songs, obviously, one thing has to occur
    # after another.  To do this, we could just pass in GIGANTIC
    # arrays to everything but that would suck!

    # now, everything in CAMP is built off the idea of generators.
    # this means the system can pretty well know if one thing is done
    # playing and more on to the next.

    # while we could just pass in huge note arrays, that kind of sucks.
    # What if we want a flute to play
    # it's part and then have the trombone come in?  To do that,
    # we need a facility for ordering - to say "this comes next"

    # NOTE: we're setting stop seconds to 100 seconds but this composition
    # will complete due to the sources being exhausted first, which is the point.
    # we're not writing an endlessly generative piece here, but moving towards
    # more explicit songwriting tools.  The point of this example is to show
    # we are writing a finite song in PIECES.

    output = Performance(bpm=240, stop_seconds=100)
    scale_choices = Endlessly([scale("a3 major")])

    source = ScaleSource(scales=scale_choices)

    pattern1 = Roman(symbols="1 2 3 4".split())
    pattern2 = Roman(symbols="I I I I".split())
    pattern2_transpose = Transpose(octaves=Endlessly([2]))
    pattern2.send_to(pattern2_transpose)

    # in this example, we're going to play pattern1 until it is exhausted
    # then pattern2, and when that's done, we're done.

    ordered = Ordered(sources=[pattern1, pattern2], channel=1)

    # HOMEWORK ASSIGNMENT:
    # uncomment this line to randomly pick a pattern and play it until
    # it is exhausted, but keep doing that endlessly.  Patterns might
    # repeat, see notes about advanced usages of Randomly in examples/11_randomness.py
    #
    # ordered = Ordered(sources=Randomly([pattern1,pattern2]), channel=1)

    # HOMEWORK ASSIGNMENT:
    #
    # uncomment this next line to play pattern1, pattern2 in an endless sequence
    # ordered = Ordered(Endlessly([pattern1,pattern2]))

    # TODO: IDEA: it might be nice to have a "beats" flag on ordered where it can stop
    # producing after a certain number of beats
    # ordered = Ordered(Randomly([pattern1,pattern2,pattern3]), beats=24)
    # this would allow for patterns of patterns, and better nesting.

    # TODO: IDEA: anything that can take a "beats" should really take a bars=, it's just easier
    # to think about

    # HOMEWORK: using a pattern in Ordered that uses Endlessly will cause the pattern to NOT switch.
    # Try this out and understand why pattern 2 will never play.
    # pattern1 = Roman(symbols=Endlessly("3 6 3 6 5 1 2".split()))
    # ordered = Ordered([pattern1,pattern2,pattern3])

    # TODO: IDEA, make the above homework example actually work, with something like:
    # pattern1 = Roman(symbols=Endlessly("3 6 3 6 5 1 2".split()))
    # ordered = Ordered([ dict(pattern=pattern1, beats=8), dict(pattern=pattern2, beats=8) ])

    # NOTE: in simple cases we could connect ordered to the output, but we'd miss the transposition,
    # and I wanted to show off a more complete example.  This also underscores the idea that source.chain
    # is just syntactic sugar and you don't have to use it.

    source.send_to(ordered)
    pattern1.send_to(output)
    pattern2_transpose.send_to(output)

    conductor = Conductor(signal=[source], performance=output)
    conductor.start()
Пример #7
0
def play():

    # in example 15 we show how to drift between different patterns.

    # so far, we've mostly been showing patterns inside a scale, because
    # that sounds good for melodic instruments.  Not everything lives
    # inside a scale though - accidentals etc.  Transpose and the arp
    # can move by semitones to overcome that.

    # however, when dealing with drum kits, the scale is pretty much never
    # relevant

    # Usually these things trigger with something like C3 for a kick drum, D4
    # for a Tom, and so on -- but it varies by drumkit.

    # Having a transpose or scale change in there would
    # mess it all up.

    # Here's an example of switching through some drum patterns, and it also
    # fires multiple types of drum hits on a single channel.

    # when setting this example up, put any synth you want on MIDI channel 2,
    # but on MIDI channel 1 put some kind of drumkit.  You may need to change
    # the MIDI note names to make it sound right

    K = "F4"
    H = "A4"
    C = "Bb4"

    output = Performance(bpm=120, stop_seconds=15)

    melody_trigger = ScaleSource(scales=scale("D minor"))
    melody = Roman(symbols=Endlessly("1 - - - - 2 - - - -".split()), channel=1)

    drum_trigger = Subdivide(splits=4, channel=2) # gimme 16th notes for the drum tracks

    # kick drum on the quarter notes
    kicks = Literal(symbols=Endlessly([K, None, None, None,
                                       K, None, None, None,
                                       K, None, None, None,
                                       K, None, None, None]))

    # hihat on the 8th notes every other bar
    # but wait one bar before starting that up.
    hihat = Ordered(
        sources = Endlessly([
            Literal(symbols="- - - - - - - - - - - - - - - -".split()),
            Literal(symbols=Endlessly([
                H, None, H, None, H, None, H, None,
                H, None, H, None, H, None, H, None
            ]))
        ])
    )

    # cymbals on the half notes
    cymbals = Literal(symbols=Endlessly([
            C, None, None, None, None, None, None,
            C, None, None, None, None, None, None
        ]))


    melody_trigger.send_to(melody)
    drum_trigger.send_to([kicks, hihat, cymbals])
    output.listens_to([melody, kicks, hihat, cymbals])


    conductor = Conductor(signal=[melody_trigger, drum_trigger], performance=output)
    conductor.start()