### Introduction

Player Keys are the easiest way to create relationships between your Player objects. They let you share data in a reactive and dynamic way and are especially useful if you are collaborating when using the Troop interface. They are accessed as you would any Python object attribute, by typing the name of the object, a dot, then the name of the attribute e.g. `p1.pitch`

. The neat thing about Player Keys is that, if the original Player is updated, so is the Player Key, so you don’t need to worry about updating any values.

These work for any attribute of a Player e.g. `degree`

, `amp`

, `sus`

, `pan`

or anything else. It will even work for custom attributes on your own SynthDefs. It isn’t quite the same as copying and pasting the Pattern value, but will always use the most up-to-date value held by that attribute. Let’s look at an example:

p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1.degree, dur=1/2)

The Pattern used by `p1`

is `P[0, 4, 5, 3]`

but the duration is 4 beats for each note. After using `p1.degree`

, the `p2`

player will play the same pitch, only changing the value when the pitch of `p1`

changes. Essentially, `p2`

will play each pitch 8 times. To access the Pattern directly, you need to read the data from the `attr`

dictionary like so:

p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1["degree"], dur=1/2)

**Note**: if `p1`

is updated, then the pitch of `p2`

will **not** be updated until the line of code is re-run when using the `attr`

dictionary.

### Aliases

The Player Key uses two aliases for retrieving a player’s `degree`

value. You can use `.pitch`

for synths and `.char`

for the `play`

synth, which makes it easier to understand what value you are actually getting.

### Maths and Logic

You can perform any mathematical operation on a Player Key that is available in Python:

Symbol | Name | Description |

+ | Addition | |

– | Subtraction | |

/ | Division | |

* | Multiplication | |

** | Power | |

^ | Power | |

// | Floor division | Returns the integer result of the division |

% | Modulo division | Returns the remainder part of the division |

== | Equal to | Tests if the Player Key is equal to the given value, returns 1 if True and 0 if False |

!= | Not equal to | Tests if the Player Key is not equal to the given value, returns 1 if True and 0 if False |

> | Greater than | Tests if the Player Key is greater than the given value, returns 1 if True and 0 if False |

< | Less than | Tests if the Player Key is less than the given value, returns 1 if True and 0 if False |

>= | Greater than or equal to | Tests if the Player Key is greater than or equal to the given value, returns 1 if True and 0 if False |

<= | Less than or equal to | Tests if the Player Key is less than or equal to the given value, returns 1 if True and 0 if False |

### Methods

`PlayerKey.transform(func)`

The behaviour of a Player Key is similar to that of the TimeVar. It is essentially a number/string that changes over time but any transformation made to it, such as multiplying it by two, will also hold true whenever the value changes.

>>> p1 >> pads([0, 4, 5, 3], dur=4) >>> a, b = p1.pitch, p1.pitch * 2 >>> print(a, b) 4, 8 >>> print(a, b) 5, 10

As the time changes, so does the player’s pitch and performing any arithmetic operation on it will create a new Player Key that holds information about the original and the transformation. That way it always returns the transformation of the correct value.

Things get tricky when we want to use a custom function on our player key. Let’s say we want to want transform our Player Key into a 5 when odd and a 3 when even. Here’s a function that will do that you:

>>> def odd_test(num): ... return 5 if num % 2 == 1 else 3 >>> p1 >> pads([0, 1, 2, 3], dur=4) >>> a, b = p1.pitch, odd_test(p1.pitch) >>> print(a, b) 0, 3 >>> print(a, b) 1, 3 >>> print(a, b) 2, 3

Notice anything? We always got 3, even if the Player Key’s value was odd. To apply a function (as opposed to a mathematical operation) you need to use the `transform`

method and supply the method with the function to transform it. It should take only one input argument:

>>> p1 >> pads([0, 1, 2, 3], dur=4) >>> p2 >> pluck(p1.pitch.transform(odd_test), dur=1/2) >>> print(p1.pitch, p2.pitch) 0, 5 >>> print(p1.pitch, p2.pitch) 1, 3

`.map(mapping_dict, default=0)`

Instead of defining a function to return certain values as above, we can provide a mapping in the form of a Python dictionary. The mappings can be one-to-one values or functions. If a Player Key’s value is not in the dictionary, then the `default`

value is returned.

>>> p1 >> pads([0, 4, 5, 3], dur=4) >>> p2 >> pluck(p1.pitch.map({4: 1, 3: 0}, default=2)) >>> print(p1.pitch, p2.pitch) 0, 2 >>> print(p1.pitch, p2.pitch) 4, 1 >>> print(p1.pitch, p2.pitch) 5, 2 >>> print(p1.pitch, p2.pitch) 3, 0

Here’s how you can implement the `odd_test`

transformation using map and a lambda function:

p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1.pitch.map({lambda x: x % 2 == 1: 5}, default=3)

`.accompany(rel=[0, 2, 4])`

Returns a Player Key that, when the source Player Key changes value, moves to the closest value that is +/- the values in `rel`

i.e. [0, 2, 4]. When used with `.pitch`

this will move to the nearest pitch value that completes the third or fifth above or below the note.

p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1.pitch.accompany())

### Useful Examples

Create a chord sequence based on the pitch of a player:

p1 >> bass([0, 4, 5, 3], dur=4) p2 >> pluck(p1.pitch + (0, 2, 4), dur=1/2)

Use the pitch of a player within a sequence:

p1 >> bass([0, 4, 5, 3], dur=4) p2 >> pluck([p1.pitch, 7, 6, 7], dur=1/2)

Invert the amplitude of a player:

p1 >> play("x-o-", amp=[1,1,0,1,0,1,0], dur=1/4) p2 >> play("*", amp=p1.amp != 1, dur=1/4)

Harmonise and pan two players to opposing channels:

p1 >> pluck([0, 2, 6, 3, 2, 4, 1, -2], dur=1/2, pan=[-1, 0.5, 0.25, -0.5, 0]) p2 >> blip(p1.pitch + 2, dur=1/2, pan=p1.pan * -1)

Use indexing to accompany the root note of a chord sequence:

p1 >> pluck([0, 4, 5, 3], dur=4) + (0, 2, 4) p2 >> blip(p1.pitch[0].accompany())