Variáveis

Uma coisa útil a fazer no nosso código é dar nomes às coisas. Sonic Pi torna isto muito fácil: escreves o nome que queres usar, um sinal de igual (=), e a coisa que te queres lembrar:

sample_name = :loop_amen

Aqui “lembramo-nos” do símbolo :loop_amenna variável sample_name. Podemos agora usar sample_nameem todo o lado que usaríamos :loop_amen. Por exemplo:

sample_name = :loop_amen
sample sample_name

Existem 3 razões principais para usar variáveis no Sonic Pi: comunicar significado, gerir repetições e capturar o resultado de coisas.

Comunicar sentido

Quando escreves código é fácil de pensar que estas a dizer ao computador como fazer coisas - desde que o computador perceba está Ok. No entanto é importante lembrar que não é só o computador que lê código. Outras pessoas podem o ler e tentar perceber o que se está a passar. Além disso, é provável que tenhas que ler o teu código no futuro e tentar perceber o que se passa. Apesar de poder parecer óbvio para ti agora - pode não o ser para outros ou o teu eu futuro!

Uma maneira de ajudar os outros a perceber o que o teu código está a fazer é adicionar comentários (como vimos na secção anterior). Outra coisa é usar nomes de variáveis com sentido. Vê este código:

sleep 1.7533

Porque usa o numero 1.7533? De onde veio este número? O que significa? Vê agora este código:

loop_amen_duration = 1.7533
sleep loop_amen_duration

Agora é muito mais claro o que 1.7533significa: é a duração do sample :loop_amen! Claro, podes dizer porque não escrever simplesmente:

sleep sample_duration(:loop_amen)

Que, claro, é uma boa maneira de comunicar a intenção do código.

Gerindo a repetição

Frequentemente vês muita repetição no teu código e quando queres mudar as coisas, tens que as mudar em muitos sítios. Vê este código:

sample :loop_amen
sleep sample_duration(:loop_amen)
sample :loop_amen, rate: 0.5
sleep sample_duration(:loop_amen, rate: 0.5)
sample :loop_amen
sleep sample_duration(:loop_amen)

Estamos a fazer muitas coisas com o :loop_amen! E se queremos ouvir como soa com outro loop sample como o :loop_garzul? Teremos de encontrar e substituir todos os :loop_amens por :loop_garzul. Isso pode ser Ok se tiveres muito tempo - mas se tiveres a actuar em palco? As vezes não temos o luxo de tempo - especialmente se queres manter as pessoas a dançar.

E se escreveres código como este:

sample_name = :loop_amen
sample sample_name
sleep sample_duration(sample_name)
sample sample_name, rate: 0.5
sleep sample_duration(sample_name, rate: 0.5)
sample sample_name
sleep sample_duration(sample_name)

Isto faz exactamente o mesmo que o anterior (experimenta). Também nos dá a habilidade de apenas mudar uma linha sample_name = :loop_amen para sample_name = :loop_garzule mudamos em muitos sítios pela magia das variáveis.

Capturando resultados

Finalmente, uma boa motivação para usar variáveis é para capturar o resultados de coisas, podes querer fazer coisas com a duração do sample:

sd = sample_duration(:loop_amen)

Agora podemos usar sd em qualquer lugar que necessitemos da duração do sample :loop_amen.

Talvez mais importante, a variável permite nos capturar o resultado da chamada a playou a sample:

s = play 50, release: 8

Agora capturamos e lembramos-nos de s como variável, que nos permite controlar o synth enquanto corre:

s = play 50, release: 8
sleep 2
control s, note: 62

Veremos como controlar os synths em mais detalhe numa secção posterior.

Aviso: Variáveis and Threads

Embora as variáveis sejam ótimas para dar nomes às coisas e capturar os resultados das coisas, é importante saber que elas normalmente só devem ser usadas localmente num segmento. Por exemplo, não faça isso:

a = (ring 6, 5, 4, 3, 2, 1)
live_loop :sorted do
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end
live_loop :shuffled do
  a = a.shuffle
  sleep 0.5
end

In the above example we assign a ring of numbers to a variable a and then used it within two separate live_loops. In the first live loop every 0.5s we sort the ring (to (ring 1, 2, 3, 4, 5, 6)) and then print it out to the log. If you run the code, you’ll find that the printed list is not always sorted!. This may surprise you - especially that sometimes the list is printed as sorted, and sometimes it is not. This is called non-deterministic behaviour and is the result of a rather nasty problem called a race-condition. The problem is due to the fact that the second live loop is also manipulating the list (in this case shuffling it) and by the time the list is printed, sometimes it has just been sorted and sometimes it has just been shuffled. Both live loops are racing to do something different to the same variable and every time round a different loop ‘wins’.

Há duas soluções para estes soluções. Primeiramente, não usar as mesmas variáveis em múltiplos loops em tempo real ou processos a correr concorrentemente. Por exemplo, o seguinte código deverá sempre imprimir uma lista sorteada à medida que cada loop em tempo real tenha as suas variáveis separadas

live_loop :shuffled do
 a = (ring 6, 5, 4, 3, 2, 1)
 a = a.shuffle 
sleep 0.5
end
live_loop :sorted do 
a = (ring 6, 5, 4, 3, 2, 1)
a = a.sort
sleep 0.5
puts "sorted: ", a
end

However, sometimes we do want to share things across threads. For example, the current key, BPM, synth etc. In these cases, the solution is to use Sonic Pi’s special thread-safe state system via the fns get and set. This is discussed later on in section 10.