4.1 TimeVar Básico🔗
Introdução🔗
A música é algo que ocorre ao longo do tempo – mudanças em tons, durações, amplitudes e sons – e um FoxDot TimeVar (Variável dependente do tempo) permite criar valores que mudam ao longo do tempo. Aqui est]a como isso funciona: você cria um objeto var e fornece duas entradas: uma lista de valores que deseja que ele contenha e uma lista de durações (em batidas) para manter esses valores. Por exemplo, considere esta TimeVar:
Isso irá manter o valor de 0 por 8 batidas, depois 1 por 4 batidas, depois 2 e 3 por 2 batidas cada. Depois disso, voltará ao início do ciclo e manterá o valor de 0 novamente por 8 batidas. Os conceitos básicos também são explicados na seção Introdução.
Você pode realizar qualquer operação matemática em uma TimeVar e ela ainda assim mudará seu valor ao longo do tempo. Então, se você duplicar a TimeVar definida acima da seguinte forma:
Então, após 8 batidas e a ter um valor de 1, b terá um valor de 2. Após mais 4 batidas, a terá um valor de 2 e b terá um valor de 4. Você pode adicionar uma lista ou tupla a um TimeVar para obter um padrão de valores TimeVar; isso pode ser útil para transformar melodias ou ritmos inteiros por períodos de tempo:
Você pode notar algumas coisas sobre as entradas de duração para as TimeVars acima. Primeiro, nenhuma duração foi fornecida para a primeira TimeVar – por padrão, a duração será o comprimento de uma barra (geralmente 4 batidas) por valor. Em segundo lugar, um único valor foi fornecido ao TimeVar, var([1, 2], 8), em vez de uma lista. Nesse caso, essa duração é usada para todos os valores no TimeVar (ou seja, 8 batidas cada).
Outras funcionalidades🔗
TimeVars Aninhadas🔗
Uma característica útil do TimeVars é que você pode aninhar um dentro do outro para subdividir o valor de um... bem, o valor. Isso é útil para criar TimeVars mais complexos e é melhor explicado com uma demonstração trivial. Digamos que você criou o seguinte TimeVar durante uma sessão do FoxDot:
Agora, quero alterar o último valor na última batida do segundo ciclo do TimeVar. Aqui está a maneira manual de fazer isso:
Isso é muito texto e está começando a ficar confuso. Nós também poderíamos adicionar outro TimeVar ao nosso original:
Não mau, mas requer que saibamos a duração do ciclo e o número que temos de adicionar ao nosso valor original para obter o valor desejado. Veja como fazê isso usando TimeVars aninhadas. Primeiro, use uma lista aninhada para alternar o último valor do ciclo e, em seguida, use uma TimeVar com essa lista aninhada da seguinte forma:
Esta é uma maneira prática de criar TimeVars mais complexas sem precisar controlar as durações de cada valor usado. Nem sempre você precisa usar a lista aninhada, mas ela foi útil para o propósito deste exemplo. Exemplos mais práticos dessa técnica serão mostrados em outras partes da documentação.
TimeVars Nomeadas🔗
Às vezes, pode ser útil utilizar um TimeVar em vários locais do seu código. Um exemplo disso pode ser compartilhar uma sequência de acordes entre objetos Player. Veja como você pode fazer isso:
chords = var([0, 4, 5, 3])
p1 >> blip(chords + (0, 2, 4), dur=4)
p2 >> pasha(chords + [0, 2, 3, 4, 7, 9], dur=1/4)
O que acontece quando você deseja alterar a sequência de acordes? Experimente executar este código no FoxDot. Se você alterar o valor em chords, a música não mudará até que você execute novamente as linhas de código correspondentes a p1 e p2. Existe uma maneira de contornar esse problema, que é usar TimeVars nomeadas. Para fazer isso, todo o que você precisa é iniciar o nome da variável com var, assim:
Então, faça referência a ele usando o mesmo nome, de modo que seu código fique assim:
p1 >> blip(var.chords + (0, 2, 4), dur=4, oct=5)
p2 >> pasha(var.chords + [0, 2, 3, 4, 7, 9], dur=1/4)
Agora, o FoxDot rastreia esse nome de variável e atualizará todos os objetos players que o utilizam quando ele for atualizado. Portanto, se você executar seu novo código e alterar o valor de var.chords para outro:
A música mudará instantaneamente. Ótimo!
Transformações🔗
Você já viu que é possível fazer transformações simples de uma TimeVar realizando operações aritméticas nelas, por exemplo, adição e multiplicação. Você também pode transformar valores usando suas próprias funções predefinidas ou funções lambda de uma linha (se você for um usuário avançado de Python). No entanto, você não pode simplesmente usar my_function(my_timevar), a menos que a função faça apenas operações matemáticas básicas. Se ela estiver fazendo algo mais complexo, como usar instruções if-else, você precisará conhecer o método de transformação TimeVar. Vejamos um exemplo:
Aqui está minha função arbitrária que retorna 5 se sua entrada for ímpar e 3 se sua entrada for par:
E aqui está o meu TimeVar:
Se eu chamar odd_test(my_var), ele retornará sua saída (3 ou 5) com base no valor atual de my_var e o valor permanecerá o mesmo, mesmo que my_var mude. Teste você mesmo para ver. Para garantir que você sempre retorne o valor correto dado my_var como entrada, você precisa chamar o método transform, que recebe um objeto chamável, geralmente uma função, como entrada. Observe que essa função chamável só pode receber um argumento como entrada.
Agora, my_output será sempre 5 quando my_var for ímpar e 3 quando for par. Se você for um usuário avançado de Python, poderá até criar uma classe com um método __call__() para criar um objeto chamável e usá-lo como entrada para o método de transformação para manter algum tipo de estado entre as transformações, por exemplo, contar o número de vezes que foi chamado e alterar o valor a cada 10 vezes.