Pular para conteúdo

2.5 Chaves do Player🔗

Introdução🔗

As chaves do player são a maneira mais fácil de criar relações entre seus objetos Player. Elas permitem que você compartilhe dados de maneira reativa e dinâmica e são especialmente úteis se você estiver colaborando ao usar a interface Troop. Elas são acessadas como qualquer atributo de objeto Python, digitando o nome do objeto, um ponto e, em seguida, o nome do atributo, por exemplo, p1.pitch. O interessante sobre as chaves do Player é que, se o Player original for atualizado, a chave do Player também será, então você não precisa se preocupar em atualizar nenhum valor em nenhum outro lugar.

Isso funciona para qualquer atributo de um Player, por exemplo, degree, amp, sus, pan ou qualquer outro. Funciona até mesmo para atributos personalizados em seus próprios SynthDefs. Não é exatamente o mesmo que copiar e colar o valor do Padrão, pois sempre usará o valor mais atualizado mantido por esse atributo. Vejamos um exemplo:

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

O padrão usado por p1 é P[0, 4, 5, 3], mas a duração é de 4 batidas para cada nota. Depois de usar p1.degree, o player p2 tocará a mesma nota, alterando o valor apenas quando a nota de p1 mudar. Essencialmente, p2 tocará cada nota 8 vezes. Para acessar o padrão diretamente, você precisa ler os dados do dicionário attr da seguinte maneira:

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

Observação: se p1 for atualizado, a nota de p2 não será atualizado até que a linha de código seja executada novamente ao usar o dicionário attr.

Apelidos🔗

A chave Player usa dois apelidos para recuperar o valor degree de um player. Você pode usar .pitch para sintetizadores e .char para o sintetizador play, o que facilita a compreensão do valor que você está realmente obtendo.

Matemática e Lógica🔗

Você pode realizar qualquer operação matemática em uma chave do Player que esteja disponível no Python:

Símbolo Nome Descrição
+ Adição
- Subtração
/ Divisão
* Multiplicação
** Potência
^ Potência
// Divisão inteira Retorna o resultado inteiro da divisão
% Módulo da divisão Retorna o resto da divisão
== Igual a Testa se a chave do player é igual ao valor fornecido, retorna 1 se True e 0 se False.
!= Não igual a Testa se a chave do player não é igual ao valor fornecido, retorna 1 se True e 0 se False.
> Maior que Testa se a chave do player é maior que o valor fornecido, retorna 1 se True e 0 se False.
< Menos que Testa se a chave do player é menor que o valor fornecido, retorna 1 se True e 0 se False.
>= Maior ou igual que Testa se a chave do player é maior ou igual ao valor fornecido, retorna 1 se True e 0 se False.
<= Menor ou igual que Testa se a chave do player é menor ou igual ao valor fornecido, retorna 1 se True e 0 se False.

Métodos🔗

.transform(func)🔗

O comportamento de uma chave de um player é semelhante ao da TimeVar. É essencialmente um número/string de caracteres que muda ao longo do tempo, mas qualquer transformação feita nela, como multiplicá-la por dois, também se manterá válida sempre que o valor mudar.

>>> 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

À medida que o tempo muda, o nota do player também muda, e qualquer operação aritmética realizada nele criará uma nova chave do player que contém informações sobre o original e a transformação. Dessa forma, ele sempre retorna a transformação do valor correto.

As coisas ficam complicadas quando queremos usar uma função personalizada em nossa chave do player. Digamos que queremos transformar nossa chave de um player em um 5 quando for ímpar e em um 3 quando for par. Aqui está uma função que fará isso por você:

>>> 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

Notou alguma coisa? Sempre obtivemos 3, mesmo que o valor da chave do player fosse ímpar. Para aplicar uma função (em oposição a uma operação matemática), você precisa usar o método transform e fornecer ao método a função a ser transformada. Ele deve receber apenas um argumento de entrada:

>>> 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)🔗

Em vez de definir uma função para retornar determinados valores como acima, podemos fornecer um mapeamento na forma de um dicionário Python. Os mapeamentos podem ser valores ou funções um-para-um. Se o valor de uma chave de player não estiver no dicionário, o valor padrão será retornado.

>>> 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

Veja como você pode implementar a transformação odd_test usando map e uma função lambda:

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])🔗

Retorna uma chave de player que, quando a chave de reprodução de origem altera o valor, move-se para o valor mais próximo que é +/- os valores em rel, ou seja, [0, 2, 4]. Quando usado com .pitch, isso moverá para o valor da tom mais próximo que completa a terceira ou quinta acima ou abaixo da nota.

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

Exemplos Úteis🔗

Crie uma sequência de acordes com base nas notas de um player:

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

Use a nota de um player dentro de uma sequência:

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

Inverter a amplitude de um 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)

Harmonize e distribua dois reprodutores por canais opostos:

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 a indexação para acompanhar a nota fundamental de uma sequência de acordes:

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