Pular para conteúdo

2.3 Manipulação Algorítmica🔗

Uma das vantagens do live coding é que você pode programar eventos para acontecerem ou se repetirem no futuro. Isso permite que você continue codificando enquanto funções repetidas são chamadas, adicionando variedade à sua música. Esta seção é uma análise aprofundada de como cada método do Player é implementado e como você pode combinar várias instâncias dele para criar músicas complexas a partir de padrões simples.

Básico🔗

Primeiro, vejamos um exemplo simples que inverte uma sequência a cada 8 batidas:

p1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every(8, "reverse")

O primeiro parâmetro é o número de batidas entre cada chamada de um método e o segundo parâmetro é o nome do próprio método como uma string. A razão para usar o nome da string do método em vez de uma função é para que o Python possa verificar se o método é válido usando a função getattr e gerar um erro se não for. Executar o código print(getattr(p1, "reverse")) resultará em algo semelhante a player.reverse. O que acontece, em essência, é que o relógio de agendamento executa getattr(p1, "reverse").__call__() a cada 8 batidas.

Você pode usar uma lista de durações para agendar chamadas de método em intervalos irregulares, desta forma:

p1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every([6, 2], "reverse")

O código acima chamará o método reverse após 6 batidas, depois 2 batidas após isso, depois novamente 6 batidas após essa chamada, repetindo isso até ser interrompido. Você também pode usar um objeto Pattern ou PatternGenerator, como PRand, para chamar métodos em momentos não predeterminados:

p1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every(PRand([2, 4, 8]), "reverse")

Se você tentar especificar várias chamadas do mesmo método, verá que apenas a última atualizada será agendada. Se quiser usar mais de uma chamada repetida para o mesmo método, você pode usar o parâmetro nomeado ident e atribuir um nome ou número para diferenciá-la:

# Chame "reverse" a cada 8 batidas *e* a cada 5 batidas
d1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every(8, "reverse").every(5, "reverse", ident=1)

Os métodos do Player que podem ser usados com eficácia são reverse, rotate, shuffle, jump e stutter.

O parâmetro cycle🔗

Às vezes, pode ser útil programar um método para o mesmo ponto em um ciclo de N batidas, por exemplo, repetir o som na 6ª batida de cada ciclo de 8 batidas. Você pode fazer isso simplesmente especificando a duração do ciclo como um parâmetro nomeado:

d1 >> play("x-o-").every(6, "stutter", cycle=8)

Em vez de chamar stutter a cada 6 batidas, ele é chamado a cada 8 batidas (o tamanho do ciclo), mas com um deslocamento de 6 batidas.

O método stutter em profundidade🔗

Um dos métodos mais úteis que pode ser chamado usando every é o método stutter. Ele reproduz o último evento enviado ao SuperCollider várias vezes durante um período especificado. Você também pode especificar atributos/efeitos a serem anexados aos eventos, como pan ou shape, usando parâmetros nomeados.

Você pode especificar o número de vezes que um evento é repetido simplesmente fornecendo um número inteiro para cada chamada após o nome do método como uma string. O padrão para isso é 2, o que significa que você ouvirá 1 evento extra – 2 menos o evento que já está sendo reproduzido. Usar um valor de 4 reproduzirá 3 eventos extras (você entendeu a ideia). Por padrão, os eventos serão repetidos ao longo da duração do evento que você está repetindo, mas você também pode repetir os eventos em um determinado período de tempo fornecendo o parâmetro dur:

# Repita o evento 4 vezes a cada 6 batidas ao longo de 1/2 batida
d1 >> play("x-o-", dur=1/2).every(6, "stutter", 4)

# Repita o evento 4 vezes a cada 6 batidas ao longo de 3 batidas
d1 >> play("x-o-", dur=1/2).every(6, "stutter", 4, dur=3)

# Também pode especificar o número de eventos a serem repetidos usando o parâmetro "n".
d1 >> play("x-o-", dur=1/2).every(6, "stutter", dur=3, n=4)

