Pattern Methods

Below is a detailed list of methods with examples that can be used with Pattern objects. These are useful for transforming sequences of values and can be combined with Player objects using the every method (more information here).

shuffle(n=1)

Returns the pattern with it’s contents in a random order and n is the number of permutations:

# Single permutation of shuffle
>>> print(P[0, 1, 2, 3].shuffle())
P[0, 3, 2, 1]
# Two permutations
>>> print(P[0, 1, 2, 3].shuffle(2))
P[3, 1, 2, 0, 2, 1, 3, 0]

reverse()

Returns the pattern with its contents in reverse order. Nested patterns / groups are *not* reversed. Use Pattern.mirror to get that behaviour:

# Reverses the order
>>> P[0, 1, 2, 3].reverse()
P[3, 2, 1, 0]
# Nested pattern is not reversed when using "reverse"
>>> P[[0, 4], 3, 2, 1].reverse()
P[1, 2, 3, P[0, 4]]
# Using mirror *does* reverse the nested pattern
>>> P[[0, 4], 3, 2, 1].mirror()
P[1, 2, 3, P[4, 0]]

mirror()

Returns a pattern with its contents in reverse order, including nested patterns and groups:

# Reverses the order
>>> P[0, 1, 2, 3].mirror()
P[3, 2, 1, 0]
# Reverse nested patterns and groups
>>> P[[0, 1], 2, 3, (4, 5)].mirror()
P[P(5, 4), 3, 2, P[1, 0]]

sort(*args, **kwargs)

Returns a pattern with the values sorted in order. The args and **kwargs are those that are supplied to Python’s builtin sorted function but this returns a Pattern as opposed to a list.

# Sort in ascending order
>>> print(P[1, 3, 2, 0].sort())
P[0, 1, 2, 3]
# Sort by length of item
>>> print(P[(1, 2), (3,), (4, 5, 6, 7), (8, 9, 10)].sort(key=lambda x: len(x)))
P[P(3), P(1, 2), P(8, 9, 10), P(4, 5, 6, 7)]

stutter(n=2)

Returns a new pattern with each value repeated n number of times. If n is a pattern itself, then each value is repeated by the number at the same index in the given pattern.

# Stutter each value 3 times
>>> print(P[0, 1, 2, 3].stutter(3))
P[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]
# Stutter every other value by 2
>>> print(P[0, 1, 2, 3].stutter([1, 2]))
P[0, 1, 1, 2, 3, 3]

arp(seq)

Returns a new pattern with each item repeated len(seq) times and incremented by the values in seq. Useful for arpeggiating.

# Stutter by 2 and add 4 to every second value.
>>> print(P[0, 1, 2, 3].arp([0, 4]))
P[0, 4, 1, 5, 2, 6, 3, 7]

splice(seq, *seqs)

Takes one or more patterns to “splice” into the original pattern. The new pattern returned is made up of the values from the original and given sequences in an alternated fashion.

# Alternating between two sequences
>>> print(P[0, 1, 2, 3].splice([4, 5, 6, 7]))
P[0, 4, 1, 5, 2, 6, 3, 7]
# Alternating between three sequences
>>> print(P[0, 2, 4].splice([1, 3, 5], [6, 7, 8]))
P[0, 1, 6, 2, 3, 7, 4, 5, 8]

invert()

Creates an inverted version of pattern by subtracting its values from the largest value in the pattern such that the largest value in the pattern becomes the smallest (and vice versa) and the difference between other values and the min/max are swapped:

>>> print(P[2, 5, 1, 11].invert())
P[10, 7, 11, 1]
# Inverting a linear sequence will just reverse it
>>> print(P[0, 1, 2, 3].invert())
P[3, 2, 1, 0]

shufflets(n = 4)

Returns a new pattern that contains the original pattern as a PGroup in random order of length n.

>>> print(P[0, 1, 2, 3].shufflets(3))
P[P(2, 3, 1, 0), P(3, 2, 0, 1), P(2, 1, 0, 3)]

pivot(i)

Returns a new pattern that is a reversed version of the original but then rotated such that the element at index i is still in the same place.

# In a pattern of length 5, a pivot at 2 will keep the middle item in the same place
>>> print(P[5, 1, 6, 2, 3].pivot(2))
P[3, 2, 6, 1, 5]

accum(n=None)

Returns a pattern that is equivalent to the list of sums of that pattern up to that index (the first value is always 0). The argument n specifies the length of the new pattern. When n is None then the new pattern takes the length of the original.

# Accumulation of a series of values
>>> print(P[1, 2, 3, 4].accum())
P[0, 1, 3, 6]
# The new value can be longer than the original
>>> print(P[1, 2, 3, 4].accum(8))
P[0, 1, 3, 6, 10, 11, 13, 16]

stretch(size)

Returns a pattern that is repeated until the length is equal to size.

# Stretch the pattern
>>> print(P[1, 2, 3, 4].stretch(6))
P[1, 2, 3, 4, 1, 2]
# Size can be smaller than the length of the original
>>> print(P[1, 2, 3, 4].stretch(3))
P[1, 2, 3]

