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()
def play(): # examples/06_subdivide showed how to chop up the incoming quarter note signal # to create faster signals. However, sometimes in a given bar we want a mix of note durations. # how do we do that? # For this example, lets play whole note chords underneath a quarter note melody. # implementation caveat: # Because the "beat" signal from the conductor comes in every quarter note, we have to take # care and rest in the right places of the input signal to avoid funness. This may get easier # later. # this is pretty close to what we did in 09_harmony.py output = Performance(bpm=120, stop_seconds=15) # this performance will actually complete so stop_seconds is mostly ignorable. scale_choices = Endlessly([scale("D major")]) source = ScaleSource(scales=scale_choices) # the underlying chords - note the rests chords = Roman(symbols=Endlessly( "I - - - I - - - IV - - - V - - - ".split()), channel=1) # every beat is a quarter note, but on the first beat in a cycle of 4 # play a WHOLE note chords_len = Duration(lengths=Endlessly([1, 0, 0, 0])) source.chain([chords, chords_len, output]) # the melody # TODO: Roman should figure out if input is a string here and auto-split. pattern2 = Roman("1 2 3 1 2 2 1 3 3 1 3 2".split(), channel=2) pattern3 = Roman("1 3 3 1 4 4 1 3 3 1 5 -".split(), channel=2) pattern4 = Roman("1 5 5 1 4 4 1 3 3 1 2 2".split(), channel=2) pattern5 = Roman("1 2 4 6 4 2 1 6 4 2 1 -".split(), channel=2) melody_sequence = [pattern2, pattern3, pattern4, pattern5] melody = Ordered(sources=Endlessly(melody_sequence)) # we could just do: source.chain(source, ordered) here # but it would mean later we would have less flexibility # to make the patterns feel different. source.chain([melody]) for pattern in melody_sequence: source.chain([pattern, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # Let's show how to play a sequence of one length but omit every Nth note output = Performance(bpm=120, stop_seconds=15) source = ScaleSource(scales=scale("D minor")) melody = Roman(symbols=Endlessly("1 2 3 4 5 6 7".split()), channel=1) silence = Permit(when=Endlessly([1, 1, 0])) # so we're playing a pattern of 1 2 3 4 5 6 7 of scale degree notes in a giant loop # the first time through what really happens is: # 1 2 <REST> 4 5 <REST> 7 # and the second time: # 1 <REST> 3 4 <REST> 6 7 # and the third time: # <REST> 2 3 <REST> 5 6 <REST> # all of this is because the pattern and the 'silence' pattern are of unequal lengths # this is not ALWAYS relevant in a composition, but if you want to do something # polyrhytmic and unorthodox (not just with 'Silence') patterns of unequal length # can be interesting. # HOMEWORK: experiment with changing the melody patterns and the silence patterns # HOMEWORK: change endlessly to randomly, and see what happens source.chain([melody, silence, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
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 play(): # now modifying our previous example, instead of playing the same two # scales in a loop, let's play a given set of notes in each scale. # We'll use roman notation to play the 1st, 4th, and 5th note in the scale # followed by the 1st, 4th, and 5th major chord # finally, we'll play the 2nd, 3rd, and 6th minor chord. output = Performance(bpm=120, stop_seconds=10) # this is just as before, playing one scale then the other in a loop of 7 # notes each scale1 = scale("c6 major") scale2 = scale("c6 minor") scale_choices = [ dict(scale=scale1, beats=7), dict(scale=scale2, beats=7) ] source = ScaleSource(scales=Endlessly(scale_choices)) # the scale follower will play the first 7 notes in each scale, whatever the current # scale is. Note that a scale change that doesn't quite line up with the length # of the roman pattern rolling over might sound a bit weird. That's ok. roman = Roman(symbols=Endlessly("1 4 5 I IV V ii iii vi".split()), channel=1) source.chain([roman, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
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 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(): # here we aren't introducing any new concepts, but we're arranging some # concepts a little differently. This is somewhat of a review, as we're going # to start exploring some more (hopefully) musical demos in our examples now. # This one sounds just a bit Perrey and Kingsley with the right VST. output = Performance(bpm=60, stop_seconds=10) # let's play in the A major scale scale_choices = Endlessly([dict(scale=scale("a4 major"))]) source = ScaleSource(scales=scale_choices) # we're going to alternate between the 1st, 4th, and 5th notes # of the scale, but we didn't just jump to chords because of what # we are about to do with the arp. roman = Roman(symbols=Endlessly("1 4 5".split()), channel=1) # and now for a clever use of the arp, to machine gun 4 repititions of # each chord, with rests in between. Subdivide alone couldn't do this. # Also notice this is running with NO tranpositions. arp = Arp( # no transpositions semitones=Endlessly([0, 0, 0, 0, 0, 0, 0, 0]), # every beat gets sliced up 8 times, no exceptions splits=Endlessly([8]), # try uncommenting this next line: #octaves=Endlessly([0,0,1,0,2,0,3,0]), # play every other note on the arp # TODO: IDEA: seems like we should also allow arp velocity! rests=Endlessly([0, 1, 0, 1, 0, 1, 0, 1])) # now the output here is just machine gunned notes. Turn it into major chords. chordify = Chordify(types=Endlessly(['major'])) source.chain([roman, arp, chordify, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # Previously, in 11_randomness we introduced the default 'choice' random mode, which just endlessly # picks something from a list. # in 18_randomness2.py we introduced 'probability', which returns True or False depending on the chances # given. It's used with the "when" statement, shown in both 18_randomness2.py and 19_skipover.py for doing # some rather fun things. # Some more types of randomness are "exhaust" and "human_random". # just to prove this performance will terminate by reaching the END of the performance, we're setting the stop # seconds to a crazy long amount of time. This one won't loop endlessly, because of the way 'exhaust' mode works. output = Performance(bpm=120, stop_seconds=9999) # exhaust takes a list and feeds it in random order. It would be the same as shuffle sorting the list, basically, and then # popping off the first element repeatedly. The result is all items will be used, in a random order, and then the sequence # will stop. # # We normally write this in a one liner, but we'll break it up in this example to make things a bit more clear scale_choices = [ scale("Ab blues"), scale("C major"), scale("Eb mixolydian") ] scale_chooser = Randomly(scale_choices, mode='exhaust') source = ScaleSource(scales=Randomly(scale_choices, mode='exhaust')) # human_random is inspired by the Apple iTunes problem. In a party shuffle mode, people may get suprised to learn # that the system played three Van Halen songs in a row. Apple changed the system to switch between artists more frequently. # in CAMP, human random will play each item in a list once, before going back and starting over with a new random selection. note_choices = "1 2 3 4 5 6 7".split() note_chooser = Randomly(note_choices, mode='human_random') melody = Roman(symbols=note_chooser, channel=1) # combining these two concepts together, we are going to play 3 random scales in sequence, and then FOR EACH SCALE, play # the scale notes in random order. source.chain([melody, chordify, transpose, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # in example 11 we showed off some random functionality # in example 17 we showed how to silence notes based on that # knowledge of 'random'. # 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) silence = Permit(when=Randomly([1, 0.5], mode='probability')) # so we're playing a scale pattern, but every other note has a 50% chance # of not being played. source.chain([melody, silence, output]) 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(): # 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(): # 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()
def play(): # in example 10 we showed you how powerful the arpeggiator can get. # well, that's great for some degrees of chaos, but what if we want # to let the computer make MORE decisions? output = Performance(bpm=120, stop_seconds=10) # randomness is one way to do that. # in example 03 we showed how to use Endlessly to loop over a set of input. # that used SELECTORS, but Endlessly is just a LINEAR selector that loops # when it gets to the end of the input. # randomness can also be accessed, using the Randomly selector, which # chooses an item from a list. # each choice is then repeated for a given number of times. # here lets pick some random scales, but whatever we pick, hold that choice # for 7 beats, which we covered in example 01. random_scale_choices = Randomly([ # each of these items are scale specifications. You've seen these in the very first examples. dict(scale=scale("c6 major"), beats=7), dict(scale=scale("Db4 minor_pentatonic"), beats=7), dict(scale=scale("Eb3 mixolydian"), beats=7) ]) # note that the random selector could repeat a selection as currently # implemented and/or specified. See ideas below. # note if we want a random choice to be made EVERY beat we can simplify # our usage of randomly like so: random_note_choices = Randomly("1 2 3 4 5 6 7".split()) # what does that do? It randomly plays one of 7 notes in the current scale. # that's syntactically clean, but super basic. Let's override that with something # showing more options available to Randomly. # we're playing CHORDS now, and if we choose the "I" chord we are going to play # it twice in the current scale (which might change after we play the first, so this is # a minor lie). All within the current scale, of course. random_note_choices = Randomly([ dict(value="I", hold=2), dict(value="IV", hold=1), dict(value="V", hold=1), dict(value="i", hold=1), dict(value="ii", hold=1), dict(value="iv:dim7", hold=1), ]) # HOMEWORK: add some more scales to the random_scale_choices above and take out some # notes from random_note_choices. Mix scales with notes! # FUTURE IDEA: also support a notion of frequency controlling what will be drawn. # frequencies should add up to 1. This would still be compatible with "hold" above. #random_note_choices = Randomly([ # dict(value="I", frequency=0.4), # dict(value="IV", frequency=0.2), # dict(value="V", frequency=0.2), # dict(value="i", frequency=0.1), # dict(value="ii", frequency=0.05), # dict(value="iv:dim7", frequency=0.05), #]) # for more examples, see the demos labelled randomness2.py, randomness3.py, etc. # we want to cover some other things first, so I'm not going to go completelyinto # randomness now. source = ScaleSource(scales=random_scale_choices) roman = Roman(symbols=random_note_choices, channel=1) source.chain([roman, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()