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()
def play(): # here's an example that might *START* to approximate a song. # here we have two instruments playing on two different tracks. output = Performance(bpm=60, stop_seconds=10) # both instruments will use the same scale at the same time, but there is a scale # change as we cycle between scales every 24 beats scale1 = scale("c5 major_pentatonic") scale2 = scale("e5 mixolydian") scale_choices = [ dict(scale=scale1, beats=24), dict(scale=scale2, beats=24) ] source = ScaleSource(scales=Endlessly(scale_choices)) # the first instrument plays a series of chords, transposed down an octave # from the original scale carrier signal. roman1 = Roman(symbols=Endlessly("I IV V IV III:dim ii".split()), channel=1) transpose1 = Transpose(octaves=-1) source.chain([roman1, transpose1, output]) # the second instrument plays a series of notes, but is responding to sixteenth # notes, not quarter notes, because of the subdivide. subdivide2 = Subdivide(splits=4) roman2 = Roman(symbols=Endlessly("1 4 3 4 4 3 2 1".split()), channel=2) source.chain([subdivide2, roman2, output]) # homework assignment: # change subdivide2 so it's chained BEFORE roman2 # what happens and why? conductor = Conductor(signal=[source], performance=output) conductor.start()
def test_simple_band(self): output = Performance(bpm=120, stop_seconds=10) scale1 = scale("c6 major") scale2 = scale("c6 minor") source = ScaleSource( scales=[dict(scale=scale1, beats=7), dict(scale=scale2, beats=7)]) subdivide = Subdivide(splits=[4]) roman = Roman(symbols="1 2 3 4 I IV V iii".split(), channel=1) follower = ScaleFollower(lengths=[7]) chordify = Chordify(types=['power']) shift = Transpose(octaves=[-3], channel=2) source.chain([subdivide, roman, output]) source.chain([follower, chordify, shift, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # example 05 was "playing all the power chords in a chromatic scale". # example 06 used subdivide to chop up alternating measures with faster notes # now lets alternately transpose every 2nd measure up an octave # and every 3rd measure down an octave output = Performance(bpm=120, stop_seconds=10) source = ScaleSource(scales=scale("c4 chromatic")) follower = ScaleFollower(lengths=Endlessly([12])) subdivide = Subdivide(splits=Endlessly([1,4])) # pay attention to this part - nothing else has changed transpose = Transpose(octaves=Endlessly([0,1,-1])) chordify = Chordify(types="power", channel=1) source.chain([follower, subdivide, transpose, chordify, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # we've focussed a lot on randomness now. So far, we've shown how to pick random values # for notes and how to conditionally do something or not with "when=". # What's interesting though is that, due to the way some effects plugins work, we can choose # to intermix effects. Here, we show that there are really two patterns going on, but only one # is going to win and actually get to play a note. # we're relying one 'musician' object stomping on another, but only sometimes. output = Performance(bpm=120, stop_seconds=15) source = ScaleSource(scales=scale("Ab blues")) pattern1 = Endlessly("1 2 3 4 5 6 7".split()) pattern2 = Randomly( "VII:power VI:power V:power IV:power III:power II:power I:power".split( )) cut_over = Randomly([0, 0, 0, 1, 1, 1], mode='probability') melody1 = Roman(symbols=pattern1, channel=1) melody2 = Roman(symbols=pattern2, channel=2, when=cut_over) transpose = Transpose(octaves=Endlessly([-2, -1, 0, 1, 2])) # there is no sane reason to want to do this, but what happens is that for the first three notes we are guaranteed # to play pattern1. Then three notes of pattern 2. The last note is acutally a toss up between pattern1 and pattern2. # since they live in the same chain, pattern1 is going to overwrite pattern2 even though they are expressed in a chain. # we can also even choose to overwrite the MIDI channel, which we do, all while sharing a transposition cycle. # again, this isn't realistic for most compositions, we'd likely just set up a bunch of patterns with RESTS, but # I wanted to show all the possibilities before leaving the theme of randomness for a while. Hopefully the # idea of "when=" is now drummed in. source.chain([melody1, melody2, transpose, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # this is sort of a variation of example 08. Except now, rather than # playing two different patterns that might clash, we're selecting chord # patterns for instrument 2 to harmonize with what instrument 1 is playing. output = Performance(bpm=120, stop_seconds=10) # both instruments will use the same scale at the same time, but there is a scale # change as we cycle between scales every 24 beats scale1 = scale("c5 major_pentatonic") scale2 = scale("e5 mixolydian") scale_choices = [ dict(scale=scale1, beats=24), dict(scale=scale2, beats=24) ] source = ScaleSource(scales=Endlessly(scale_choices)) # the first instrument plays a series of notes roman1 = Roman(symbols=Endlessly("1 2 4 1 2 3 1 2 4 3 3".split()), channel=1) source.chain([roman1, output]) # the second instrument transposes that note down two octaves and plays a power # chord. We could pass in an array of chords to vary the chord type, but this is # probably going to sound less prone to clashing. chordify = Chordify(types=Endlessly(["power"]), channel=2) transpose = Transpose(octaves=Endlessly([-2])) source.chain([roman1, chordify, transpose, output]) # note that roman 1 is part of each chain, but the channel number is overridden # in the second set. This can be done because the event objects are copied as they # are passed between each layer. Technically the channel can be overriden at any # time. Ideas for future chaos, perhaps? conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # Permit, introduced in the example 18_randomness2.py allows us to # silence an entire chain when certain conditions are met. # However, sometimes, we may want to decide to apply an affect only # when something is true. Because this could be useful ANYWHERE # the same type of "when" logic can actually be attached to ANYTHING. # here is a probabilistic way to use random, that combines the concepts. output = Performance(bpm=120, stop_seconds=15) source = ScaleSource(scales=scale("Ab blues")) melody = Roman(symbols=Endlessly("1 2 3 4 5 6 7".split()), channel=1) chordify = Chordify(types=Endlessly(['major', 'minor']), when=Randomly([0, 0.45], mode='probability')) transpose = Transpose(octaves=Endlessly([2, -2]), when=Randomly([0, 0, 0.75], mode='probability')) # the result is every other note has a 40% chance of becoming a chord, which is always alternating # major and minor when it happens # every THIRD note has a 75 percent chance of being transposed, which will be alternating +2/-2 octaves # when it happens # so now, we have easily inserted CONDITIONAL effects. The use of when=Randomly wasn't required. # we could also have used Endlessly or Repeatedly. Though keep in mind if using Repeatedly, when # the event chain is exhausted, that particular part of the performance will stop. And when everything stops, # the performance is done. Because this is likely being applied to an effect chain, Repeatedly probably # doesn't make the most sense with "when". But Endlessly? Sure! source.chain([melody, chordify, transpose, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
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()
def play(): # We are building a house of fire, baby. song = SongFactory(name='Foo', author='Your Name') song.set_defaults(bpm=120, scene_bar_count=8) song.set_instruments( strings=Instrument(channel=1), lead=Instrument(channel=2), ) song.set_patterns( typ='basic', patterns=dict( some_jam_pt1= "4 6 1 6 | 4 4 4 4 | 6 6 4 1 | 1 4 6 4 | 6 4 4 4 | 4 6 4 6", some_jam_pt2= "1 2 3 4 | 3 2 5 1 | 1 1 7 6 | 5 4 3 2 | 1 2 3 4 | 5 6 7 1", )) song.set_patterns( typ='random', mode='probability', patterns=dict( # chordify_chance_pt = [ 0, 0.5 ] )) song.set_patterns(typ='random', mode='exhaust', patterns=dict(serialism="1 2 3 4 5 6 7 8 9 10 11 12")) song.set_patterns( typ='random', mode='choice', patterns=dict( # random_pt1 = "1 2 3 4 5 6 7", # implies we want a new kind of generator below... # velocity_pt1 = [ 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110 ] )) song.set_patterns( typ='random', mode='probability', patterns=dict( # chordify_chance_pt1 = [ 0, 0.5, 0.25, 0.125 ] )) song.set_patterns( typ='endless', patterns=dict( occasional_holes=[1, 0, 1, 1, 0, 0], chord_sequence=['major', 'minor', 'power'], subdivide_arp=[3], subdivide_lots=[2], transpose_pt1=[2, 0, -2], # duration_pt1 = [ 0.25, 0.25, 0.125, 0.125 ], # chordify_pt1 = [ "major", "major", "minor", "major", "pow", "aug"], basic_chords="I IV V I", boring_part="1", transpose_arp=[0, 4, 5], down_two_up_two=[-2, 2])) # --- FX --- song.set_fx_buses( chordify_lead=FxBus([Chordify(types=song.pattern('chord_sequence'))]), arpeggiate_lead=FxBus([ Arp(semitones=song.pattern('transpose_arp'), splits=song.pattern('subdivide_arp'), octaves=song.pattern('transpose_pt1'), mode='locked') ]), some_silence_and_vamp_but_transpose_down=FxBus( [Transpose(octaves=song.pattern('down_two_up_two'))]), subdivide=FxBus([ # FIXME: Permit seems to not work. Figure out why. Permit(when=song.pattern('occasional_holes')), Subdivide(splits=song.pattern('subdivide_lots')), ])) song.set_scenes( # BOOKMARK: FIXME: bar count is not yet implemented as of time of writing, need a camp.band.members.stop or something to implement. Easy though. overture=Scene( scale="C4 chromatic", bar_count=12, # pre_fx = dict(strings='random_velocity_and_duration'), post_fx=dict(strings='chordify_lead'), patterns=dict(strings='serialism')), llama_theme=Scene( scale="C5 minor", bar_count=12, # pre_fx = dict(lead='subdivide'), # post_fx = dict(strings = 'arpeggiate_strings', lead = 'transpose_lead'), post_fx=dict(strings='arpeggiate_lead', lead='some_silence_and_vamp_but_transpose_down'), patterns=dict(strings='boring_part', lead=[ 'some_jam_pt1', 'some_jam_pt2', 'some_jam_pt1', 'some_jam_pt2' ]))) # -- GO! -- # scene_names = ['overture', 'llama_theme', 'bridge', 'chorus', 'verse', 'chorus', 'verse', 'ending'] # scene_names = ['overture', 'llama_theme' ] scene_names = ['llama_theme'] song.play(scene_names) print(song.to_json())