trim(size)

Like stretch but the length cannot exceed the length of the original pattern.

# Trim the pattern to length 3
>>> print(P[1, 2, 3, 4, 5].trim(3))
P[1, 2, 3]
# Values for size greater than the length are ignored
>>> print(P[1, 2, 3, 4, 5].trim(10))
P[1, 2, 3, 4, 5]

ltrim(size)

Like trim but removes items from the start of the pattern, not the end.

>>> print(P[1, 2, 3, 4, 5].ltrim(3))
P[3, 4, 5]

loop(n, func=None)

Repeats the pattern n times. Useful when chaining together multiple patterns. Nested patterns are taken into consideration when looping. A function can be supplied as an optional  secondary argument, which will be applied to values in subsequent loops.

# Repeat the pattern two times
>>> print(P[0, 1, 2, 3].loop(2))
P[0, 1, 2, 3, 0, 1, 2, 3]
# Repeat twice and chain with another pattern
>>> print(P[0, 1, 2].loop(2) | P[7, 6])
P[0, 1, 2, 0, 1, 2, 7, 6]
# Looping with nested patterns expands the nests
>>> print(P[0, [1, 2]].loop(2))
P[0, 1, 0, 2, 0, 1, 0, 2]
# Repeat the pattern three times and add 7 to the loops
>>> print(P[0, 1, 2].loop(3, lambda x: x + 7))
P[0, 1, 2, 7, 8, 9, 14, 15, 16]

duplicate(n)

Like loop but retains the nested patterns such that the first value in the nests are used on the first iteration through the duplicated sequence etc.

# Keep nested values when duplicating
>>> print(P[0, [1, 2]].duplicate(2))
P[0, P[1, 2], 0, P[1, 2]]

iter

Like loop but does not take nested patterns into account when calculating the length.

>>> print(P[0, [1, 2]].iter(2))
P[0, 1, 0, 2]

swap(n)

Swaps the places of values in the pattern. When n is 2 then values next to each other are swapped, when n is 3 then values next but 1 are swapped, and so on.

# Swap values next to each other
>>> print(P[0, 1, 2, 3].swap(2))
P[1, 0, 3, 2]
# Swap values separated by one step
>>> print(P[0, 1, 2, 3, 4, 5].swap(3))
P[2, 1, 0, 5, 4, 3]

rotate(n)

Returns a pattern with the original pattern’s values shifted left in order by n number of places. Negative numbers shift the values right.

# Rotate left by 1
>>> print(P[0, 1, 2, 3].rotate(1))
P[1, 2, 3, 0]
# Rotate right by 1
>>> print(P[0, 1, 2, 3].rotate(-1))
P[3, 0, 1, 2]

sample(n)

Returns an n-length pattern with randomly selected values from the original pattern. The n

>>> print(P[0, 1, 2, 3].sample(3))
P[3, 2, 0]

palindrome()

Appends the reverse of a pattern onto itself such that is creates a palindrome of numbers.

>>> print(P[0, 1, 2, 3].palindrome())
P[0, 1, 2, 3, 3, 2, 1, 0]

alt(seq)

Replaces the pattern with that of seq. Useful if you want to use an alternate pattern and assign it using the every method.

# Replace the pattern
>>> print(P[0, 1, 2, 3].alt([4, 5]))
P[4, 5]
# Useful when used with a Player
>>> p1 >> pads([0, 1, 2, 3]).every(6, "alt", P[4, 5, 6, 7])

norm()

Returns a pattern with all the values normalised such that every value in the new pattern is between 0 and 1.

>>> print(P[0, 1, 2, 3].norm())
P[0.0, 0.3333333333333333, 0.6666666666666666, 1.0]

undup()

Removes any consecutive duplicate values so that there are no repeated values in the pattern.

>>> print(P[0, 1, 1, 1, 2, 2, 3].undup())
P[0, 1, 2, 3]

limit(func, value)

Returns a new pattern generated by appending values from the original until func(pattern) exceeds value. The func argument must be a valid function, such as len or sum.

# Create a pattern whose sum is no greater than 7
>>> print(P[0, 1, 2, 3].limit(sum, 7))
P[0, 1, 2, 3, 0, 1]

replace(sub, repl)

Returns a new pattern with values equal to sub replaced with repl.

# Replaces values of 0 with 4
>>> print(P[0, 1, 2, 3].replace(0, 4))
P[4, 1, 2, 3]
# Also replaces values in groups and nested patterns
>>> print(P[0, (1, 0), 2, [3, 0]].replace(0, 4))
P[4, P(1, 4), 2, P[3, 4]]

submap(mapping)

Similar to replace but takes a dictionary of sub to repl values to replace multiple items.

# Replace 0 with 4 and 1 with 5
>>> print(P[0, 1, 2, 3].submap({0: 4, 1: 5}))
P[4, 5, 2, 3]
# Also works with nested values etc
>>> print(P[0, (1, 0), 2, [3, 0]].submap({0: 4, 1: 5}))
P[4, P(5, 4), 2, P[3, 4]]

layer(method, *args, **kwargs)