Assim como você fornece parâmetros nomeados para controlar o som dos seus sintetizadores, você pode fazer o mesmo com "stutter" para controlar o som que está sendo reproduzido. Estes podem ser uma lista ou padrão de valores que são atribuídos a cada evento repetido por vez, ou seja, não reproduzidos todos de uma vez:

# Repita 8 vezes com velocidade de reprodução crescente
d1 >> play("x-o-").every(4, "stutter", 8, rate=[1,2,3,4,5,6,7,8])

# Repita 4 vezes alternando entre panorâmica e taxa mais alta
d1 >> play("x-o-").every(4, "stutter", 4, dur=3, pan=[-1, 1], rate=2)

# Você ainda pode usar tuplas / PGroups para adicionar efeitos simultâneos
d1 >> play("x-o-").every(4, "stutter", 4, dur=1, pan=(-1,1), rate=(4, 1/2))

Observe que, ao usar uma lista de valores, apenas os primeiros n valores serão usados (onde n é o número de vezes que a repetição ocorre).

Usando Pattern métodos🔗

Além de reverse, rotate, shuffle, jump e stutter, você também pode programar qualquer método pertencente à classe Pattern para ser chamado em qualquer atributo de um player. O comportamento é ligeiramente diferente de quando se agenda métodos de um player, pois em vez de ser chamado a cada n batidas, ele é chamado e depois cancelado, por assim dizer. Provavelmente é melhor demonstrar com um exemplo:

# Chama o método "trim" no atributo degree
d1 >> play("x-o-").every(4, "trim", 3)

O padrão "x-o-" é reduzido para apenas "x-o" após 4 batidas e, em seguida, volta a ser "x-o-" após as 4 batidas seguintes. Por padrão, o método é chamado no atributo degree (que é a nota para a maioria dos sintetizadores e a sequência de caracteres para o sintetizador de samples) – você pode especificar um atributo diferente prefixando o nome do método com o nome do atributo e, em seguida, um ".", assim:

# Ajuste (trim) o padrão de oitava para 3 a cada 4 batidas
p1 >> pluck(oct=[4,5,6,7]).every(4, "oct.trim", 3)

Os parâmetros que seriam fornecidos ao método padrão são apresentados após o nome do método. Por exemplo, o método padrão offadd, que sobrepõe um padrão a si mesmo, mas com um valor adicionado e atrasado por um período, recebe dois parâmetros: o valor a ser adicionado e o tempo de atraso (o padrão é 0.5). Aqui estão alguns exemplos de como usá-lo com o every:

# Toque uma nota 2 tons acima com um atraso de 1/2 batida
p1 >> pasha([0, 4], dur=[3/4, 3/4, 1/2]).every(3, "offadd", 2)

# Toque uma nota 4 passos acima, com um atraso de 3/4 de batida
p1 >> pasha([0,1,3,4], dur=1/2).every(5, "offadd", 4, 3/4)

Importante: Você pode usar qualquer método da classe Pattern, que pode ver executando help(Pattern) ou consultando a página de documentação.

O objeto Cycle🔗

This might create some confusion with the cycle keyword, but the Cycle object can be used to alternate the values used by the every method. For example, you want to stutter a player every 4 times every 4 beats but over 3 beats the first time and 2 beats the next. How do you do that? Here’s how you might think it would work:

Isso pode criar alguma confusão com o parâmetro cycle, mas o objeto Cycle pode ser usado para alternar os valores usados por cada método. Por exemplo, você deseja fazer um player reepetir a cada 4 vezes a cada 4 batidas, mas com 3 batidas na primeira vez e 2 batidas na seguinte. Como fazer isso? Veja como você pode imaginar que isso funcionaria:

p1 >> play("x-o-").every(4, "stutter", 4, dur=[3, 2])

Infelizmente, isso geraria um erro, pois o método stutter tentaria usar a lista como uma duração, quando deveria ser um único valor. Em vez disso, você pode usar um objeto Cycle, que alterna os valores usados da seguinte maneira:

p1 >> play("x-o-").every(4, "stutter", 4, dur=Cycle([3, 2]))