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 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(): # 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(): # this really isn't endless, because we've engaged a global stop timer. # but if you change 10 to 100, it will play for 100 seconds. Make note # of the use of Endlessly here to see that data sources are not exhausted. output = Performance(bpm=120, stop_seconds=10) # play the two scales for 7 beats each, and then keep using those scales 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)) # note: the syntax is simpler to just play ONE scale repeatedly, and you'll see this # done more in future examples. Because we don't need to stay in one scale for N beats # before moving on to another, we don't need all the extra info. # source = ScaleSource(scales=scale1) # the scale follower will play the first 7 notes in each scale, whatever the current # scale is. follower = ScaleFollower(lengths=7, channel=1) source.chain([follower, output]) conductor = Conductor(signal=[source], performance=output) conductor.start()
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 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(): output = Performance(bpm=120, stop_seconds=10) # specify that we are going to be playing the c6 major scale for a very long # time scale1 = scale("c6 major") source = ScaleSource(scales=[ dict(scale=scale1, beats=9999) ]) # but just play the first 7 notes in the scale follower = ScaleFollower(lengths=[ 7 ], channel=1) source.chain([follower, output]) # begin performance conductor = Conductor(signal=[source], performance=output) conductor.start()
def play(): # playing all the power chords in a chromatic scale. output = Performance(bpm=120, stop_seconds=10) # play the two scales for 7 beats each, and then keep using those scales scale1 = scale("c4 chromatic") scale_choices = dict(scale=scale1, beats=12) source = ScaleSource(scales=scale_choices) follower = ScaleFollower(lengths=12) chordify = Chordify(types="power", channel=1) source.chain([follower, chordify, 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(): output = Performance(bpm=120, stop_seconds=10) scale1 = scale("c6 major") scale2 = scale("c6 minor") # the performance will use the c6 major scale for 7 beats, then the c6 minor scale for 7 beats source = ScaleSource( scales=[dict(scale=scale1, beats=7), dict(scale=scale2, beats=7)]) # the scale follower will play the first 7 notes in each scale follower = ScaleFollower(lengths=[7, 7], channel=1) source.chain([follower, 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(): # 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 play(): # example 05 was "playing all the power chords in a chromatic scale". # let's modify the example very slightly using Subdivide. # normally the conductor sends down quarter notes. Let's alternate # playing quarter notes and sixteenth notes. output = Performance(bpm=120, stop_seconds=10) # play the two scales for 7 beats each, and then keep using those scales source = ScaleSource(scales=scale("c4 chromatic")) follower = ScaleFollower(lengths=12) # pay attention to this part - nothing else has changed subdivide = Subdivide(splits=Endlessly([1, 4])) chordify = Chordify(types="power", channel=1) source.chain([follower, subdivide, chordify, output]) 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(): # 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 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(): # 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(): # 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()
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(): # 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(): # previous examples showed a couple of instruments, lets go back to one # instrument to showcase just the arpeggiator. # WARNING - may not make sense if you haven't used any hardware or # software arpeggiators. output = Performance(bpm=120, stop_seconds=10) scale1 = scale("c4 major") scale_choices = [dict(scale=scale1, beats=7)] # refresher - CAMP is generator based, and performances stop when there is # nothing left to do OR stop_seconds is reached. # by not wrapping the scale choices in "Endlessly", we're allowing this example # to terminate when the scale is done. This example will play 24 quarter note # beats and STOP. But the way the arpeggiator is coded, there will really be # 24*4 = 96 sixteenth notes, of which 3/4s of them will be played with audible notes # and the rests will be, ahem, rests. # refresher - the MIDI channel number can be set anywhere in the graph, as well as overrided # anywhere in the graph. Leaving it off here on ScaleSource and setting it on the # Arp would do exactly the same thing. Leaving off the channel will cause an exception. source = ScaleSource(scales=(scale_choices), channel=1) # refresher - the scale follower will take note of the current scale and # play the scale for a given number of notes in order. We could be more # creative by using Roman() instead to select particular notes (or chords) # in the scale. follower = ScaleFollower(lengths=Endlessly([7])) # refresher, the roman usage looks very similar: # roman = Roman(symbols="1 2 3 4 5 6 7".split()) # really, there's little use for ScaleFollower in the real world, but it was # getting lonely and wanted to be featured here. It's a bit more efficient # but I doubt that matters. # NOW FOR THE FUN PART. # ok, here's the arpeggiator. # in this example, we take the currently selected note from the scale # play that note, then the notes 4 and 9 semitones up - a major chord. # every single beat will be divided into 4 parts by the arp due to 'splits' # however every 4th note is also a REST. # # see this table: # # TRIGGER: | C4 ~~~~~~~~~~~~ | D4 ~~~~~~~~~ | ... # ---------+-----------------+--------------+ # RESTS: | N N N Y | N N N Y | # SEMI: | +0 +3 +8 - | +0 +3 +8 | # OCTAVES: | +2 -2 0 0 | +2 -2 0 0 | # ---------+-----------------+--------------+ # PLAY: | C6 E2 G4 - | D6 Gb2 A4 - | # # more creative things can be done by having the semitones # and rest patterns be different lengths, and so on, as well as using # the 'free' mode with those uneven lengths. arp = Arp(semitones=Endlessly([0, 3, 8, 0]), octaves=Endlessly([2, -2, 0, 0]), splits=Endlessly([4]), rests=Endlessly([0, 0, 0, 1])) # HOMEWORK: add "mode=free" to the Arp constructor above and experiment # with octaves, splits, rests, and semitones of different values and array # lengths. # POP QUIZ: what happens if we remove Endlessly from some of the expressions above? # WHY? # the chain here is simple - scale source feeds note source, which in turn # feeds the arp. source.chain([follower, arp, output]) # kick out the jams conductor = Conductor(signal=[source], performance=output) conductor.start()