Zips the original pattern with itself but with method called on itself, which must be a string name of a valid pattern method (similar to Player.every). However, the method argument can also be a function (example below).

# Pattern zipped with its reverse
>>> print(P[0, 1, 2, 3].layer("reverse"))
P[P(0, 3), P(1, 2), P(2, 1), P(3, 0)]
# Pattern zipped with swap(2) called on it
>>> print(P[0, 1, 2, 3].layer("swap", 2))
P[P(0, 1), P(1, 0), P(2, 3), P(3, 2)]
# Zipped with a function multiplying values by 2
>>> print(P[0, 1, 2, 3].layer(lambda x: x + 2 ))
P[P(0, 2), P(1, 3), P(2, 4), P(3, 5)]
# This is equivalent to below:
>>> print(P[0, 1, 2, 3].layer("__add__", 2))
P[P(0, 2), P(1, 3), P(2, 4), P(3, 5)]

every(n, method, *args, **kwargs)

Repeats the original pattern n times and applies the Pattern method (specified as a string) on the last repetition with args and kwargs supplied.

# Reverse the pattern on the third repetition
>>> print(P[0, 1, 2, 3].every(3, "mirror"))
P[0, 1, 2, 3, 0, 1, 2, 3, 3, 2, 1, 0]

map(callable)

Returns a new Pattern with the callable argument called on every item in the pattern.

# Set all even numbers to 0
>>> print(P[0, 1, 2, 3].map(lambda x: 0 if x % 2 == 0 else x))
P[0, 1, 0, 3]

extend(seq)

Extends the Pattern with seq in place i.e. it returns None as opposed to a new Pattern. This is more efficient than the concat method for combining multiple sequences into one Pattern.

>>> pat = P[0, 1, 2, 3]
>>> pat.extend([4, (5, 6), 7])
>>> print(pat)
P[0, 1, 2, 3, 4, P(5, 6), 7]

concat(seq)

Returns a new Pattern with the contents of seq appended onto the end of the original Pattern. The special __or__ method (which uses the | syntax) also calls this method.

# These two lines are equivalent
>>> print(P[0, 1, 2, 3].concat([4, 5, 6]))
P[0, 1, 2, 3, 4, 5, 6]
>>> print(P[0, 1, 2, 3] | [4, 5, 6])
P[0, 1, 2, 3, 4, 5, 6]

This is useful for combining multiple Patterns inside a Player object but it is not an efficient way of creating large Patterns using a loop. Try running the two blocks of code and seeing the difference.

# This is not efficient
pat = P[0, 1, 2]
for n in range(20000):
    pat = pat | [0, 1, 2]
print(pat)

# This is efficient
pat = P[0, 1, 2]
for n in range(20000):
    pat.extend([0,1,2])
print(pat)

zip(seq)

“Zipping” is the process of combining two sequences into one where each element is a group that contains the items from each sequence at the same index. If the sequences are of different lengths then then they are zipped up to the length of the lowest common multiple of both lengths.

>>> print(P[0, 1, 2, 3].zip([4, 5]))
P[P(0, 4), P(1, 5), P(2, 4), P(3, 5)]

offadd(value, dur=0.5)

Adds value to the Pattern, zips with the original, and delays the zipped value by dur using the PGroupPrime class.

>>> print(P[0, 1, 2, 3].offadd(2, 0.5))
P[P^(0, 2), P^(1, 3), P^(2, 4), P^(3, 5)]

offmul(value, dur=0.5)

Similar to offadd but multiplies the values as opposed to adding.

>>> print(P[0, 1, 2, 3].offmul(2, 0.5))
P[P^(0, 0), P^(1, 2), P^(2, 4), P^(3, 6)]

offlayer(method, dur=0.5, *args, **kwargs)

Similar to offadd and offmul but uses a user-specified method or function instead of addition/multiplication. The method argument must be a valid name of a Pattern method as a string or a callable object such as a function. Any extra arguments or keyword arguments are supplied after the duration to delay the layer, therefore duration must be supplied if supplying arguments as part of *args.

# Layer with "rotate" method with defaults
>>> print(P[0, 1, 2, 3].offlayer("rotate"))
P[P^(0, 1), P^(1, 2), P^(2, 3), P^(3, 0)]

# The following does not layer with .rotate(2) but with dur = 2
>>> print(P[0, 1, 2, 3].offlayer("rotate", 2))
P[P^(0, 1), P^(1, 2), P^(2, 3), P^(3, 0)]

# Duration must be specified to supply 2 to rotate
>>> print(P[0, 1, 2, 3].offlayer("rotate", 0.5, 2))
P[P^(0, 2), P^(1, 3), P^(2, 0), P^(3, 1)

# Can also use functions in place of method names
>>> print(P[0, 1, 2, 3].offlayer(lambda x: (x * 2) + 1))
P[P^(0, 1), P^(1, 3), P^(2, 5), P^(3, 7)]

amen()

Replicates the rhythm and order of the famous “amen break” based on a kick-drum, hi-hat, snare-drum, hi-hat sequence. Listen to the example below:

>>> p1 >> play("x-o-").every(8, "amen")