- Bem-vindo amigo :-)

Bem-vindo ao Sonic Pi. Espero que estejas tão ansioso para começar a criar sons malucos como eu para te mostrar. Vai ser uma viagem muito divertida onde vais aprender tudo sobre musica, síntese, programação, composição, desempenho e mais.

Mas espera, que maneiras! Deixa apresentar-me – chamo-me Sam Aaron – o criador do Sonic Pi. Podes encontrar-me em @samaaron no Twitter e terei todo o gosto em te dizer olá. Podes também estar interessado em saber mais sobre as minhas Live Coding Performances onde programo com o Sonic Pi, ao vivo, para audiências.

Se tens ideias para melhorar o Sonic Pi - por favor diz-nos - comentários ajudam muito. Nunca se sabe, a tua ideia pode ser a próxima grande funcionalidade!

Este tutorial está dividido em secções agrupadas por categoria. Embora o tenha escrito para ter uma evolução de aprendizagem fácil desde o início até ao fim, fica à vontade para saltar entre secções. Se achas que está alguma coisa em falta, diz-me e vou considerar pôr-la numa versão futura.

Para concluir, o processo de observar uma sessão de live coding, é uma excelente forma de, no fundo, aprender a programar. Costumo, frequentemente fazer streamings em livecoding.tv/samaaron portanto passem pelo meu canal de youtube, digam-me olá, e façam-me muitas perguntas :-)

Ok, vamos começar…


1.1 - Live Coding

Um dos aspectos mais emocionantes do Sonic Pi é que podes escrever e modificar o código em tempo real para fazer música, tal como podes tocar numa guitarra ao vivo. Isto significa que após alguma prática podes levar o Sonic Pi para o palco e tocar.

Liberta a tua mente

Antes de entrarmos nos detalhes de como o Sonic Pi funciona no resto deste tutorial, queria dar-te uma ideia de como é programar em tempo real. Não te preocupes se não perceberes muito (ou nada) disto. Tenta só segurar-te à cadeira e aproveita…

Um Live Loop

Vamos começar, copia o código seguinte para um buffer vazio:

live_loop :flibble do
  sample :bd_haus, rate: 1
  sleep 0.5
end

Agora, carrega no botão Run e vais ouvir uma boa e rápida batida de bombo. Se a qualquer momento quiseres parar o som basta carregar no botão Stop. Mas não carregues para já… Em vez disso, segue estes passos:

Certifica-te de que o som do bombo ainda está a tocar Muda o valor do sleep de 0,5 para algo maior, como 1. Carrega no botão Run outra vez Nota como a velocidade do bombo mudou. Por fim, lembra-te deste momento, esta foi a primeira vez que programaste ao vivo com o Sonic Pi e é provável que não seja a última…

Ok, isso foi simples. Vamos adicionar algo mais à mistura. Acima de sample :bd_haus adiciona a linha sample :ambi_choir, rate: 0.3. O teu código deve estar algo parecido com o seguinte:

live_loop :flibble do
  sample :ambi_choir, rate: 0.3
  sample :bd_haus, rate: 1
  sleep 1
end

Sinta-se agora à vontade para testar aquilo que aprendeu. Mude parâmetros, como o rate - preste atenção no que acontece quando usa valores mais algos, valores mais baixos, ou até valores negativos. Repare no que acontece quando você muda o parâmetro ‘rate’ pelo sample ‘:ambi_choir’ (para, por exemplo ‘0.29’). O que acontece quando você escolhe um valor pequeno para o step? Veja se você consegue fazer ele ir tão rápido que seu computador vai parar com um erro porque não consegue alcançá-lo (se isso acontecer, escolha um valor mais alto para o tempo de sleep, e aperte em Run de novo).

Experimenta comentar uma das linhas sample adicionando um # no início:

live_loop :flibble do
  sample :ambi_choir, rate: 0.3
#  sample :bd_haus, rate: 1
  sleep 1
end

Nota como o computador ignora aquela linha, e por isso não a ouvimos. Isto chama-se um comentário. No Sonic Pi podemos usar comentários para adicionar ou remover coisas da música.

Finalmente, vou deixar-te uma coisa para brincar. Copia o código abaixo para um buffer vazio. Não tentes demasiado compreendê-lo, além de ver que existem dois loops (ciclos) – duas coisas a tocar ao mesmo tempo. Agora, faz o que fazes melhor – experimenta e brinca. Aqui estão algumas sugestões:

Experimenta mudar os valores do rate: azul para ouvir o som a mudar. Experimenta mudar o valor de sleep e nota que os loops tocam a velocidades diferentes. Experimenta remover o comentário da linha sample (remover o #) e desfruta do som da guitarra tocado ao contrário. Experimenta mudar um dos valores de mix: para números entre 0 (não entra na música) e 1 (entra na música com efeito completo).

Lembra-te de clicar em Run e ouvirás as mudanças da próxima vez que o loop tocar. Se ficares com o código estragado, não te preocupes – carrega em Stop, apaga o código e cola uma cópia nova e estás de volta à ação. É a errar que aprendes mais rápido…

live_loop :guit do
  with_fx :echo, mix: 0.3, phase: 0.25 do
    sample :guit_em9, rate: 0.5
  end
#  sample :guit_em9, rate: -0.5
  sleep 8
end
live_loop :boom do
  with_fx :reverb, room: 1 do
    sample :bd_boom, amp: 10, rate: 1
  end
  sleep 8
end

Agora, continua a tocar e a experimentar até a tua curiosidade sobre como tudo isto funciona entrar em cena e começares a questionar que mais podes fazer no Sonic Pi. Agora estás pronto para ler o resto do tutorial.

Então de que estás à espera…


1.2 - A Interface do Sonic Pi

O Sonic Pi tem um interface muito simples para programar música. Vamos passar algum tempo a explorá-la.

Interface do Sonic Pi

A - Controlos de Reprodução B - Controlos do Editor C - Informação e Ajuda D - Editor (de código) E - Painel de Opções F - Vizualizador de logs G - Sistema de Ajuda ‘H’ - Osciloscópio I - Cue Viewer

A. Controlos de Reprodução

Estes botões rosa são os controlos principais para reproduzir e parar sons. O botão Run serve para reproduzir o código no editor, Stop para parar todas as reproduções, Save para guardar o código num ficheiro externo e Record para gravar (num ficheiro WAV) o som que estiver a tocar.

B. Controlos do Editor

Estes butões laranja permitem manipular o editor de código. Os butões de Tamanho + e “Tamanho -“permitem fazer com que o texto seja maior e mais pequeno.

C. Informação e Ajuda

Estes botões azuis dão-te acesso a informação, ajuda e opções. O botão Info abre a janela de informação que contém informação sobre o Sonic Pi em si – a equipa, histórico de actualizações, contribuidores e a comunidade. O botão Ajuda abre e fecha o sistema de ajuda (F) e o botão Opções abre e fecha a janela das opções que te permitem controlar alguns parâmetros básicos do sistema.

D. Editor (de código)

Esta é a área onde irá escrever o seu código e compor/tocar a sua música. Trata-se de um editor de texto simples onde pode escrever código, apagá-lo, ou modificá-lo. Pense no que é uma versão básica do Word ou do Google Docs. O editor irá mudar de cores automaticamente tendo em conta as propriedades do código. Pode parecer estranho em primeiro lugar, mas brevemente irá chegar à conclusão que isto é bastante útil. Por exemplo, irá ficar a saber que algo é um número, no instante, em que o caracter assumir a cor base azul

E. Painel de Opções

O Sonic Pi suporta um número de preferências que podem ser acedidas ao carregar no botão Prefs. Isto abre o painel das opções que inclui várias opções alteráveis. Alguns exemplos são forçar o mono mode, inverter o stereo, activar/desactivar logs e também um slider para o volume e selector de audio no Raspberry Pi.

F. Visualizador de logs

Quando corres o teu código, vai ser mostrada informação sobre o que o programa está a fazer no Vizualizador do log. Por defeito, verás uma mensagem por cada som que crias com a hora exacta a que começou a tocar. Isto é útil para debugging e perceber o que o teu código está a fazer.

G. Sistema de Ajuda

Uma das partes mais importantes da interface do Sonic Pi, é o sistema de ajuda que aparece por baixo da janela. Isto pode ser exibido através do botão azul intitulado “Help”. O sistema contém informação de ajuda acerca de todos os aspectos do SOnic Pi, incluindo este tutorial, e uma lista dos sintetizadores e samples disponíveis, assim como efeitos e uma lista completa de todas as função que o Sonic Pi disponibiliza para fins de criação musical

H. Osciloscópio

O osciloscópio permite visualizar a forma de onde do sinal de áudio reproduzido. É possível observar fcilmente a forma de uma onda triangular e constatar que o sinal se aproxima de parece uma forma de onda triangular e que um beep básico tem uma curva de sinosoidal. É também possível constatar a diferença entre um som alto e um som calmo através do tamanho das linhas. Existem três osciloscópios com os quais é possível trabalhar-se - o pré-definido é uma combinação do osciloscópio para o canal esquerdo e direito. Existe um osciloscópio estéreo que desenha um osciloscópio com linhas separadas para cada canal. Finalmente, existe um osciloscópio com curva Lissajous que permite ver a relação de fase entre o canal esquerdo e direito e permite desenhar imagens bonitas a partir da forma do som (https://en.wikipedia.org/wiki/Lissajous_curve).

I. Cue Viewer

All internal and external events (called cues in Sonic Pi) are automatically logged in the Cue Viewer. For example, if you have a MIDI controller connected and press one of its buttons, you’ll see a new cue event in the Cue Viewer telling you the name of the controller and which button you pressed. Once you’ve mastered the basics of making and producing sounds, you’ll start to want to cue sounds or whole sections of sounds based on events such as these. A cue event is just an indication that something happened. For example, every time a live loop spins round, it sends a cue event out which is logged in the Cue Viewer. Also, external events such as MIDI messages from connected MIDI equipment and OSC messages from other programs or computers are also displayed in the Cue Viewer. It is also possible to directly generate cue events using the cue function. Anything that appears in the Cue Viewer can be used to trigger something happening. This is covered in more detail in Sections 10 to 12 of this tutorial.


1.3 - Aprender ao experimentar

O Sonic Pi incentiva-te a aprender tanto sobre computação como música ao tocar e experimentar. A coisa mais importante é que te estejas a divertir, e antes que te apercebas terás aprendido, consequentemente, como escrever código, compor e tocar.

Não existem erros

Enquanto nos focamos sobre este assunto, deixa-me dar-te um concelho que aprendi ao longo dos meus anos de live coding com música – não existem erros, apenas oportunidades. Isto é algo que ouvi muitas vezes em relação a jazz mas funciona também com live coding. Independentemente do quão experiente és – de principiante a Algoraver a experiente, quando primes o botão para avaliar o código o resultado é sempre inesperado. Pode soar extremamente bem – e nesse caso usa-o. No entanto, pode ser um tanto ou quanto desajustado. Não interessa que tenha acontecido – o que importa é o que fazes com ele a seguir. Pega no som, muda-o e transforma-o em algo espetacular. As pessoas na plateia vão gostar.

Começa pelo simples

Quando estás a aprender, é tentador querer fazer coisas espetaculares imediatamente. No entanto, aguenta essa vontade e vê-a como um objectivo distante para atingir mais tarde. Por agora, pensa no que seria mais simples, divertido e recompensador de escrever que te ajudará a chegar à coisa espetacular que tens em mente. Uma vez que tenhas uma ideia sobre esse simples passo, tenta e constrói-o, brinca com ele e vê que ideias novas te dá. Brevemente estarás ocupado a divertir e progredir.

Lembra-te de partilhar o teu trabalho com outros!


2 - Sintetizadores

OK, chega de introduções – vamos começar a escrever código e a ouvir resultados.

Nesta secção vamos cobrir a base de criar e manipular sintetizadores. Synth é uma abreviatura para sintetizador, que é uma palavra que soa bem para algo que cria sons. Os sintetizadores são normalmente bastante complicados de usar – especialmente sintetizadores analógicos com muitos fios e módulos. No entanto, o Sonic Pi dá-te grande parte dessa capacidade de forma muito simples.

Não te deixes enganar pela simplicidade da interface do Sonic Pi. É possível ir bem longe com manipulação de som sofisticada se é disso que gostas. Segura-te bem…


2.1 - Os teus primeiros Beeps

Dá uma olhadela no código que se segue:

play 70

É aqui que tudo começa. Copia e cola-o no editor (o espaço em branco por baixo do botão Run). Agora carrega em Run

Beep!

Intenso. Carrega outra vez. E outra vez. E outra vez…

Wow, espactualar, tenho a certeza que fazias isso o dia todo. Mas espera, antes que te percas com os beeps, experimenta mudar o número:

play 75

Consegues ouvir a diferença? Experimenta um número mais pequeno:

play 60

Portanto, os números mais pequenos produzirão beeps de sons com uma frequência mais baixa, e números mais altos farão beeps com um pitch mais alto. Tal como no piano, as teclas a parte baixa do piano (as da mão esquerda) tocarão notes e teclas na parte mais alta do piano (as do lado da mão direita), tocar notas mais altas

play 60

Não te preocupes se nada disto fizer sentido para ti – também não fazia para mim quando comecei. O que interessa é que números pequenos fazem sons graves e números grandes fazem sons agudos.

Acordes

Tocar uma nota e divertido, mas tocar várias ao mesmo tempo pode ser ainda melhor. Experimenta:

play 72
play 75
play 79

Jazzy! Quando escreves vários plays, eles tocam todos ao mesmo tempo. Experimenta tu mesmo – que números soam bem juntos? Quais soam mal? Experimenta, explora e descobre por próprio.

Melodia

Tocar notas e acordes é divertido – mas e a melodia? E se quisesses tocar uma nota depois da outra e não ao mesmo tempo? Bem, isso é fácil, só tens de usar sleep entre notas:

play 72
sleep 1
play 75
sleep 1
play 79

Que bom, um pequeno arpeggio. Então o que significa o 1 em sleep 1? Bem, é a duração da pausa. Na realidade significa pausar durante uma batida (ou um tempo), mas para já podemos pensar como uma pausa de 1 segundo. Então e se quisessemos que o nosso arpeggio tocasse mais rápido? Bem, temos de diminuir o valor da pausa. E que tal metade, 0.5:

play 72
sleep 0.5
play 75
sleep 0.5
play 79

Nota como toca mais rápido. Agora, tenta tu, muda as pausas – usa pausas e notas diferentes.

Uma coisa para se experimentar são valores intermédios como play 52.3 e play 52.63. Não há razão para ficarmos usando apenas valores inteiros. Experimente e se diverta.

Nomes das notas tradicionais

Para aqueles que já sabem de notação musical (não te preocupes se não souberes – não precias para te divertires) podem querer escrever uma melodia usando os nomes das notas tal como Mi e La em vez de números. podem fazer o seguinte:

# Do (A) | Re (B) | Mi (C) | Fa (D) | Sol (E) | La (F) | Si (G)
play :C
sleep 0.5
play :D
sleep 0.5
play :E

Lembra-te de pôr um : antes do nome da nota para que esta fique côr-de-orsa. Também podes especificar a oitava adicionando um número à frente da nota:

play :C3
sleep 0.5
play :D3
sleep 0.5
play :E4

Se quiseres adicionar um sustenido, de modo a incrementar o pitch meio tom, adiciona um s depois da nota, como play :Fs3, e se quiseres adicionar um bemol, adiciona um b, como play :Eb3.

Agora perde-te no código e diverte-te a fazer as tuas próprias músicas.


2.2 - Opções do Sintetizador: Amplitude and Panorâmica

Além de te permitir controlar que nota tocar ou qual o sample a tocar, o Sonic Pi dispõe de um conjunto de opções para criar e controlar os sons. Vamos cobrir algumas destas neste tutorial verifica que existe documentação detalhada para cada uma no sistema de ajuda. No entanto, para já vamos introduzir dois dos parâmetros mais úteis: amplitude e panorâmica. Primeiro, vamos ver quais são as nossas opções.

Opções

O Sonic Pi suporta a notação de opções (ou opts, abreviando) para os sintetizadores. Opts são controlos que podes passar ao play que modificam e controlam aspectos do som que ouves. Cada sintetizador tem as suas próprias opts para afinar o seu som. No entanto, existem conjuntos de opts comuns partilhados por muitos synths tal como amp: e opts envelope (para serem faladas noutra secção).

Opts têm duas partes principais, o seu nome (o nome do controlo) e o seu valor (o valor que queres dar a essa opt). Por exemplo, podes ter uma opt chamada queijo e dar-lhe um valor de 1.

Opts são passadas a comandos play ao usar uma virgula (,) e depois o nome da opt, como amp: (não te esqueças dos dois pontos :) e depois um espaço e o valor da opt. Por exemplo:

play 50, queijo: 1

(Nota que queijo: não existe mesmo, só estamos a usar como exemplo)

Podes dar várias opts separando-as por vírgulas:

play 50, queijo: 1, feijões: 0.5

A ordem das opts não interessa, por isso o seguinte é idêntico:

play 50, beans: 0.5, cheese: 1

Opts que não são reconhecidas pelo sintetizado são simplesmente ignoradas (como queijo e feijões, que são claramente nomes ridículos para opts!)

Se usares a mesma opt mais de uma vez com valores diferentes, a última ganha. Por exemplo, feijões: vai ter o valor 2 em vez de 0.5:

play 50, feijões: 0.5, queijo: 3, ovos: 0.1, feijões: 2

Muitas coisas no Sonic Pi aceitam opts, portanto gasta algum tempo a aprender como usá-las e estarás preparado! Vamos brincar com a nossa primeira opt: amp:.

Amplitude

A amplitude é a representação numcomputador do volume de um som. Um nível mais elevador de amplitude conduz a um som com um nível de pressão sonora mais elevado, e consequentemente mais alto e uma amplitude baixa produz um som com um nível de pressão sonora mais baixo, e consequentemente mais suave. Da mesma forma que o Sonic Pi usa números para representar tempo e notas, também usa números para representar amplitude. Uma amplitude de 0 é silenciosa (não vais ouvir nada) enquanto uma amplitude 1 é de volume normal. Até podes aumentar a amplitude para 2, 10, 100 ou mais. No entanto, deve-se notar que quando a amplitude de todos os sons aumenta demasiado, o Sonic Pi usa uma coisa chamada compressor que os baixa para ter a certeza que o som não está demasiado alto para os teus ouvidos. Isto pode fazer o som ficar turvo e estrano. Por isso tenta usar amplitudes baixas, entre 0 e 0.5 para evitar compressão.

Aumenta o volume

Para mudar a amplitude de um som, podes usar a opt amp:. Por exemplo, para tocar com metade do nível de pressão sonora dá-lhe o valor 0.5:

play 60, amp: 0.5

Para tocar com o dobro da pressão sonora, e consequentemente amplitude e intensidade, dá-lhe 2:

play 60, amp: 2

A opt amp: só modifica a amplitude do play com que está associada. Então, neste exemplo, o primeiro play está a metade do volume e o segundo está no normal (1):

play 60, amp: 0.5
sleep 0.5
play 65

Claro, podes usar diferentes valores de amp: para cada play:

play 50, amp: 0.1
sleep 0.25
play 55, amp: 0.2
sleep 0.25
play 57, amp: 0.4
sleep 0.25
play 62, amp: 1

Panorâmica

Outra opt divertida é a pan:, que controla o a panorâmica de um som stereo. Usar panning para a esquerda num som significa que só o vais ouvir pela coluna esquerda, e usar panning para a direita significa que que só o vais ouvir pela coluna da direita. Como valores, usamos -1 para representar a esquerda, 0 para o centro e 1 para a direita, em stereo. Claro, estamos livres para usar qualquer valor entre -1 e 1 para controlar a posição exacta do som.

Vamos tocar um beep na coluna esquerda:

play 60, pan: -1

Agora, vamos tocar um beep na coluna direita:

play 60, pan: 1

Finalmente vamos tocar um beep no centro (posição predefinida):

play 60, pan: 0

Agora, diverte-te a mudar a amplitude e panning dos teus sons!


2.3 - Mudar Synths

Divertimo-nos muito até agora a fazer beeps. Mas, já deves estar a ficar aborrecido do beep básico. Será isto tudo o que o Sonic Pi tem para oferecer? De certeza que existe algo mais em live coding além de tocar beeps, não? Há pois, e nesta secção vanis explorar os sons que o Sonic Pi tem para oferecer.

Sintetizadores

O Sonic Pi tem um conjunto de instrumentos chamados synths (abreviatura para sintetizadores). Enquanto que os samples de áudio representam sons pré-gravados, sintetizadores são capazes de criar novos sons dependendo de como os controlas (que vamos explorar mais tarde neste tutorial). Os sintetizadores do Sonic Pi são muito poderosos e expressivos e vais-te divertir muito a explorá-los e brincar com eles. Primeiro, vamos aprender como escolher que synth usar.

Ondas de dente de serra ruidosas e sons do sintetizador prophet da Roland

Um som divertido é a (onda dentes de serra) – vamos experimentar-lo:

use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25

Vamos experimentar outro som – o som do sintetizador prophet da Roland:

use_synth :prophet
play 38
sleep 0.25
play 50
sleep 0.25
play 62
sleep 0.25

E que tal combinar dois sons. Um depois do outro:

use_synth :saw
play 38
sleep 0.25
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25

De seguida, iremos escutar sons com a mesma duração (por agora a dormir entre sucessivas chamadas para tocar):

use_synth :tb303
play 38
sleep 0.25
use_synth :dsaw
play 50
sleep 0.25
use_synth :prophet
play 57
sleep 0.25

Nota que o comando usar_sintetizador só afecta as chamadas que se seguem do play. Pensa nele como um interruptor – novos plays vão tocar o synth mais recente. Podes mudar o synth a usar com um novo use_synth.

Decobrindo o Som dos Sintetizadores

Para saberes que synths o Sonic Pi tem para brincares dá uma olhadela na opção Synth no sistema de ajuda (à esquerda de Fx). Existem mais de 20 por onde escolher. Aqui estão alguns dos meus favoritos:

‘:prophet’ ‘:dsaw’ ‘:fm’ ‘:tb303’ ‘:pulse’

Agora vamos brincar experimentado trocar os sintetizadores durante a musica. Diverte-te a combinar sintetizadores para criar sons novos e usar synths diferentes em diferentes secções da tua música.


2.4 - Duração com Envolventes

Numa secção anterior vimos como podemos usar o comando sleep para controlar quando tocar os nossos sons. Mas ainda não sabemos como controlar a duração dos nossos sons.

Para termos um meio simples, mas eficaz, de controlar a duração dos nossos sons, o Sonic Pi possibilita o control de uma curva de envolvente do tipo ADSR (vamos falar sobre o que ADSR significa mais à frente nesta secção). Uma curva de envolvente de amplitude oferece dois aspectos úteis de controlo:

controlo sobre a duração de um som controlo sobre a amplitude de um som

Duração

Duração é o tempo que durante o qual conseguimos ouvir o som. Uma duração mais longa faz com que ouçamos o som durante mais tempo. Todos os sons no Sonic Pi têm uma envolvente de amplitude controlável, e a duração total dessa envolvente é a duração do som. Portanto, controlando a envolvente, controlas não só a sua duração, como a curva de forma de onde do som

Amplitude

Além de controlar a duração, a envolvente ADSR também oferece um controlo excelente sobre a amplitude do som. Todos os sons audíveis começam e acabam com silêncio e contêm uma parte não silenciosa no meio. Os envolventes permitem deslizar e manter a amplitude das partes não silenciosas do som. É como dar instruções de como aumentar e diminuir o volume de um amplificador de guitarra. Por exemplo, podes pedir a alguém para “começar com silêncio, aumentar o volume lentamente até ao máximo, manter durante um bocado e depois diminuir rapidamente até silêncio”. O Sonic Pi permite programar este comportamento com curvas de envolvente.

Para recapitular, como vimos antes, uma amplitude de 0 é silêncio e uma amplitude de 1 é volume normal.

Agora, vamos ver cada uma das partes das curvas de envolvente.

fase de extinção

A única parte a envolvente que é usada por defeito é o tempo de extinsão do som (ou relaxamento). Isto é o tempo que o som de um sintetizador leva até desaparecer completamente. Todos os synths têm, por defeito, um tempo de extinsão de 1, o que significa que duram uma batida (que é 1 segundo, para BPM de 60):

play 70

Esta nota vai-se ouvir durante 1 segundo. Segue em frente e contabiliza a duração :-) Isto é a versão curta para a versão mais longa e explicita:

play 70, release: 1

Nota como soam exactamente iguais (o som dura 1 segundo). No entanto, agora é muito fácil alterar a duração mudando o valor da opt release::

play 60, release: 2

Podemos fazer com que o som dure muito pouco tempo usando um valor mais baixo para release::

play 60, release: 0.2

A duração do repouso do som chama-se fase de extinsão (ou repouso) e por defeito é uma transição linear (isto é, uma linha recta). O diagrama seguinte ilustra esta transição:

curva de envolvente da fase de extinção do som Copiar →↵…«»“”-–—

A linha vertical à esquerda do diagrama mostra que o som começa com amplitude 0, mas vai até a um nível de amplitude máximo imediatamente (isto é a fase de ataque, tal como vamos analisar de seguir). Tendo em conta a amplitude máxima, esta volta a baixar numa linha recta até 0, levando o tempo especificado pela opt release:. Tempos de repouso mais longos produzem fade outs mais longos.

Podes então mudar a duração do teu som ao mudar o tempo de repouso. Experimenta mudar os tempos de repouso da tua música.

Fase de Ataque

Por defeito, a fase de ataque é 0 para todos os synths, o que significa que a amplitude sobe de 0 para 1 imediatamente. Isto resulta num som inicialmente mais percursivo. No entanto, podes querer que o teu som tenha um fade in. Isto pode ser feito com a opt attack:. Experimenta usar fade in em alguns sons:

play 60, attack: 2
sleep 3
play 65, attack: 0.5

Pode querer usar váras opts ao mesmo tempo. Por exemplo, para um ataque curto e repouso longo, experimenta:

play 60, attack: 0.7, release: 4

Esta ataque curto e repouso longo está ilustrado no diagrama seguinte:

envolvente de ataque e extinção de um som Copiar →↵…«»“”-–—

Claro que podes é possível trocar. Tenta um ataque longo e repouso curto:

play 60, attack: 4, release: 0.7

Envolvente de Ataque Longo, com Tempo de Extenção Curto Copiar →↵…«»“”-–—

Finalmente, também é possível tirar proveito tanto um tempo de ataque como de extinção curtos para sons curtos.

play 60, attack: 0.5, release: 0.5

Envolvente de attune e extinção curtos Copiar →↵…«»“”-–—

Fase de Sustentação

Além de especificar os tempos de ataque e repouso, também podes mudar o tempo de sustentação para controlar a fase de sustentação. Isto é o tempo a que a amplitude se vai manter no máximo, entre as fases de ataque e repouso.

play 60, attack: 0.3, sustain: 1, release: 1

envolvente  deASR Copiar →↵…«»“”-–—

O tempo de sustentação é útil quando se pretende criar sons com mais presença na mistura, antes de entrar na fase de decaimento e extinção. Claro, é válido dar o valor de 0 às opts attack: e release: e usar só a sustentação para o som não ter nenhum fade in ou fade out. No entanto, deixamos o aviso, um tempo de repouso de 0 pode produzir clicks no som sendo melhor usar um valor muito baixo como 0.2.

Fase de Decaimento

Para um nível extra de controlo, também é possível especificar um tempo de decaimento. Esta é a fase do envelope que fica entre as fases de ataque e sustentação e especifica o tempo em que a amplitude vai baixar do attack_level: para o decay_level: (que, a não ser que o mudes explicitamente, vai ser o mesmo que o sustain_level:). Por defeito, a opt decay: é 0 e tanto o ataque (attack_leve:) como a sustentação (sustain_level:) são 1, portanto precisas de especificá-los para o tempo de decaimento fazer efeito:

play 60, attack: 0.1, attack_level: 1, decay: 0.2, sustain_level: 0.4, sustain: 1, release: 0.5

envolvente de ADSR Copiar →↵…«»“”-–—

Nível de Decaimento

Um último truque é que apesar da opt decay_level:, por defeito, ser igual ao sustain_level: podes dar-lhes valores diferentes para controlo total sobre o envelope. Isto permite-lhe criar envolventes como a seguinte:

play 60, attack: 0.1, attack_level: 1, decay: 0.2, decay_level: 0.3, sustain: 1, sustain_level: 0.4, release: 0.5

envolvente de ASR Copiar →↵…«»“”-–—

Também é possível contar um decay_level:, com um valor superior ao do sustain_level

play 60, attack: 0.1, attack_level: 0.1, decay: 0.2, decay_level: 1, sustain: 0.5, sustain_level: 0.8, release: 1.5

curva de envolvente envolvente ASR Copiar →↵…«»“”-–—

Curvas de Envolvente ADSR

Em suma, curvas de envolvente do tipo ADSR no Sonic Pi têm as seguintes fases:

ataque - tempo de amplitude 0 até ao attack_level: decaimento - tempo para mudar a amplitude de attack_level: até sustain_level: sustentação - tempo para mudar a amplitude de decay_level: até sustain_level: extinção - tempo para mudar a amplitude de sustain_leve: até 0

É importante notar que a duração de um som é a soma dos tempos de cada uma das fases. Portanto, o seguinte som vai durar 0.5 + 1 + 2 + 0.5 = 4 tempos:

play 60, attack: 0.5, attack_level: 1, decay: 1, sustain_level: 0.4, sustain: 2, release: 0.5

Agora vamos experimentar usar curvos de envolventes com os teus sons…


3 - Samples

Outra boa maneira de criar a tua música é usar sons pré-gravados. Em hip-hop chamamos, tradicionalmente, estes sons de samples. Se levares um microfone para a rua, e gravares o som da chuva a bater nas lonas, acabaste de criar um sample, passível de ser usado neste contexto.

O Sonic Pi permite-te fazer coisas espectaculares com samples. Não só traz um banco de mais de 90 samples de domínio público prontos para serem usados, como te deixa tocar e manipular os teus. Vamos lá…


3.1 - Trigar Samples

Tocar beeps é só o início. Uma coisa muito mais divertida é tocar samples pré-gravados. Experimenta:

sample :ambi_lunar_land

O Sonic Pi traz muitos samples passíveis de serem usados. Podes usá-las usando o comando play. Para tocar vários samples e notas basta escreve-los de forma sequencial:

play 36
play 48
sample :ambi_lunar_land
sample :ambi_drone

Se quiseres separá-los temporalmente, usa o comando sleep:

sample :ambi_lunar_land
sleep 1
play 48
sleep 0.5
play 36
sample :ambi_drone
sleep 1
play 36

Nota como o Sonic Pi não espera que os sons acabem de tocar antes de começar a tocar o seguinte. O comando sleep só conta o espaço de tempo entre o início de dois sons(sejam eles samples ou beeps). Isto permite criar sons facilmente, assim como sobreposição de efeitos. Mais tarde neste tutorial vamos ver como controlar a duração de sons com envolventes.

Descobrir Samples

Existem duas maneiras de descobrir que samples o Sonic Pi já traz. Primeiro, podes usar o sistema de ajuda. Clica em Samples no menu vertical da esquerda, escolhe uma categoria e vais ver uma lista com os samples disponíveis.

Alternativamente, podes usar o sistema de auto-completação. Basta escreveres o início de um grupo de samples, como: sample :ambi_ e vais ver um menu suspenso com nomes de samples. Experimenta os prefixos de categorias seguintes:

‘:ambi_’ :bass_ :elec_ :perc_ :guit_ :drum_ :misc_ :bd_

Experimenta agora misturar samples nas tuas peças!


3.2 - Parâmetros dos Samples: Amplitude e Panorâmica

Como vimos com sintetizadores, podemos, facilmente, controlar sons através do seu sistema de parametrização. Os samples suportam exactamente o mesmo mecanismo de parametrização. Vamos reexaminar os parâmetros amp: e pan:.

Usar Amplitude com samples

Podes alterar a amplitude de samples com a mesma abordagem que usaste para os sintetizadores:

sample :ambi_lunar_land, amp: 0.5

Usar Panorâmica com Samples

Também podemos usar o parâmetro pan: com samples. Por exemplo, podemos repoduzir o Amen Break no ouvido esquerdo e depois, a meio, tocá-lo outra vez pelo ouvido direito:

sample :loop_amen, pan: -1
sleep 0.877
sample :loop_amen, pan: 1

Nota que 0.877 é metade da duração da sample :loop_amen em segundos.

Finalmente, nota que se alterares algums valores pré-definidos dos sintetizadores com use_synth_defaults (vamos falar mais tarde), estes vão ser ignorados pelo sample


3.3 - Aplicar time stretching em Samples

Agora que sabemos como tocar uma variedade de sintetizadores e samples para criar música, está na hora de aprender a modificar tanto sintetizadores como samples para criar música com um som mais pessoal e consequentemente interessante. Primeiro, vamos explorar a possibilidade de aplicar time-stretching em samples.

Representação de Samples

Samples são sons pré-gravados, guardados como números que representam como o diafragma da coluna em movimento com vista a gerar som. O diafragma da coluna pode mover-se para dentro ou fora, e então, os números representam o quão dentro ou fora tem de estar o cone para cada momento no tempo. Um sample normalmente tem de guardar vários milhares de números por segundo para para poder ser reproduzido com qualidade e precisão. O Sonic Pi pega nesses números e dá-os à velocidade certa para mover a coluna para dentro e fora e reproduzir o som. Mas também é divertido mudar a velocidade a que os números são alimentam o processo de conversão de sinal digital analógico para que as colunas gerem som.

Mudar a Velocidade (Rate)

Vamos brincar com um dos sons de ambiente: :ambi_choir. Para tocá-la à velocidade (rate) normal, podes passar a opt rate: com o valor 1:

sample :ambi_choir, rate: 1

Isto toca o sample à velocidade normal (1), nada de especial para já. Mas, podemos mudar esse valor para outro qualquer. Que tal 0.5:

sample :ambi_choir, rate: 0.5

Wow! Que é que se passou aqui? Bem, duas coisas. Primeiro, o sample demora o dobro do tempo a ser reproduzido. segundo, o som está uma oitava abaixo. Vamos explorar estas coisas com um bocado mais de detalhe.

Vamos aplicar time-stretching ao som

Um sample que resulta muito bem com time-stretching é o “Amen Break”. À velocidade normal, poderiamos pô-la numa música de drum ‘n’ bass:

sample :loop_amen

Contudo, ao mudar a velocidade podemos eventualmente entrar em domínios estéticos, e consequentemente géneros musicais diferentes. Tenta, transpor o sample para metade da velocidade, para obter uma espécie de “hip-hop old school”:

sample :loop_amen, rate: 0.5

Se aumentarmos a velocidade entramos no território jungle:

sample :loop_amen, rate: 1.5

Agora para o nosso truque final – vamos ver o que acontece se usarmos um valor de rate (velocidade) negativo:

sample :loop_amen, rate: -1

Wow! Toca em sentido contrário! Agora experimenta samples diferentes com rates diferentes. Experimenta rates muito altas e muito lentas. Vê até que ponto consegues obter sons interessantes.

Uma Explicação simples do Termo Sample Rate

Uma maneira de pensar em samples é como molas. Mudar a rate é como esticar ou encolher um mola. Se tocarmos a sample com rate: 2, estamos a encolher a mola para metade do seu comprimento normal, e então o sample demora metade do tempo a tocar por ser mais curta. Se tocarmos a sample com rate: 0.5, estamos a esticar a mola para o dobro do seu comprimento e, portanto, a sample demora o dobro do tempo a tocar por ser mais longa. Quanto a encolhermos (rate mais alta), esta fica mais curta, quanto mais a esticares (rate mais baixa), mais longa fica.

Ao comprimir uma mola a sua densidade aumenta (número de voltas por cm) – isto faz com que o sample soe mais agudo. Ao esticar a mola a sua densidade diminui e isso faz com que o sample acabe por soar mais grave.

Vamos perceber o conceito de Sample Rate de um Ponto de Vista Matemático

(Esta parte é para aqueles interessados nos detalhes. Podes passar à frente se não for o teu caso…)

Como vimos anteriormente, um sample é representada por uma lista grelha de representação de valores ao nível das suas coordenadas polares e cartesianas e consequentemente na sua representação através de pfft (fast Fourier transform) e que acabam por ter uma correlação com a fase do som e indicar-nos o ponto onde a coluna se deve encontrar ao longo do tempo. Podemos pegar nessa lista de números e usá-la para desenhar um gráfico que seria parecido com este:

gráfico do sample Copiar →↵…«»“”-–—

Já deve ter visto imagens parecidas com esta anteriormente. Esta imagem consiste basicamente na forma de onda de um sample. É só uma gráfico de números. Normalmente, uma onda como esta terá 44100 pontos de informação por segundo (isto deve-se ao Teorema de Nyquist-Shannon), apesar de poder ter mais ou menos (48000, 96000, 192000, etc., resultando daí a necessidade de mais capacidade processamento, e consequentemente um nível superior de qualidade de audio, especialmente em processos de manipulação do áudio como time-stretching). Se o sample tiver a duração de 2 segundos, a onde vai ser representada por 88200 números, e iremos dar à coluna a uma velocidade de 44100 pontos por segundo. Claro, podíamos dá-los ao dobro da velocidade, que seria 88200 pontos por segundo. Levaria, portanto, apenas 1 segundo a tocar. Também podemos tocá-la a metade da velocidade, correspondente a 22050 pontos por segundo, demorando 4 segundos a tocar.

A duração de um sample sample é afectada pela velocidade (rate):

O Dobro do rate diminui a duração para metade, Metade do rate aumenta a duração para o dobro, Um rate de 1/4 multiplica a duração por quatro, Com um rate de 1/10 o sample acaba por durar 10 vezes mais.

Podemos representar isto com a seguinte fórmula:

new_sample_duration = (1 / rate) * sample_duration 

Mudar o rate também afecta a altura (não confundir com volume!) da sample. A frequência, ou altura, de uma onda é determinada pela velocidade com que esta se move para cima ou para baixo. O nosso cérebro, de alguma forma, transforma o movimento rápido das colunas em notas agudas e movimento lento em notas graves. É por isso que às vezes conseguimos ver as colunas a mexer.

Se pegarmos numa onda e a encolhermos, ela vai mover-se para cima e para baixo mais vezes durante o nosso período de tempo, que corresponde a um segundo (uma vibração por segundo corresponde. a um hz). Isto faz com que o som soe mais agudo. Acontece que ao duplicar o número de oscilações (movimentos para cima e para baixo) duplica a frequência. Então, tocar uma sample ao dobro do rate e isto duplica também a frequência a que esta é ouvida. Do mesmo modo, diminuir o rate para metade vai diminuir a frequência para metade. Outros rates vão afectar a frequência da mesma maneira.


3.4 - Samples controlados por curvas de envolvente

Também é possível modificar a duração e amplitude de um sample usando uma curva de envolvente do tipo ADSR. Contudo, isto funciona de forma ligeiramente diferente para curvas de envolvente ADSR disponíveis em sintetizadores. As curvas de envolvente dos samples apenas permitem reduzir a amplitude e duração de um sample - e acabam por não permitir aumenta-la. O sempre irá parar quando tanto o sample tiver terminado de tocar e a envolvente estiver concluída - que acaba por ser primeiro. Portanto, usa um valor de ‘release’ longo, e acabarás por não estender a duração do sample.

Curvas de Envolvente do Amen Sample

Vamos voltar ao nosso sample de eleição Amen Break:

sample :loop_amen

Sem opts, ouvimos o sample completo, com toda a sua amplitude. Se quisermos fazer um fade durante 1 segundo usamos o parâmetro ‘ataque’:

sample :loop_amen, attack: 1

Para um fade in mais curto, escolha um valor de ataque mais curto:

sample :loop_amen, attack: 0.3

Sustain Automático

As curvas de envolvente do comportamento do ADSR difere da envolvente do sintetizar standard, ou pre-definido, no valor de sustain. Na envolvente do sintetizador pré-definida, o sustain é 0 por pré-definição a não ser que seja manualmente definido. Com samples, o valor de sustain é definido como default, para um valor automático - o tempo que demora a tocar o resto do sample. É por isto que nós ouvimos o sample completo quando passamos sem pré-definições. Se os valores de ataque, decay, sustain, e release forem todos 0 nós acabamos por nunca ouvir um peep. O Sonic Pi, acaba então por calcular a duração do sample que super-impõe qualquer ataque decay, e tempos de release e usa o resultado como valor de sustain. Se o valor de ataque, decay e release for superior à duração do sample, o sustain é simplesmente definido como 0.

Fade Outs

Para explorar isto, vamos considerar o Amen Break para mais detalhe. Se perguntarmos ao Sonic Pi durante quanto tempo sample se mantém activo

print sample_duration :loop_amen

Isto irá imprimir o valor de 1.753310657596372 que possui a duração de um sample em segundos. Vamos agora arrendondá-lo para 1.75 para conveniência neste preciso momento. Agora, se definirmos a o valor do release para ‘0.75’, also surpreendente acabará por acontecer:

sample :loop_amen, release: 0.75

Irá tocar durante o primeiro segundo do sample num nível de amplitude/pressão sonora/intensidade dinâmica/SPL total, antes de fazer um fade de um período de cerca de 0.75 segundos. Isto é o sustain automático, em acção. Por pré-definição, o tempo de release, outra extinção do som, funciona sempre a partir do fim do sample. Se o nosso sempre tiver 10.75 segundos de duração, este irá tocar durante os primeiro s dez segundos da sua execução em amplitude total antes de fazer um fade out durante cerca de. 0.75s.

Lembre-se: por pré-definição, o valor de ‘release:’ diminui até ao fim do sample.

Fade In e Fade Out

Podemos usar tanto o valor de ‘ataque:’ e ‘release:’ juntos com o comportment de auto sustain para fazer tanto fade in como fade out durante a duração do sample:

sample :loop_amen, attack: 0.75, release: 0.75

Como a duração completamente do sample é 1.75s o nosso ataque e release (tempo de extinsão do som), demora cerca de 1.5s, sendo o sustain automaticamente definido para 0.25s. isto permite facilmente fazer fazer fade in e out do sample

Sustain explicito

Podemos facilmente voltar ao valor normal de ADSR do comportamento do sintetizador definindo manualmente o ‘sustain’ para um valor como 0:

sample :loop_amen, sustain: 0, release: 0.75

Agora, o nosso sample apenas reproduz durante 0.75 segundos no total. Por pré-definição o ‘ataque:’ e ‘decay:’ é 0, o sample salta automaticamente para a amplitude completa, adiciona ai os 0s e extinguindo-se então para 0 durante o perigo de release - 0.75s.

Címbalos percussivos

É possível usar este comportamento para afectar positivamente e tornar sons mais longos em sons mais pequenos, e versões mais permissivas. Considere por exemplo o sample ‘:drum_cymbal_open’

sample :drum_cymbal_open

É possível ouvir o som dos pratos (cymbal), a tocar durante um determinado período de tempo. Contudo, podemos usar a nossa curva de envolvente para o tornar, enfim, mais percussivo:

sample :drum_cymbal_open, attack: 0.01, sustain: 0, release: 0.1

É então possível emular o ataque de um prato (cymbal) e mantê-lo activo, aumentado o período de sustain

sample :drum_cymbal_open, attack: 0.01, sustain: 0.3, release: 0.1

Dedica-te agora a colocar curvas de envolvente nos samples. Tenta mudar a velocidade de sobremaneira para resultados realmente interessantes


3.5 - Samples Parciais

Esta secção tem como propósito concluir a exploração do reprodutor de simples do Sonic Pi. Vamos fazer uma pequena recapitulação. Até agora foca-mo-nos em possíveis abordagens com vista a disparar samples:

sample :loop_amen

Observamos então formas de mudar a velocidade de samples tais como tocá-los a a metade da sua velocidade:

sample :loop_amen, rate: 0.5

De seguida, ire-mo-nos focar em formas de introduzir um sample através de um fade in (vamos fazê-lo a metade da velocidade):

sample :loop_amen, rate: 0.5, attack: 1

Também olhámos a formas que nos permitem usar o começo de um sample percursivamente dando-lhe ‘sustain’: um valor explícito e definir tanto o ataque como a release (extinção do som), para valores relativamente curtos:

sample :loop_amen, rate: 2, attack: 0.01, sustain: 0, release: 0.35

Contudo, não seria interessante se nos não tivéssemos que começar no início do sample? Não também interessante se nós não tivesse que acabar sempre no fim do sample?

Escolhe um ponto de começo

É possível escolher um ponto de começo arbitrário no samples como um valor entre 0 e 1 onde 0 é o início do sample, 1 é o final, e 0.5 é metade da duração do sample. Vamos tentar tocar apenas a última parte do amen break:

sample :loop_amen, start: 0.5

E que tal um quarto do sample:

sample :loop_amen, start: 0.75

A escolher um ponto de conclusão

Do mesmo modo, é possível escolher um ponto arbitrário no sample como um valor entre 0 e 1. Vamos concluir a reprodução do amen break a metade da sua duração:

sample :loop_amen, finish: 0.5

A especificar o início e o final

Claro está, podemos combinar estas duas formas de reproduzir segmentos arbitrários dos ficheiros de audio. E que tal uma pequena secção no meio:

sample :loop_amen, start: 0.4, finish: 0.6

O que acontece se escolhermos um ponto inicial depois da posição final?

sample :loop_amen, start: 0.6, finish: 0.4

Porreiro! Toca em sentido contrário!

A combinar com a velocidade

É possível combinar esta possibilidade de tocar arbitrariamente segmentos do audio com o nosso amigo ‘velocidade:’. Por exemplo, podemos reproduzir um pequeno segmento do meio do amen break muito lentamente:

sample :loop_amen, start: 0.5, finish: 0.7, rate: 0.2

A combinar com curvas de envolvente

Finalmente, podemos combinar tudo isto com as nossas curvas de envolvente de ADSR para produzir resultados interessantes:

sample :loop_amen, start: 0.5, finish: 0.8, rate: -0.2, attack: 0.3, release: 1

Agora vamos e temos um mash up de samples em reprodução com todas estas coisas interessantes…


3.6 - Samples Externos

Enquanto que os samples incorporados permitem a alguém iniciar o processo de interacção com a plataforma rapidamente, podes desejar experimentar com outros gravados na tua música. O Sonic Pi suporta isto de forma integral. Primeiro, deixa-me ter uma pequena discussão acerca da portabilidade da tua peça.

Portabilidade

Quando compões uma peça apenas com samples e sintetizadores incorporados, o código é tudo o que precisas para reproduzir fielmente a tua música. Pensa nisto por um breve momento - é espetacular! Um pequeno excerto de texto permite-te enviar a música numa pen ou colocar o código no Gist representado tudo o que precisas para reproduzir os teus sons. Isto faz com que seja realmente simples partilhar com os teus amigos de forma a que eles precisem apenas do código para reproduzir a música

Contudo, se começares a usar os teus sons pré-gravados, perdes esta portabilidade. É por isso que ao reproduzir a tua música aos outras pessoas não precisem apenas do teu código, mas também precisem dos teus samples. Isto limita a possibilidade para outras pessoas manipularem, misturarem e experimentarem com o teu trabalho. É claro que não deves deixar de usar os teus samples, sendo apenas algo que deves considerar, decidindo então por ti a melhor forma para trabalhares.

Samples Locais

Portanto como é que fazes para tocar arbitrariamente um ficheiro WAV, AIFF ou FLAC no teu computador? Tudo o que precisas é de passar o cominho para esse ‘sample’.

# Raspberry Pi, Mac, Linux
sample "/Users/sam/Desktop/my-sound.wav"
# Windows
sample "C:/Users/sam/Desktop/my-sound.wav"

O Sonic Pir permite carregar automaticamente e tocar o sample. Também podes passar os parâmetros pré-definidos que costumas para passar como ‘sample’:

# Raspberry Pi, Mac, Linux
sample "/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3
# Windows
sample "C:/Users/sam/Desktop/my-sound.wav", rate: 0.5, amp: 0.3

3.7 - Pacotes de Samples

Nota: esta secção do tutorial cobre tópicos avançados de trabalho com grandes directórios dos teus próprios samples. Isto será o caso se tiveres feito download ou comprado o teu próprio pacote de samples e desejares usa-lo com o Sonic Pi.

Sente-te à vontade para saltar esta secção se estiveres contente com trabalhar com samples pré-incorporados

Quando te encontrares a trabalhar com ficheiros grandes ou ficheiros externos também pode ser espectaculérrimo escrever o caminho completo para disparar um sample individual

Por exemplo, vamos partir do princípio que tens a pasta abaixo na tua máquina:

/path/to/my/samples/

Quando olhamos para os conteúdos da pasta encontramos os seguintes samples:

‘100_A#_melody1.wav’ 100_A#_melody2.wav 100_A#_melody3.wav 120_A#_melody4.wav 120_Bb_guit1.wav 120_Bb_piano1.wav

Normalmente de modo a reproduzirmos o sample de piano apenas temo de usar o caminho completo:

sample "/path/to/my/samples/120_Bb_piano1.wav"

Se quisermos tocar o sample de guitarra podemos usar este caminho, também

sample "/path/to/my/samples/120_Bb_guit.wav"

Contudo, ambas as evocação do sample exigem que saibamos os nomes dos samples dentro da nossa directoria. E que tal se quisermos apenas ouvir cada um dos samples individualmente de forma rápida?

A indexar as Bibliotecas de Samples

Se quisermos reproduzir o primeiro sample na directoria apenas precisamos de passar o nome do directório para ‘sample’ e o index a ‘0’ tal como acontece abaixo

sample "/path/to/my/samples/", 0

Também podemos criar um atalho para a nossa directoria utilizando uma variável:

samps = "/path/to/my/samples/"
sample samps, 0

Se agora quisermos reproduzir a segunda amostragem na nossa directoria, apenas é necessário adicionar 1 ao nosso índice:

samps = "/path/to/my/samples/"
sample samps, 1

Note-se que não mais é preciso conhecer os nomes das amostragens na directoria - apenas necessitamos de conhecer a própria directoria (ou ter um atalho para ela). Se pedirmos um índice que é maior do que o número de amostragens, simplesmente dará a volta da mesma foram que Rings. Portanto, qualquer que seja o número que for utilizado, é garantido que vamos obter uma das amostragens nessa directoria.

Como filtrar Pacotes de Amostragens

Geralmente indexar é o suficiente, mas algumas vezes precisamos de mais capacidade para organizar os samples. No entanto, muitos pacotes de samples contém informações úteis nos nomes dos arquivos. Vamos dar uma olhada nos nomes dos arquivos de sample em nosso diretório.

‘100_A#_melody1.wav’ 100_A#_melody2.wav 100_A#_melody3.wav 120_A#_melody4.wav 120_Bb_guit1.wav 120_Bb_piano1.wav

Note que há boas informações nos nomes dos arquivos. Primeiro, BPM (batidas por minuto)

Podemos usar essa convenção de nomeclatura apresentada nos exemplos para ajudar a filtrar o que queremos. Por exemplo, se estamos trabalhando em 120 BPM, podemos filtrar todos os exemplos que contenham ‘“120’” da seguinte maneira:

samps = "/path/to/my/samples/"
sample samps, "120"

Isso tocará o primeiro resultado encontrado. Se quisermos o segundo, basta usar o índice:

samps = "/path/to/my/samples/"
sample samps, "120", 1

Podemos usar vários filtros ao mesmo tempo. Se quisermos um exemplo em que o nome do ficheiro contenha tanto “120” como “A#”, podemos usar o seguinte código:

samps = "/path/to/my/samples/"
sample samps, "120", "A#"

Finalmente, podemos usar nossas próprias definições para chamar o ‘sample’:

samps = "/path/to/my/samples/"
sample samps, "120", "Bb", 1, lpf: 70, amp: 2

Código

O filtro pre-arg aceita dois tipos de informação: código e filtros. Códigos são informações usadas para criar uma lista de resultados em potencial. Um código pode ter duas formas:

“/path/to/samples” - um comando representando um caminho válido para um diretório “/path/to/samples/foo.wav” - um comando representando um caminho válido para um sample

sample fn primeiro reunirá todos os códigos e os usará para criar uma grande lista de resultados possíveis. A lista é construída primeiro adicionando todos os caminhos de diretório válidos e depois todos os arquivos .flac, .aif, .aiff, .wav, .wave encontrados nos diretórios.

Por exemplo, dê uma olhada no seguinte código:

samps = "/path/to/my/samples/"
samps2 = "/path/to/my/samples2/"
path = "/path/to/my/samples3/foo.wav"
sample samps, samps2, path, 0

Aqui estamos combinando os samples encontrados em dois diretórios e adicionando um sample específico. Se "/path/to/my/samples/" contém 3 samples e "/path/to/my/samples2/" contém 12, temos 16 samples possíveis para indexar e filtrar ( 3+ 12 + 1).

Por padrão, apenas os arquivos de sample dentro de um diretório são colhidos para a lista de resultados possíveis. Algumas vezes você pode querer pesquisar e filtrar em subdiretórios. Para isso, use a busca recursiva adicionando ‘**’ ao final do diretório raiz.

samps = "/path/to/nested/samples/**"
sample samps, 0

Cuidado ao buscar em uma pasta com muitos subdiretórios porque poderá levar muito tempo. Porém, os conteúdos serão guardados para utilização posterior e a demora acontecerá apenas na primeira vez.

Finalmente, note que as fontes precisam de ser definidas inicialmente. Se nenhuma fonte é indicada, os samples de origem serão usados como candidatos na lista padrão de trabalho.

Filtros

Depois de teres uma lista de candidatos poderás usar os seguintes filtros para reduzir ainda mais a seleção:

"foo" As cadeias filtram ocorrências da sub-cadeia dentro do nome do ficheiro (menos o caminho da directoria e a sua extensão). /fo[oO]/ Usando o padrão de “Expressões Regulares” para filtrar o nome do ficheiro (menos o caminho da directoria e a extensão do ficheiro). :foo - Keywords filtra os candidatos com base na correspondência directa da palavra chave no nome do ficheiro (menos o caminho da directoria e a extensão do ficheiro). lambda{|a| ... } - Função PROC com um argumento será tratada como um filtro de candidatos ou uma função geradora. Recebe uma lista de candidatos actuais e devolve uma nova lista de candidatos (uma lista de caminhos para os ficheiros de samples). 1 - Números irão selecionar o candidato com esse índice (desdobrando o índice circularmente se necessário).

,Por exemplo. podemos filtrar sobre todos os samples de uma directoria que contêm a cadeia "foo"e tocar o sample com a primeira correspondência a meia velocidade:

sample "/path/to/samples", "foo", rate: 0.5

Consultar a ajuda para sample para exemplos mais detalhados de uso. Notar que a ordem dos filtros é honrada.

Compósitos

Finalmente, poderá ser usadas listas sempre que se colocar uma fonte ou filtro. A lista será “achatada” e o seu conteúdo será tratado como uma fonte regular ou filtro. Assim as seguintes chamadas a sample são semanticamente equivalentes:

sample "/path/to/dir", "100", "C#"
sample ["/path/to/dir", "100", "C#"]
sample "/path/to/dir", ["100", "C#"]
sample ["/path/to/dir", ["100", ["C#"]]]

Envolvendo

Esta é uma secção avançada para pessoas que necessitam verdadeiro poder para manipular e usar pacotes de samples. Se muito desta secção não fizer sentido não se preocupe. É provável que não necessite de nenhuma da sua funcionalidade por agora. No entanto, saberá quando necessitar e poderá regressar e reler a secção quando começar a trabalhar com grandes directorias de samples.


4 - Randomização

Uma boa maneira de adicionar algum interesse à musica é usando números aleatórios. Sonic Pi apresenta uma excelente funcionalidade em adicionar aleatoriedade à sua musica, mas antes de começar temos que aprender a verdade chocante: no Sonic Pi random não é verdadeiramente random. O que raio quer isto dizer? Bem, vamos ver.

Repetibilidade

Uma função verdadeiramente útil para gerar números aleatórios é rrand que devolve um número aleatório entre dois números - um min e um max (rrand é abreviatura de ranged random). Vamos tentar tocar uma nota aleatória:

play rrand(50, 95)

Ooh, tocou uma nota aleatória. Tocou a nota 83.7527. Um simpática nota entre 50 e 95. Espera, previ a mesma nota que tu? Algo estranho está a acontecer. Tenta correr o código novamente. O quê? Escolheu 83.7527 novamente? Isto não pode ser aleatório!

A resposta é que não é verdadeiramente aleatório, é pseudo-aleatório. Sonic Pi gera números pseudo-aleatórios de uma maneira repetível. Isto é bastante útil para assegurar que a musica que crias na tua maquina soa idêntica na maquina de qualquer pessoa - mesmo que use aleatoriedade na tua composição.

Claro que, numa dada peça de musica, se ‘aleatoriamente’ escolhe 83.7527todas as vezes, não seria muito interessante. No entanto, não o faz. Experimente o seguinte:

loop do
  play rrand(50, 95)
  sleep 0.5
end 

Sim! Finalmente soa a aleatório. Numa dada run subsequentes chamadas à função random devolve valores aleatórios. No entanto, a próxima corrida ira produzir exactamente a mesma sequência de valores aleatórios e soa exactamente igual. É como se todo o código do Sonic Pi regressa-se no tempo exactamente ao mesmo ponto cada vez que se pressiona o botão Run. É o dia do Groundhog da síntese musical!

Sinos amaldiçoados

Uma bonita ilustração da aleatoriedade em acção é o exemplo dos sinos amaldiçoados em que o loop do sample :perc_bell é tocado a uma velocidade e tempo de descanço aleatorio entre os sons de sinos.

loop do
  sample :perc_bell, rate: (rrand 0.125, 1.5)
  sleep rrand(0.2, 2)
end

Cutoff aleatório

Outro exemplo giro de aleatoriedade é a modificação do cutoff de um sintetizador de forma aleatória. Um bom sintetizador para experimentar isto é o emulador :tb303:

use_synth :tb303
loop do
  play 50, release: 0.1, cutoff: rrand(60, 120)
  sleep 0.125
end

Sementes para gerar números aleatórios

Então e se não gostares desta sequência em particular de números aleatórios que o Sonic Pi fornece? É totalmente possível escolher um diferente ponto de partida usando use_random_seed . A semente padrão usada para gerar números aleatórios é 0, escolhe uma semente diferente para uma diferente experiência aleatória!

Considera o seguinte:

5.times do
  play rrand(50, 100)
  sleep 0.5
end

Cada vez que corres este código, ouvirás a mesma sequência de 5 notas. Para ter uma diferente sequência simplesmente altera a semente:

use_random_seed 40
5.times do
  play rrand(50, 100)
  sleep 0.5
end

Isto irá produzir uma sequência diferente de 5 notas. Ao alterar a semente e ouvindo o resultado poderás encontrar algo que gostes - e depois partilhar com outros, eles ouviram exactamente o que ouviste.

Vamos ver algumas outras funções aleatórias úteis.

escolhe

Algo bastante comum de se fazer é escolher um item aleatoriamente de uma determinada lista de itens conhecidos. Por exemplo, posso querer tocar uma nota da seguinte lista: 60, 65 ou 72. Posso conseguir isso com chooseque me deixa escolher um item da lista. Primeiro coloco os meus números numa lista o que é feito envolvendo-os em parênteses rectos separados por virgulas: [60, 65, 72]. A seguir só temos que os passar ao choose:

choose([60, 65, 72])

Vamos ouvir como soa:

loop do
  play choose([60, 65, 72])
  sleep 1
end

rrand

Já vimos rrand, mas voltando a ela. Ela devolve um número aleatório entre dois números exclusivamente. Isso significa que numa irá fornecer o máximo ou o mínimo - mas sim sempre algo entre os dois. O número será sempre um número flutuante - que não é um numero inteiro mas sim a fracção de um numero. Exemplo de números flutuantes devolvidos por rrand(20,110):

87.5054931640625 86.05255126953125 61.77825927734375

rrand_i

Ocasionalmente queremos um número inteiro e não um flutuante. É ai que a rrand_i nos vem ajudar. Trabalha da forma similar a ´rrandexcepto que pode devolver o min e o max como potencial número aleatório (o que significa que é inclusivo e não exclusivo nos limites). Exemplos de números devolvidos por rrand_i(20,100)` são:

88 86 62

rand

Isto devolve um número aleatório flutuante entre 0 (inclusive) e um valor máximo especificado (exclusivo). Por padrão irá devolver um valor entre 0 e 1. É assim útil para escolher valores aleatórios amp::

loop do
  play 60, amp: rand
  sleep 0.25
end

rand_i

Similarmente à relação entre rrand_i e rrand, rand_i irá devolver um número aleatório inteiro entre 0 e o valor máximo que especificaste.

Dado

Às vezes queres emular o lançamento de um dado - isto é um caso especial de rrand_i em que o valor mais baixo é 1. Chamar dice requer que especifiques o número de lados do dado. Um dado normal tem 6 lados, assim dice(6) irá se comportar de forma semelhante - devolvendo os valores 1, 2, 3, 4, 5 ou 6. No entanto, tal como nos jogos de role play, poderás encontrar dados de 4 lados, ou 12 ou 20, ou até mesmo uma dado de 120 lados.

one_in

Finalmente poderás querer emular o lançamento de uma pontuação máxima num dado tal como um 6 num dado normal. one_in devolve true com a probabilidade de um sobre o número de lados do dado. Assim one_in(6) irá devolver true com a probabilidade de 1 em 6 ou false em caso contrario. True e false são valores muito úteis nas declarações condicionais if, que serão descritas nas seguintes secções deste tutorial.

Agora vai e enche o teu código de aleatoriedade!


5 - Estruturas de programação

Agora que aprendemos o básico de como criar sons com play e sample e a criação de melodias simples e ritmos usando sleep entre os sons, perguntas-te o que mais o mundo do código te pode oferecer…

Vais ter uma agradável surpresa! Estruturas básicas de programação como looping, condicionais, funções e threads dão-te ferramentas extremamente poderosas para expressares as tuas ideias musicais.

Vamos começar com o básico…


5.1 - Blocos

Uma estrutura que se vê bastante no Sonic Pi é um bloco. Um bloco permite-nos fazer coisas úteis com grandes pedaços de código. Podemos mudar algo que ocorre numa única linha de código com parâmetros de synth e sample. No entanto podemos querer fazer algo mais significativo a várias linhas de código. Por exemplo, podemos querer fazer um loop, adicionar reverb, apenas correr 1 vez a cada 5 vezes, etc. Considera o seguinte código:

play 50
sleep 0.5
sample :elec_plip
sleep 0.5
play 62

Para fazer algo com um pedaço de código devemos dizer ao Sonic Pi onde o bloco começa e onde acaba. Usamos do para o começo e end para o fim. Por exemplo:

do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

No entanto isto não está completo e não funcionará (tenta e terás um erro) uma vez que não dissemos ao Sonic Pi o que fazer com este bloco do/end. Dizemos isso aos Sonic Pi escrevendo um código especial antes do do. Iremos ver alguns destes pedaços especiais de código mais tarde neste tutorial. Por agora, é importante saber que envolvendo o teu código entre doe end diz ao Sonic Pi que queres fazer algo especial com esse pedaço de código.


5.2 - Iteração e Loops

Até agora passamos imenso tempo a olhar para diferentes sons que podemos fazer com blocos play e sample. Também aprendemos como lançar esses sons no tempo usando sleep.

Como provavelmente descobriste, existe muito divertimento que se tem com estes blocos básicos de construção. No entanto, uma dimensão totalmente nova de divertimento abre-se quando começares a usar o poder do código para estruturar a tua musica e composições. Nas próximas secções iremos explorar essas novas poderosas ferramentas. Primeiro iteração e loops.

Repetição

Escreveste algum código e gostarias de o repetir algumas vezes? Por exemplo, podes ter algo como isto:

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

Se quiseres repetir isto 3 vezes? O que podemos fazer é copiar e colar três vezes:

play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25
play 50
sleep 0.5
sample :elec_blup
sleep 0.5
play 62
sleep 0.25

Isso é muito código! O que acontece se quiseres mudar o sample para :elec_plip? Terás de encontrar todos os locais onde aparece o :elec_bluporiginal e os mudar. Mais importante, como repetir o código original 50 ou 1000 vezes? Isso é muito código, e muitas linhas de código para alterar se quiseres fazer uma mudança.

Iteração

De facto, alterar o código deverá ser fácil como dizer faz isto 3 vezes. Na verdade é isso. Lembraste do nosso velho amigo bloco de código? Podemos o usar para marcar o inicio e o fim do código que queremos repetir 3 vezes. Usamos então o código especial 3.times. Assim, em vez de escrever faz isto 3 vezes, escrevemos 3.time do - não é difícil. Não te podes esquecer de escrever end no final do código que queres repetir:

3.times do
  play 50
  sleep 0.5
  sample :elec_blup
  sleep 0.5
  play 62
  sleep 0.25
end

Isto assim é bem mais limpo que cortar e colar. Podemos usar isto para criar elegantes estruturas repetitivas:

4.times do
  play 50
  sleep 0.5
end
8.times do
  play 55, release: 0.2
  sleep 0.25
end
4.times do
  play 50
  sleep 0.5
end

Iterações aninhadas

Podemos colocar iterações dentro de iterações e produzir padrões interessantes. Por exemplo:

4.times do
  sample :drum_heavy_kick
  2.times do
    sample :elec_blip2, rate: 2
    sleep 0.25
  end
  sample :elec_snare
  4.times do
    sample :drum_tom_mid_soft
    sleep 0.125
  end
end

Looping

Se quiseres que algo repita muitas vezes, poderás dar por ti a usar números grandes como 1000.times do. Neste caso é provavelmente melhor pedir ao Sonic Pi para repetir para sempre (pelo menos até premires o botão stop). Vamos repetir o amen break para sempre:

loop do
  sample :loop_amen
  sleep sample_duration :loop_amen
end

a coisa importante a saber sobre loops é que eles actuam como buracos negros para o código. Uma vez que o código entra em loop nunca sairá até premires stop - irá repetir para sempre. Isso significa que se tiveres código após o loop nunca o irás ouvir. Por exemplo, o címbalo depois deste loop nunca será tocado:

loop do
  play 50
  sleep 1
end
sample :drum_cymbal_open

Agora podes estruturar o teu código com iterações e loops!


5.3 - Condicionais

Uma coisa comum que certamente quererás fazer é não tocar só notas aleatórias (ver a secção anterior em aleatoriedade) mas também tomar decisões aleatórias baseadas no resultado do código que corre ou nalgum outro código. Por exemplo, poderás querer aleatoriamente tocar uma bateria ou címbalo. Podemos conseguir isso com uma declaração if.

Lançar uma moeda

Então, vamos lançar uma moeda: se for cara, toca a bateria, se for coroa, toca o címbalo. Podemos emular o lançamento da moeda com a nossa função one_in (introduzida na secção de aleatoriedade), especificando a probabilidade de 1 em 2: one_in(2). Podemos usar esse resultado para decidir entre dois pedaços de código, o código que toca a bateria e o código que toca o címbalo.

loop do
  if one_in(2)
    sample :drum_heavy_kick
  else
    sample :drum_cymbal_closed
  end
  
  sleep 0.5
  
end

Repara que a declaração if tem 3 partes:

A questão a perguntar A primeira escolha de código a executar (se a questão à pergunta for sim) A segunda escolha de código a executar (se a resposta à questão for não)

Tipicamente em linguagens de programação, a noção de sim é representada pelo termo true e a noção de não é representada pelo termo false. Assim temos que arranjar uma questão que nos dirá uma resposta true ou false o que é exactamente isso que o one_in faz.

Repara como a primeira escolha está envolvida entre o if e o else e a segunda escolha está envolvida entre o else e o end. Tal como os blocos do/end poderás colocar múltiplas linhas de código nesses espaços. Por exemplo:

loop do
  if one_in(2)
    sample :drum_heavy_kick
    sleep 0.5
  else
    sample :drum_cymbal_closed
    sleep 0.25
  end
  
end

Desta vez estamos a dormir por um determinado tempo diferente dependendo da escolha que fazemos.

if simples

Por vezes queremos opcionalmente executar apenas uma linha de código. Isto é possível colocando o if e depois a questão no final. Por exemplo:

use_synth :dsaw
loop do
  play 50, amp: 0.3, release: 2
  play 53, amp: 0.3, release: 2 if one_in(2)
  play 57, amp: 0.3, release: 2 if one_in(3)
  play 60, amp: 0.3, release: 2 if one_in(4)
  sleep 1.5
end

Isto irá tocar o acorde de diferentes números com a possibilidade de cada nota ter uma diferente probabilidade.


5.4 - Threads

Fizeste uma killer bassline e um fat beat. Como os tocar ao mesmo tempo? Uma solução é interligar os dois manualmente - tocar algum baixo, depois um pouco de bateria, e mais algum baixo… No entanto, o tempo torna-se difícil de pensar, especialmente se começares a entrelaçar mais elementos.

E se o Sonic Pi pode-se entrelaçar as coisas por ti automaticamente? Bem, ele pode, e fazes isso com algo chamado thread.

Loops infinitos

Para manter este exemplo simples, terás que imaginar que isto é um fat beat e uma killer bassline:

loop do
  sample :drum_heavy_kick
  sleep 1
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end

Como discutimos previamente, loops são buracos negros para o programa. Uma vez neles nunca poderás sair até premires stop. Então como tocar ambos os loops ao mesmo tempo? Teremos que dizer ao Sonic Pi que queremos começar algo ao mesmo tempo que o resto do código. É ai que os threads vêm ao nosso auxilio.

Threads ao auxilio

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end

Envolvendo o primeiro loop num in_thread do bloco do/end dizemos aos Sonic Pi para correr o conteúdo do bloco exactamente ao mesmo tempo que a declaração seguinte ao bloco (que até é o segundo loop). Experimenta e ouvirás a bateria e o baixo entrelaçados.

Agora e se queremos adicionar um synth por cima. Algo como:

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
loop do
  use_synth :fm
  play 40, release: 0.2
  sleep 0.5
end
loop do
  use_synth :zawa
  play 52, release: 2.5, phase: 2, amp: 0.5
  sleep 2
end

Teremos o mesmo problema que anteriormente. O primeiro loop é tocado ao mesmo tempo que o segundo devido ao in_thread. No entanto, o terceiro loop nunca é alcançado. Assim necessitamos de outro thread:

in_thread do
  loop do
    sample :drum_heavy_kick
    sleep 1
  end
end
in_thread do
  loop do
    use_synth :fm
    play 40, release: 0.2
    sleep 0.5
  end
end
loop do
  use_synth :zawa
  play 52, release: 2.5, phase: 2, amp: 0.5
  sleep 2
end

Correr como threads

O que te pode supreender é que quando carregas no botão Run, está a criar um novo thread para o código correr. É por isso que carregando múltiplas vezes irá adicionar camadas de som umas sobre as outras. As próprias corridas são threads, elas irão entrelaçar automaticamente os sons por ti.

Scope

Quando aprenderes a conquistar o Sonic Pi, aprenderas que os threads são o bloco de construção mais importante da tua musica. Um dos importantes trabalhos que fazem é isolar a noção de settings actuais de outros threads. O que significa isso? Bem, quando trocas de synth usando o use_synth apenas estás a mudar de sintetizador na thread actual - nenhum outro thread terá a mudança de sintetizador. Vamos ver isto em pratica:

play 50
sleep 1
in_thread do
  use_synth :tb303
  play 50
end
sleep 1
play 50

Repara como o som do meio foi diferente dos restantes? A declaração use_synth apenas afectou o thread onde estava e não o thread principal exterior que corre.

Herança

Quando crias um novo thread com in_thread, o novo thread irá automaticamente herdar todas as settings actuais do thread corrente. Vamos ver isso:

use_synth :tb303
play 50
sleep 1
in_thread do
  play 55
end

Repara como a segunda nota foi tocada com o sintetizador :tb303 apesar de ter sido tocada de uma thread separada? Todas as settings modificadas com as várias funções use_* irão se comportar da mesma maneira.

Quando os threads são criados eles herdam todas as settings dos seus pais mas não passam para eles qualquer mudança que tenham.

Nomeando threads

Finalmente, podemos dar nomes aos nossos threads:

in_thread(name: :bass) do
  loop do
    use_synth :prophet
    play chord(:e2, :m7).choose, release: 0.6
    sleep 0.5
  end
end
in_thread(name: :drums) do
  loop do
    sample :elec_snare
    sleep 1
  end
end

Vê o painel de registro quando corres este código. Vê como o regsitro reporta o nome do thread na mensagem?

[Run 36, Time 4.0, Thread :bass]
 |- synth :prophet, {release: 0.6, note: 47}

Apenas é permitido um Thread por nome

Uma ultima coisa sobre nomear threads é que apenas um thread de um determinado nome pode estar a correr ao mesmo tempo. Vamos explorar isto. Considera o seguinte código:

in_thread do
  loop do
    sample :loop_amen
    sleep sample_duration :loop_amen
  end
end

Vamos lá e cola isso num buffer e carrega o butão Run. Carrega-o uma série de vezes. Ouve a cacofonia de vários amen break looping fora de tempo entre eles. Ok, podes carregar o Stop agora.

Este é o comportamento que vemos sempre - se carregares o botão Run, as camadas de som sobrepõem-se às do som existente. Assim se tiveres um loop e carregares o botão Run 3 vezes, terás 3 camadas de loops a correr simultaneamente.

No entanto, com threads com nome é diferente:

in_thread(name: :amen) do
  loop do
    sample :loop_amen
    sleep sample_duration :loop_amen
  end
end

Experimenta carregar o botão Run 3 vezes com este código. Apenas irás ouvir um amen break loop. Verás também isto no registro:

==> Skipping thread creation: thread with name :amen already exists.

Sonic Pi diz que um thread com o nome :amenjá está a tocar, e assim não irá criar outro.

Este comportamento pode não ser imediatamente útil para ti por enquanto - mas será muito quando começarmos com o live code…


5.5 - Funções

Quando começares a escrever muito código, podes querer encontrar uma maneira de organizar e estruturar as coisas que forma elegante e de fácil compreensão. Funções são maneiras muito poderosas de conseguir isso. Elas dão-nos a habilidade de dar nome a uma serie de código. Vamos dar uma olhada.

Definindo funções

define :foo do
  play 50
  sleep 1
  play 55
  sleep 2
end

Aqui definimos uma nova função chamada foo. Fazemos isso com o nosso amigo bloco do/end e a palavra magica define seguida pelo nome que queremos dar à nossa função. Não temos que a chamar foo, podemos chamar-lhe o que quisermos como bar, baz ou idealmente algo com sentido para ti como secção_principalou lead_riff.

Lembra-te de acrescentar dois pontos : ao nome da tua função quando a definires.

Chamando funções

Depois de definirmos a nossa função podemos a chamar escrevendo o seu nome:

define :foo do
  play 50
  sleep 1
  play 55
  sleep 0.5
end
foo
sleep 1
2.times do
  foo
end

Até podemos usar foo dentro de um bloco de iteração ou em qualquer lado que tenhamos escrito play ou sample. Isto dá-nos uma excelente maneira de nos expressar e cria palavras significativas para usar nas nossas composições.

As funções são recordadas ao longo das execuções

Até agora, cada vez que carregas no botão Run, o Sonic Pi começa completamente do zero. Ele não sabe nada excepto o que está no buffer. Não podes referir código noutro buffer ou noutra thread. No entanto as funções mudam isso. Quando defines a função, o Sonic Pi lembra-se dela. Vamos experimentar. Apaga todo o código na teu buffer e substitui por:

foo

Carrega no botão Run - ouve a tua função a tocar. Onde foi o código? Como é que o Sonic Pi sabe o que tocar? O Sonic Pi lembra-se da tua função - assim mesmo que apagues do buffer, ele lembra-se do que escreveste. Este comportamento apenas funciona com funções criadas usando o define (e defonce).

Funções parametrizadas

Podes estar interessado em saber que tal como tu podes passar valores mínimos e máximos a rrand, tu também podes ensinar as tuas funções a aceitar argumentos. Vamos dar uma olhada:

define :my_player do |n|
  play n
end
my_player 80
sleep 0.5
my_player 90

Isto não é muito excitante, mas ilustra o ponto. Criamos a nossa versão de playchamada my_playerque é parametrizada.

Os parâmetros devem vir a seguir ao do do bloco define, rodeados pela barra vertical | e separados por virgulas ,. Podes usar qualquer palavra para o nome dos parâmetros.

A magia acontece dentro do bloco define. Podes querer usar nomes de parâmetros como se fossem valores reais. Neste exemplo estou a tocar a nota n. Podes considerar que os parâmetros são uma espécie de promessa que quando o código corre serão substituídos por valores actuais. Fazes isso passando um parâmetro às função quando a chamas. Eu faço isso com my_player 80 para tocar a nota 80. Dentro da definição da função, né então substituído por 80, assim play nfica play 80. Quando a chamas novamente com my_play 90, o né substituído por 90 e play nfica play 90.

Vamos ver um exemplo mais interessante:

define :chord_player do |root, repeats| 
  repeats.times do
    play chord(root, :minor), release: 0.3
    sleep 0.5
  end
end
chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3

Onde usei repeat como se fosse um número na linha repeat.times do. Também usei root como se fosse o nome de uma nota na minha chamada a play.

Vê como podemos escrever algo muito expressivo e facil à leitura movendo muito da nossa lógica para uma função!


5.6 - 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 em um 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.


5.7 - Sincronização de Threads

Quando te tornares suficientemente avançado em live coding com uma serie de funções e threads simultaneamente, irás notar que é bastante fácil fazer em erro num dos threads e o matar. Isso não é muito importante porque o podes reiniciar carregando no Run. No entanto, quando reinicias o thread ele está fora de tempo com os threads originais.

Herança de tempo

Como discutimos anteriormente, novos threads criados com in_thread herdam todas as definições do thread pai. Isto inclui o tempo corrente. Isto significa que os threads estarão sempre sincronizados uns com os outros quando começarem simultaneamente.

No entanto, quando começas um thread por si só, o seu tempo é improvável estar sincronizado com qualquer dos outros threads em execução.

Fila e sincronização

O Sonic Pi oferece uma solução para este problema com as funções cuee sync.

cuepermite-nos enviar uma mensagem de “batimento cardiaco” para todos os outros threads. Por padrão os outro threads não estão interessados na mensagem. No entanto, podes registar interesse com a função sync.

A coisa importante a saber é que sync é similar a sleepna medida que pára o thread corrente de fazer alguma coisa por um período de tempo. No entanto, com sleepespecificas o tempo de espera enquanto com syncnão sabes quanto tempo tens de esperar - uma vez que syncespera pelo próximo cuede outro thread que pode ser logo ou após um longo tempo.

Vamos explorar isto em mais detalhe:

in_thread do
  loop do
    cue :tick
    sleep 1
  end
end
in_thread do
  loop do
    sync :tick
    sample :drum_heavy_kick
  end
end

Aqui temos 2 threads - um actuando como um metronomo, não tocando nenhum som mas enviando a mensagem de batimento:tick a cada beat. O segundo thread está sincronizado na mensagem tick e quando recebe um herda o tempo do thread do cue e continua a correr.

Como resultado, ouviremos o sample :drum_heavy_kick exactamente quando o outro thread envia a mensagem :tick, mesmo que o dois threads não começaram o seu tempo de execução ao mesmo tempo:

in_thread do
  loop do
    cue :tick
    sleep 1
  end
end
sleep(0.3)
in_thread do
  loop do
    sync :tick
    sample :drum_heavy_kick
  end
end

A chamada maldosa sleeptipicamente faria o segundo thread fora de fase com o primeiro. No entanto, como estamos a usar cue e sync, automaticamente sincronizamos os threads evitando qualquer offset de tempo acidental.

Nomes de Cues

És livre de usar qualquer nome que queiras para as tuas mensagens de cue- não apenas :tick . Só tens que assegurar que tal como os outros threads estão syncronizados no nome correcto - ou então ficarão à espera para sempre (ou até carregares no botão Stop).

Vamos jogar com alguns nomes de cues:

in_thread do
  loop do 
    cue [:foo, :bar, :baz].choose
    sleep 0.5
  end
end
in_thread do
  loop do 
    sync :foo 
    sample :elec_beep
  end
end
in_thread do
  loop do
    sync :bar
    sample :elec_flip
  end
end
in_thread do
  loop do
    sync :baz
    sample :elec_blup
  end
end

Aqui temos um cue loop principal que está aleatoriamente a enviar um batimento chamado :foo,:bar ou :baz. Temos também 3 loop threads sincronizando a cada um desses nomes independentemente e tocando um sample diferente. O efeito total é que ouvimos um som cada 0.5 batida porque cada syncthread é aleatoriamente sincronizado com a thread cue e toca o seu sample.

Isto claro que também funciona se inverteres a ordem dos threads pois eles os threads sync simplesmente esperam pela próxima cue.


6 - Estudio de efeitos

Um dos mais gratificantes e divertidos aspectos do Sonic Pi é a habilidade de facilmente adicionar efeitos de estúdio aos nossos sons. Por exemplo, podes querer adicionar algum reverb a partes das tua peça, ou algum eco ou até distorção ou vibração à tua linha de baixo.

Sonic Pi fornece uma maneira simples mas poderosa de adicionar efeitos. Até permite o encadeamento deles (para que possas passar os teus sons pela distorção, depois echo e depois reverb) e além disso controlar individualmente cada unidade de efeito com opts (numa maneira similar a dar parâmetros a synths e samples). Podes até modificar as opts dos efeitos com ele a correr. Assim por exemplo, podes aumentar o reverb do teu baixo ao longo da faixa…

Pedais de guitarra

Se tudo isto soa complicado, não te preocupes. Uma vez que brinques um pouco com isto, tudo se tornará claro. Até lá uma simples analogia é a de pedais de efeitos de guitarra. Existem muitos tipos diferentes de pedais de efeitos que podes comprar. Alguns adicionam reverb, outros distorcem, etc. Um guitarrista liga a guitarra um um pedal, p. ex. distorção -, depois com outro cabo conecta (encadeia) a um pedal de reverb. A saída do pedal de reverb pode então ser ligada ao amplificador:

Guitar -> Distortion -> Reverb -> Amplifier

Isto é chamado encadeamento de efeitos. O Sonic Pi suporta exactamente isto. Adicionalmente, cada pedal tem dials e sliders que te permitem controlar a quantidade de distorção e reverb, eco, etc. a aplicar. Sonic Pi também suporta este tipo de controlo. Finalmente imagina um guitarrista a tocar enquanto alguém controla os efeitos enquanto toca. O sonic Pi também suporta isto - mas em vez de necessitares alguém para controlar as coisas por ti, usamos o computador.

Vamos explorar os efeitos!


6.1 - Adicionando efeitos

Nesta secção iremos ver um par de efeitos: rever e eco. Veremos como os usar, como controlar as suas opts e como os podemos encadear.

O sistema de efeitos do Sonic Pi usa blocos. Se ainda não leste a secção 5.1 podes dar uma pequena mirada e depois regressar.

Reverb

Se queremos usar reverb escrevemos with_fx :reverb como o código especial do nosso bloco desta forma:

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Agora toca este código e ouviras a tocar com reverb. Soa bem, não soa! Tudo soa bem com reverb.

Agora vamos ver o que acontece se tivermos código fora do bloco do/end:

with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end
sleep 1
play 55

Repara que a nota final play 55não é tocada com reverb. Isto é porque está fora do bloco do/end, não sendo capturada pelo efeito reverb.

Similarmente, se fizeres sons antes do bloco do/end, também não serão capturados:

play 55
sleep 1
with_fx :reverb do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end
sleep 1
play 55

Eco

Existem muitos efeitos para escolher. Que tal algum eco?

with_fx :echo do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Um dos aspectos poderosos dos blocos de efeitos do Sonic Pi é que podem ser passadas opts similares às opts que já vimos com play e sample. Por exemplo uma opt divertida de se brincar é a phase: que representa a duração de um determinado eco em beats. Vamos tornar o eco mais lento:

with_fx :echo, phase: 0.5 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Vamos também ver o eco mais rápido:

with_fx :echo, phase: 0.125 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Vamos tornar o eco mais longo até desaparecer colocando o tempo de decay:para 8 beats:

with_fx :echo, phase: 0.5, decay: 8 do
  play 50
  sleep 0.5
  sample :elec_plip
  sleep 0.5
  play 62
end

Aninhando efeitos

Um dos mais poderosos aspectos dos blocos de efeitos é que podem ser aninhados. Isto permite facilmente encadear efeitos. Por exemplo, se quisermos tocar algum código com eco e a seguido de reverb? Fácil, basta colocar um dentro de outro:

with_fx :reverb do
  with_fx :echo, phase: 0.5, decay: 8 do
    play 50
    sleep 0.5
    sample :elec_blup
    sleep 0.5
    play 62
  end
end

Pensa no audio fluindo de dentro para fora. O som do código dentro no bloco do/end interior como o play 50 é primeiro enviado para o efeito de eco e o som do efeito de eco é então enviado para o efeito de reverb.

Podemos usar aninhamentos muito profundos para resultados estranhos. No entanto, um aviso, os efeitos podem usar muitos recursos, e quando os aninhas efectivamente estas a usar múltiplos efeitos simultaneamente. Limita o uso de efeitos especialmente em plataformas com pouco poder como o Raspberry Pi.

Descobrindo efeitos

O Sonic Pi vem com um grande número de feitos para brincares com eles. Para descobrires quais estão disponíveis, clica no botão FX no lado esquerdo deste sistema de ajuda e verás uma listagem das opções disponíveis. Aqui vai uma lista dos meus favoritos:

Ondular, reverb, eco, distorção, fatiador

Agora fica maluco e adiciona efeitos em todo lado para incríveis novos sons!


6.2 - Efeitos na pratica

Apesar de parecerem relativamente simples exteriormente, os efeitos são uma besta realmente complexa internamente. A sua simplicidade faz com que as pessoas os usem demasiado nas suas peças. Isto pode não ter importância se tiverem uma maquina poderosa mas se - tal como eu - usares uma Rasperry Pi para tocar, terás de ter atenção à quantidade de trabalho que pedes para fazer de forma a garantir que a batida continue a correr.

Considera este código:

loop do
  with_fx :reverb do
    play 60, release: 0.1
    sleep 0.125
  end
end

Neste código estamos a tocar a nota 60 com um muito pequeno tempo de release, é uma nota curta. Também queremos reverb assim embrulhamos num bloco de reverb. Até aqui tudo bem. Excepto…

Vamos ver o que este código faz. Primeiro temos um loop que significa que tudo dentro dele é repetido para sempre. A seguir temos um bloco with_fx. Isto significa que criamos um novo efeito de reverb cada vez que repetimos. Isto é como ter um pedal de reverb para cada vez que tocamos na corda da guitarra. É muito cool que se possa fazer isso, mas não é sempre o que queres fazer. Por exemplo, este código terá dificuldade em correr bem no Raspberry Pi. Todo o trabalho de criar o reverb e depois esperar até que tenha que ser parado e removido é tratado por with_fx por ti, mas isso requer poder de CPU que pode ser precioso.

Como o tornamos mais similar ao setup tradicional em que o guitarrista tem apenas um pedal de reverb e todo o som passa por ele? Simples:

with_fx :reverb do
  loop do
    play 60, release: 0.1
    sleep 0.125
  end
end

Colocamos o nosso loop dentro do bloco with_fx. Desta forma apenas criamos um simples reverb para todas as notas do nosso loop. Este código é muito mais eficiente e executa bem num Raspberry Pi.

Um compromisso é usar with_fxnuma iteração dentro do loop:

loop do
  with_fx :reverb do
    16.times do
      play 60, release: 0.1
      sleep 0.125
    end
  end
end

Desta forma tiramos o with_fxfora da parte interior do loope criamos um novo reverb a cada 16 notas.

Este é um padrão muitos comum que o with_fx suporta uma opção que faz exactamente isto mas sem ter de escrever o bloco 16.times.

loop do
  with_fx :reverb, reps: 16 do
    play 60, release: 0.1
    sleep 0.125
  end
end

Tanto o exemplo reps: 16 como o 16.times do irão se comportar de forma idêntica. O resp: 16 essencialmente repete o código no bloco do/end 16 vezes assim podes usar um ou outro conforme preferires.

Lembra-te não existem erros, apenas possibilidades. No entanto, algumas destas abordagens terão diferentes sons e características de performance diferentes. Brinca com isso e usa a abordagem que soa melhor para ti trabalhando na performance dentro dos constrangimentos da tua plataforma.


7 - Controlando sons que correm

Até agora vimos como podemos despoletar synths e samples, a como podemos mudar as suas opções padrão como a amplitude, panorâmica, envelope e entre outras. Cada som despoletado é essencialmente o seu próprio som com a sua lista de opções durante a sua duração.

Não seria porreiro se pudesse-mos mudar as opções de som quando ele esta a ser tocado, tal como dobramos a corda de uma guitarra enquanto ela ainda esta a vibrar?

Estás com sorte - esta secção mostra-te como podes fazer exactamente isso.


7.1 - Controlando Synths em execução

Até agora apenas nos preocupamos em despoletar novos sons e efeitos. No entanto, o Sonic Pi dá-nos a habilidade de manipular e controlar sons em execução. Fazemos isso usando uma variável para capturar a referencia a um synth:

s = play 60, release: 5

Aqui temos uma variável de execução local s que representa o synth a tocar a nota 60. Nota que é run-local - não poderás aceder a ela a partir de outras corridas como as funções.

Depois de termos s, podemos começar a controlar-la via a função control:

s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

A coisa a reparar é que não estamos a despoletar 4 synths diferentes - estamos apenas a despoletar um synth e posteriormente mudamos o pitch 3 vezes, enquanto é tocado.

Podemos passar qualquer das opções padrão ao control, assim podes controlar coisas como amp:, cutoff: ou pan:.

Opções não controláveis

Algumas das opções não podem ser controladas depois do synth ter começado. Este é o caso para todos os parâmetros dos envelopes ADSR. Podes descobrir que opções podem ser controlados vendo a documentação no sistema de ajuda. Se na documentação diz Can not be changed once set, saberás que não é possível controlar as opções depois do synth ter sido iniciado.


7.2 - Controlando os efeitos

É também possível controlar os efeitos, apesar de isto ser feito de uma maneira ligeiramente diferente:

with_fx :reverb do |r|
  play 50
  sleep 0.5
  control r, mix: 0.7
  play 55
  sleep 1
  control r, mix: 0.9
  sleep 1
  play 62
end

Em vez de usar uma variável, usamos um parâmetro de meta do bloco do/end. Dentro das barras |, necessitamos especificar um nome único para o nosso efeito em execução no qual então fazemos referencia no respectivo bloco do/end. Este comportamento é idêntico ao uso de funções parametrizadas.

Vai agora e controla alguns synths e efeitos!


7.3 - Opções deslizantes

Enquanto exploravas as opções dos synth e efeitos, poderás ter reparado que existe um número de opções terminando com _slide. Podes até ter tentado as chamar e não veres nenhum efeito. Isto é porque eles não são parâmetros normais, eles são opções especiais que apenas funcionam quando controlares synths como introduzido na secção anterior.

Considera o exemplo seguinte:

s = play 60, release: 5
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

Aqui, podes ouvir o pitch do synth mudar imediatamente a cada chamada a control. No entanto, podemos querer que o pitch deslize entre as mudanças. Ao controlarmos o parâmetro note:, para adicionar o deslizamento, necessitamos de definir o parâmetros note_slide no synth:

s = play 60, release: 5, note_slide: 1
sleep 0.5
control s, note: 65
sleep 0.5
control s, note: 67
sleep 3
control s, note: 72

Agora podemos ouvir as notas a serem dobradas entre as chamadas a control. Soa bem ,não soa? Podes acelerar o deslizamento usando um tempo mais curto como note_slide: 0.2 ou abrandar usando um tempo mais longo.

Cada parâmetro pode ser controlado como um parâmetro _slide correspondente para tu brincares com ele.

Deslizamento é permanente

Uma vez definido um parâmetro _slide num synth em execução, ele será lembrado e usado cada vez que deslizes o parâmetro correspondente. Para parar o deslizamento, terás que definir o valor de _slide a 0 antes da próxima chamada a control.

Deslizando opções de efeitos

É também possível deslizar opções de efeitos:

with_fx :wobble, phase: 1, phase_slide: 5 do |e|
  use_synth :dsaw
  play 50, release: 5
  control e, phase: 0.025
end

Agora diverte-te deslizando coisas para suavizar transições e controlo do fluxo…


8 - Estruturas de dados

Uma ferramenta muito útil na caixa de ferramentas de um programador é uma estrutura de dados.

As vezes podes querer representar e usar mais do que uma coisa. Por exemplo, pode ser útil teres uma serie de notas a tocar umas a seguir as outras. Linguagens de programação têm estruturas de dados que te permitem fazer exactamente isso.

Existem muitas estruturas de dados excitantes e exóticas disponíveis para os programadores - as pessoas estão sempre a inventar novas. No entanto, por enquanto precisamos apenas de considerar uma muito simples - a lista.

Vamos ver em mais detalhe. Descrevemos a forma básica e depois como as listas podem ser usadas para representar escalas e acordes.


8.1 - Listas

Nesta secção vamos dar uma vista de olhos à estrutura de dados que é bastante útil - a lista. Já encontramos anteriormente na secção de aleatoriedade quando escolhíamos de uma lista de notas a tocar:

play choose([50, 55, 62])

Nesta secção iremos explorar o uso de listas para representar acordes e escalas. Primeiro vamos recapitular em como poderemos querer tocar um acorde. Lembra-te que se não usarmos o sleep, o som acontece todo ao mesmo tempo:

play 52
play 55
play 59

Vamos ver outras maneiras de representar este código.

Tocando uma lista

Uma das opções é colocar todas as notas numa lista: [52, 55, 59]. O nosso amigável play é suficientemente esperto para saber como tocar uma lista de notas. Tenta:

play [52, 55, 59]

Ooh, já é bastante melhor de se ler. Tocar uma lista de notas não te impede de usar qualquer outro parâmetro normalmente:

play [52, 55, 59], amp: 0.3

Claro, que poderás usar o nome tradicional das notas em vez do seu número MIDI:

play [:E3, :G3, :B3]

Aqueles sortudos que estudaram teoria musical poderão reconhecer o acorde como Mi Menor tocado na terceira oitava.

Acedendo à lista

Uma outra característica bastante útil numa lista é a habilidade de receber informação dela. Isto pode soar estranho, mas não é mais complicado do que alguém pedir para abrir o livro na pagina 23. Com uma lista, dizes, qual é o elemento do índice 23? A única coisa estranha é que os índices na programação geralmente começam do 0 e não do 1.

Com os índices das listas não contamos 1, 2, 3… Em vez disso contamos 0, 1, 2…

Vamos ver isto em mais detalhe. Vê esta lista:

[52, 55, 59]

Não existe nada assustador sobre isto. Agora, qual é o segundo elemento da lista? Sim , claro que é o 55. É fácil. Vamos ver se o computador dá a mesma resposta que nós:

puts [52, 55, 59][1]

Ok, isto é um pouco esquisito se não tinhas visto algo assim anteriormente. Acredita em mim, não é difícil. Existe 3 partes na linha acima: a palavra puts, a nossa lista 52, 55, 59 e o nosso índice[1]. Primeiro estamos a dizer puts porque queremos que o Sonic Pi imprima a resposta no registo. Segundo, estamos a dar a nossa lista e finalmente o índice está a perguntar pelo segundo elemento. Necessitamos de rodear o nosso índice com parênteses rectos e como a contagem começa do 0, o índice do segundo elemento é 1. Olha:

# indexes:  0   1   2
           [52, 55, 59]

Tenta correr o código puts [52, 55, 59][1]e verás 55 aparecer no registo. Muda o indice 1para outros índices, tenta listas maiores e pensa em como podes usar uma lista na próxima sessão de jam. Por exemplo, que estruturas musicais podem ser representadas por uma serie de números…


8.2 - Acordes

O Sonic Pi tem suporte incluído para nomes de acordes que devolverão listas. Tenta por ti próprio:

play chord(:E3, :minor)

Agora estamos a chegar a algum lado. Isso parece mais bonito que as listas em bruto (e são mais fáceis de ler para outras pessoas). Assim que outros acordes o Sonic Pi suporta? Bem, muitos. Tenta alguns destes:

chord(:E3, :m7) chord(:E3, :minor) chord(:E3, :dim7) chord(:E3, :dom7)

Arpejos

Podemos facilmente transformar acordes em arpejos com a função play_pattern:

play_pattern chord(:E3, :m7)

Ok, isto não é tão divertido - tocou muito devagar. play_pattern irá tocar cada nota na lista separada com uma chamada a sleep 1 entre cada chamada a play. Podemos usar outra função play_pattern_timed para especificar o nosso próprio tempo e acelerar as coisas:

play_pattern_timed chord(:E3, :m7), 0.25

Podemos até passar uma lista de tempos que ira ser tratada como um circulo de tempos:

play_pattern_timed chord(:E3, :m13), [0.25, 0.5]

Isto é equivalente a:

play 52
sleep 0.25
play 55
sleep 0.5
play 59
sleep 0.25
play 62
sleep 0.5
play 66
sleep 0.25
play 69
sleep 0.5
play 73

Qual preveres escrever?


8.3 - Escalas

O Sonic Pi suporta uma grande quantidade de escalas. Que tal tocar uma escala de Dó maior na 3 oitava?

play_pattern_timed scale(:c3, :major), 0.125, release: 0.1

Podemos até pedir mais oitavas:

play_pattern_timed scale(:c3, :major, num_octaves: 3), 0.125, release: 0.1

Que tal todas as notas de uma escala pentatónica?

play_pattern_timed scale(:c3, :major_pentatonic, num_octaves: 3), 0.125, release: 0.1

Notas aleatórias

Acordes e escalas são óptimas maneiras de constranger as escolhas aleatórias em algo significativo. Brinca com este exemplo que escolhe notas aleatórias do acorde Mi3 menor:

use_synth :tb303
loop do
  play choose(chord(:E3, :minor)), release: 0.3, cutoff: rrand(60, 120)
  sleep 0.25
end

Tenta diferentes acordes e distancias de corte.

Descobrindo acordes e escalas

Para saber que escalas e acordes são suportados pelo Sonic Pi simplesmente clica no botão Lang na esquerda estrema a este tutorial e escolhe acorde ou escala na lista de API. Na informação do painel principal, no final verás uma longa lista de acordes e escalas (dependendo de qual estiveres a ver).

Diverte-te e lembra-te, não existem erros, apenas oportunidades.


8.4 - Anéis

Um variação interessante às listas padrão são os anéis. Se sabes alguma programação, poderás conhecer buffers em anel ou arrays em anel. Aqui chamam-se apenas anéis - é curto e simples.

Na secção anterior sobre listas vimos que podíamos obter elementos dela usando o mecanismo de indexação:

puts [52, 55, 59][1]

O que acontece se queremos o índice 100? Bem, claramente que não existe elemento no índice 100 porque a lista só tem 3 elementos. Assim o Sonic Pi devolve nil que significa nada.

No entanto, considera que temos um contador tal como a batida corrente que aumenta continuamente. Vamos criar o nosso contador e a nossa lista:

counter = 0
notes = [52, 55, 59]

Podemos usar o nosso contador para aceder a nota na nossa lista:

puts notes[counter]

Boa, obtemos 52. Agora, vamos aumentar o nosso contador e obter outra nota:

counter = (inc counter)
puts notes[counter]

Fantástico, agora obtemos 55e se o fizéssemos outra vez obteria-mos 59. No entanto, se o fizéssemos outra vez, ficaríamos sem números na nossa lista e obteríamos nil. E se quiséssemos regressar ao inicio da lista novamente? É para isto que os anéis servem.

Criando anéis

Podemos criar anéis de duas maneiras. Ou usamos a função ring com os elementos do anel como parâmetros:

(ring 52, 55, 59)

Ou podemos usar uma lista normal e converter num anel enviando a mensagem .ring:

[52, 55, 59].ring

Indexando anéis

Depois de termos um anel, podemos usar exactamente da mesma maneira que usaríamos uma lista normal com a excepção que podemos usar índices que são negativos ou maiores que o tamanho do anel e eles enrolam de forma a apontar sempre para um elemento do anel:

(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59

Usando anéis

Imagina que estamos a usar uma variável que representa o número corrente do beat. Podemos usar isto como índice no nosso anel para buscar notas a tocar, ou tempos de release ou qualquer coisa útil que podemos armazenar no nosso anel independentemente do número de beat que estamos correntemente.

Escalas e acordes são anéis

Uma coisa útil é que as listas devolvidas por scale e chord são também anéis e permitem que os acedas com índices arbitrários.

Construtores de anéis

Além de ring existem algumas outras funções que constroem um anel por nós.

range convida-te a especificar um ponto de inicio, um ponto final e um tamanho de passo. bools permite usar 1s e 0s para sucintamente representar booleans. knitpermite-te tricotar uma sequência de valores repetidos. spread cria um anel de bools com uma distribuição Euclidiana.

Dá uma vista de olhos na documentação respectiva para mais informação.


8.5 - Cadeia de anéis

Para além de construtores como range e spread outra maneira de criar novos anéis é manipular anéis existentes.

Cadeia de comandos

Para explorar isto, vê este anel simples:

(ring 10, 20, 30, 40, 50)

E se o quisermos ao contrario? Usamos a cadeia de comando .reverse para pegar no anel e o rodar:

(ring 10, 20, 30, 40, 50).reverse  #=> (ring 50, 40, 30, 20, 10)

Agora, e se quisermos os 3 primeiros valores do anel?

(ring 10, 20, 30, 40, 50).take(3)  #=> (ring 10, 20, 30)

Finalmente, e se quisermos baralhar o anel?

(ring 10, 20, 30, 40, 50).shuffle  #=> (ring 40, 30, 10, 50, 20)

Múltiplas cadeias

Isto já é uma maneira poderosa de criar novos anéis. No entanto, o poder real vem quando encadeias alguns destes comando em conjunto.

Que tal baralhar o anel, largar o 1 elemento e obter os 3 posteriores?

Vamos fazer isso por etapas:

(ring 10, 20, 30, 40, 50) - o nosso anel inicial (ring 10, 20, 30, 40, 50).shuffle - baralhar - (ring 40, 30, 10, 50, 20) (ring 10, 20, 30, 40, 50).shuffle.drop(1) - retira 1 - (ring 30, 10, 50, 20) (ring 10, 20, 30, 40, 50).shuffle.drop(1).take(3) - obtem 3 - (ring 30, 10, 50)

Como podes ver acabamos de criar uma cadeia longa destes métodos adicionando-os em conjunto. Podemos combinar estes em qualquer ordem criando uma maneira extremamente rica e poderosa de gerar novos anéis a partir de existentes.

Imutabilidade

Estes anéis têm uma poderosa e importante propriedade. Eles são imutáveis o que significa que não podem mudar. o que quer dizer que encadeando estes métodos descritos nesta secção não mudam os anéis apenas criam novos anéis. Isto significa que estas livre de partilhar anéis entre threads e começar a encadear-los dentro de um thread sabendo que não irá afectar outros threads que estejam a usar o mesmo anel.

Cadeias de métodos disponíveis

Aqui está uma lista de cadeia de métodos disponíveis para brincares:

.reverse - devolve uma versão invertida do anel .sort- cria uma versão ordenada do anel .shuffle - cria uma versão baralhada do anel .pick(3) - devolve um anel com o resultado de chamar .choose 3 vezes .pick(3) - devolve um anel com o resultado de chamar .choose 3 vezes .take(5)- devolve um novo anel contendo apenas os primeiros 5 elementos drop(3)- devolve um novo anel com tudo excepto os 3 primeiros elementos butlast - devolve um novo anel sem o ultimo elemento do anel original .drop_last(3) - devolve um novo anel com os 3 últimos elementos originais em falta take_last(6) - devolve um novo anel com apenas os últimos 6 elementos originais .stretch(2) - repete 2 vezes cada elemento do anel original .repeat(3) - repete todo o anel original 3 vezes .mirror - adiciona ao anel original uma versão revertida dele próprio .reflect- o mesmo que mirror mas não duplica o valor do meio do anel .scale(2) - devolve um novo anel com todos os elementos multiplicados por 2 (assumindo que o anel apenas contem números)

Claro que estes métodos em cadeia podem receber também outros números. És livre de chamar .drop(5) em vez de .drop(3)se quiseres largar os primeiros 5 elementos.


9 - Live Coding

Um dos aspectos mais excitantes do Sonic Pi é que te permite escrever e modificar código ao vivo para criar musica, como uma performance ao vivo com uma guitarra. Uma vantagem desta abordagem é dar-te mais feedback enquanto compões (pôr um loop a correr enquanto ajustas o som até a perfeição). No entanto, a principal vantagem é que podes levar o Sonic Pi em palco e tocar com ele.

Nesta secção cobrimos os fundamentos de tornar as tuas composições de código estático em performances dinâmicas.

Agarrarem-se às cadeiras…


9.1 - Live Coding

Agora aprendemos o suficiente para começar a ter alguma diversão. Nesta secção iremos buscar de todas as outras secções e mostrar em como podes começar a fazer composições musicais ao vivo tornando-as numa performance. Necessitamos 3 ingredientes principais para isso:

A habilidade de escrever código que gera som - CHECK! Uma habilidade de escrever funções - CHECK! A habilidade de usar threads (nomeados) - CHECK!

Muito bem, vamos começar. Vamos codificar os nossos primeiros sons. Primeiro necessitamos de uma função contendo o código que queremos tocar. Vamos começar simples. Também queremos num loop chamar essa função num thread:

define :my_loop do
  play 50
  sleep 1
end
in_thread(name: :looper) do
  loop do
    my_loop
  end
end

Se isto te parece muito complicado para ti, volta a trás e relê a secção sobre funções e threads. Não é muito complicado se já dominares estas coisas.

O que temos aqui é uma definição de função que apenas toca a nota 50 e descansa por um beat. Depois definimos um thread chamado :looper que em loop chama my_looprepetidamente.

Se correres este código, ouvirás a nota 50 repetidamente uma e outra vez…

Fazendo alterações

Agora é quando o divertimento começa. Enquanto o código está a correr muda o 50 para outro número, talvez 55, depois prime o botão Run outra vez. WOW! Mudou! Em directo!

Não adicionou uma nova camada porque estamos a usar um thread com nome que apenas permite um thread para cada nome. Também o som mudou porque redefinimos a função. Demos a :my_loopuma nova definição. Quando o thread :looper repetiu simplesmente chamou a nova definição.

Experimenta mudar novamente, muda a nota, muda o tempo de descanso. Que tal adicionar uma definição use_synth? Por exemplo muda para:

define :my_loop do
  use_synth :tb303
  play 50, release: 0.3
  sleep 0.25
end

Agora soa bastante interessante, mas podemos apimentar as coisas. Em vez de tocar a mesma nota uma e outra vez, tenta tocar um acorde:

define :my_loop do
  use_synth :tb303
  play chord(:e3, :minor), release: 0.3
  sleep 0.5
end

Que tal tocar notas ao acaso do acorde:

define :my_loop do
  use_synth :tb303
  play choose(chord(:e3, :minor)), release: 0.3
  sleep 0.25
end

Ou usar um valor de cutoff aleatório:

define :my_loop do
  use_synth :tb303
  play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
  sleep 0.25
end

Finalmente, adiciona alguma bateria:

define :my_loop do
  use_synth :tb303
  sample :drum_bass_hard, rate: rrand(0.5, 2)
  play choose(chord(:e3, :minor)), release: 0.2, cutoff: rrand(60, 130)
  sleep 0.25
end

Agora as coisas estão a ficar excitantes!

No entanto, antes de saltares e começares a codificar ao vivo com funções e threads, pára o que estas a fazer e lê a próxima secção sobre live_loop que irá mudar a forma como escreves código no Sonic Pi para sempre…


9.2 - Live Loops

Ok, esta secção do tutorial é uma verdadeira gema. Se apenas leres uma secção, deveria ser esta. Se leste as secções anteriores sobre os fundamentos de codificar ao vivo, live_loop é uma simples maneira de fazer isso mas sem ter que escrever muito código.

Se não leste a secção anterior, live_loopé a melhor maneira de improvisar com o Sonic Pi.

Vamos tocar. Escreve o seguinte num buffer novo:

live_loop :foo do
  play 60
  sleep 1
end

Agora prime o botão Run. Ouviras o beep básico. Nada de especial por aqui. No entanto, não primas Stop ainda. Muda o 60 para 65 e clica no Run outra vez.

WOW! Mudou automaticamente sem perder a batida. Isto é Live coding.

Porque não mudar para algo mais parecido com baixo? Actualiza o teu código enquanto corre:

live_loop :foo do
  use_synth :prophet
  play :e1, release: 8
  sleep 8
end

Depois prime Run.

Vamos fazer mudanças ao cutoff:

live_loop :foo do
  use_synth :prophet
  play :e1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Prime o botão Run outra vez.

Adiciona bateria:

live_loop :foo do
  sample :loop_garzul
  use_synth :prophet
  play :e1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Muda a nota de e1 para c1:

live_loop :foo do
  sample :loop_garzul
  use_synth :prophet
  play :c1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end

Agora pára de me ouvir tocar e brinca tu próprio! Diverte-te!


9.3 - Múltiplos Live Loops

Considera o seguinte live loop:

live_loop :foo do
  play 50
  sleep 1
end

Podes ter-te perguntado porque necessita o nome :foo. O seu nome é importante porque significa que este live loop é diferente de todos os outros live loops.

Nunca pode haver 2 live loops a correr com o mesmo nome.

Isso quer dizer que se quisermos múltiplos live loops concorrentes, teremos que dar diferentes nomes:

live_loop :foo do
  use_synth :prophet
  play :c1, release: 8, cutoff: rrand(70, 130)
  sleep 8
end
live_loop :bar do
  sample :bd_haus
  sleep 0.5
end

Podemos agora actualizar e mudar cada live loop independentemente e tudo funciona.

Sincronizando live loops

Uma coisa que poderás já ter notado é que os live loops funcionam automaticamente com o mecanismo de cue do threaad que exploramos anteriormente. Cada vez que o live loop repete, ele gera um novo envento cue com o nome do live loop. Podemos então sync nestes cues para assegurar que os nossos loops estão sincronizados sem ter que parar alguma coisa.

Considera este código muito mal sincronizado:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.4
end
live_loop :bar do
  sample :bd_haus
  sleep 1
end

Vamos ver se conseguimos reparar o timing e a sincronização sem parar. Primeiro, vamos arranjar o loop :foo para fazer parar pelo factor de 1 - algo como 0.5 serve:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.5
end
live_loop :bar do
  sample :bd_haus
  sleep 1
end

Ainda não terminamos - notarás que os beats não se alinham correctamente. ISto é porque os loops estão fora de fase. Vamos resolver isso sincronizando um com o outro:

live_loop :foo do
  play :e4, release: 0.5
  sleep 0.5
end
live_loop :bar do
  sync :foo
  sample :bd_haus
  sleep 1
end

Wow, agora tudo está perfeitamente a tempo - tudo sem ter que parar.

Agora avança e codifica ao vivo com live loops!


9.4 - Ticking

Algo que darás por ti a fazer muitas vezes quando codificas ao vivo é looping por anéis. Irás colocar notas em anéis para melodias, pausas para ritmos, progressões de acordes, variações tímbricas, etc, etc.

Anéis tiquetantes

O Sonic Pi fornece uma ferramenta muito útil para trabalhar com anéis dentro de live_loops. É chamado o sistema de tick. Na secção sobre anéis falamos algo sobre o contador que está constantemente a aumentar, como o número da batida corrente. Ticks apenas implementam a ideia. Fornece-te a habilidade de tiquetaquear pelo anel. Vamos ver este exemplo:

counter = 0
live_loop :arp do
  play (scale :e3, :minor_pentatonic)[counter], release: 0.1
  counter += 1
  sleep 0.125
end

Isso é equivalente a:

live_loop :arp do
  play (scale :e3, :minor_pentatonic).tick, release: 0.1
  sleep 0.125
end

Aqui, estamos a buscar a escala pentatónica de Mi3 menor e tiquetaquear por cada elemento. Isto é feito adicionando .tick ao fim da declaração da escala. Este tick é local ao live loop, assim cada live loop pode ter o seu próprio tick independente:

live_loop :arp do
  play (scale :e3, :minor_pentatonic).tick, release: 0.1
  sleep 0.125
end
live_loop :arp2 do
  use_synth :dsaw
  play (scale :e2, :minor_pentatonic, num_octaves: 3).tick, release: 0.25
  sleep 0.25
end

Tick

Podes também chamar tickcomo função padrão e usar o valor como índice:

live_loop :arp do
  idx = tick
  play (scale :e3, :minor_pentatonic)[idx], release: 0.1
  sleep 0.125
end

No entanto, é muito melhor chamar .tick no final. A função tick é para quando queres fazer algo coisas mais bonitas com o valor de tick e para quando queres usar ticks com outras coisas que indexar em anéis.

Look

A coisa mágica sobre tick é que não só devolve um novo índice (ou o valor do anel nesse índice) mas também garante que a próxima vez que chamares o tick, é um novo valor. Vê os exemplos na documentação para tick para as muitas maneiras que podes trabalhar com ele. No entanto, por agora, é importante apontar que algumas vezes apenas queres ver o valor corrente de tick e não aumentar. Isso é conseguido através da função look. Podes chamar look como função padrão ou adicionando .look ao final do anel.

Nomeando ticks

Finalmente, algumas vezes necessitas de mais do que um tick por live loop. Isto é conseguindo dando nome a um tick:

live_loop :arp do
  play (scale :e3, :minor_pentatonic).tick(:foo), release: 0.1
  sleep (ring 0.125, 0.25).tick(:bar)
end

Aqui estamos a usar dois ticks, um para tocar as notas e outro para o tempo de pausa. Como ambos estão no mesmo live loop, para os manter separados necessitamos de lhes dar nomes únicos. Isto é exactamente a mesma coisa que nomear live_loops - apenas passamos o símbolo com o prefixo :. No exemplo acima chamamos um dos ticks :foo e o outro :bar. Se quisermos os look temos que passar o nome do tick a look.

Não o faças muito complicado

A maioria do poder do sistema de tick não é útil quando começas. Não tentes aprender tudo nesta secção. Foca-te no tiquetaque de um único anel. Isso dará a maioria da alegria da simplicidade do tiquetaque de anéis nos teus live_loops.

Dá uma vista de olhos na documentação sobre tick onde existe muitos exemplos úteis e tem um feliz tiquetaquear!


10 - Time State

Often it is useful to have information that is shared across multiple threads or live loops. For example, you might want to share a notion of the current key, BPM or even more abstract concepts such as the current ‘complexity’ (which you’d potentially interpret in different ways across different threads). We also don’t want to lose any of our existing determinism guarantees when doing this. In other words, we’d still like to be able to share code with others and know exactly what they’ll hear when they run it. At the end of Section 5.6 of this tutorial we briefly discussed why we should not use variables to share information across threads due to a loss of determinism (in turn due to race conditions).

Sonic Pi’s solution to the problem of easily working with global variables in a deterministic way is through a novel system it calls Time State. This might sound complex and difficult (in fact, in the UK, programming with multiple threads and shared memory is typically a university level subject). However, as you’ll see, just like playing your first note, Sonic Pi makes it incredibly simple to share state across threads whilst still keeping your programs thread-safe and deterministic..

Meet get and set


10.1 - Set e Get

Sonic Pi has a global memory store called Time State. The two main things you do with it are to set information and get information. Let’s dive deeper…

Set

To store information into the Time State we need two things:

the information we want to store, a unique name (key) for the information.

For example, we might want to store the number 3000 with the key :intensity. This is possible using the set function:

set :intensity, 3000

We can use any name for our key. If information has already been stored with that key, our new set will override it:

set :intensity, 1000
set :intensity, 3000

In the above example, as we stored both numbers under the same key, the last call to set ‘wins’, so the number associated with :intensity will be 3000 as the first call to set is effectively overridden.

Get

To fetch information from the Time State we just need the key we used to set it, which in our case is :intensity. We then just need to call get[:intensity] which we can see by printing out the result to the log:

print get[:intensity] #=> prints 3000

Notice that calls to get can return information that was set in a previous run. Once a piece of information has been set it is available until either the information is overridden (just like we clobbered the :intensity value of 1000 to 3000 above) or Sonic Pi is closed.

Threads

The main benefit of the Time State system is that it can be safely used across threads or live loops. For example, you could have one live loop setting information and another one getting it:

live_loop :setter do
  set :foo, rrand(70, 130)
  sleep 1
end
live_loop :getter do
  puts get[:foo]
  sleep 0.5
end

The nice thing about using get and set across threads like this is that it will always produce the same result every time you hit run. Go on, try it. See if you get the following in your log:

{run: 0, time: 0.0}
 └─ 125.72265625
{run: 0, time: 0.5}
 └─ 125.72265625
{run: 0, time: 1.0}
 └─ 76.26220703125
{run: 0, time: 1.5}
 └─ 76.26220703125
{run: 0, time: 2.0}
 └─ 114.93408203125
{run: 0, time: 2.5}
 └─ 114.93408203125
{run: 0, time: 3.0}
 └─ 75.6048583984375
{run: 0, time: 3.5}
 └─ 75.6048583984375

Try running it a few times - see, it’s the same every time. This is what we call deterministic behaviour and it’s really very important when we want to share our music as code and know that the person playing the code is hearing exactly what we wanted them to hear (just like playing an MP3 or internet stream sounds the same for all listeners).

A Simple Deterministic State System

rand

## Um exemplo de comportamento não-determinístico
## (devido a race conditions causadas por múltiplos
## loops manipulando a mesma variárvel ao mesmo tempo).
##  
## Se você executar este código você notará
## que a lista que é impressa
## nem sempre sai ordenada!
a = (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
  a = a.shuffle
  sleep 0.5
end
live_loop :sorted do
  a = a.sort
  sleep 0.5
  puts "sorted: ", a
end

Let’s take a look at how this might look using get and set:

## Um exemplo de comportamento determinístico
## (apesar do acesso simultâneo ao estado compartilhado)
## usando o novo sistema Time State do Sonic Pi.
##
## Quando este código é executado, a lista
## sempre é impressa de forma ordenada!
set :a, (ring 6, 5, 4, 3, 2, 1)
live_loop :shuffled do
  set :a, get[:a].shuffle
  sleep 0.5
end
live_loop :sorted do
  set :a, get[:a].sort
  sleep 0.5
  puts "sorted: ", get[:a]
end

Notice how this code is pretty much identical to the version using a variable before it. However when you run the code, it behaves as you would expect with any typical Sonic Pi code - it does the same thing every time in this case thanks to the Time State system.

Therefore, when sharing information across live loops and threads, use get and set instead of variables for deterministic, reproducible behaviour.


10.2 - Sincronização (Sync)

A seção 5.7 introduziu as funções cue e sync para lidar com problemas de sincronização de threads. O que não foi explicado é que é o sistema de Time State que fornece esta funcionalidade. É de tal forma que set is na realidade uma variação de cuee foi construído de forma que que possa trabalhar perfeitamente com o Time State - qualquer informaçãoque nós planejamos armazenar no Time State nós podemos sincronizar. Em outras palavras - nós sincronizamos synceventos que ainda serão inseridos no Time State.

Aguardando por eventos

Vamos dar uma olhada em como usar sync para esperar por novos eventos que serão inseridos ao Time State:

in_thread do
  sync :foo
  sample :ambi_lunar_land
end
sleep 2
set :foo, 1

Neste exemplo nós primeiro criamos uma thread que espera um evento :foo ser adicionado ao Time State. Após a declaração desta thread, nós esperamos por 2 batidas e então setamos (set) :foo para ser 1. Isso libera a sincronização (sync) que então segue para a próxima linha que dispara a amostra :ambi_lunar_land.

Note que sync sempre espera por eventos futuros e isso irá bloquear a a thread atual esperando por um novo evento. Também, irá herdar o tempo lógico da thread que chamou a sincronização através de set ou cue então pode também ser usado para sincronizar tempo.

Passando valores para o Futuro

No exemplo acima nós configuramos :foo igual a 1 e não fizemos nada com isso. Nós podemos, na verdade, recuperar este valor na thread chamando sync:

in_thread do
  amp = sync :foo 
  sample :ambi_lunar_land, amp: amp
end
sleep 2
set :foo, 0.5

Note que valores que são passados através de set e cue devem ser seguros - i.e. Rings imutáveis, números, símbolos ou strings congeladas. O Sonic Pi irá gerar um erro se o valor que você está tentando armazenar no Time State não for válido.


10.3 - Correspondência de Padrões

Para passar e recuperar informações para o Time State, é possível usar chaves mais complexas que símbolos básicos como :foo e :bar. Você também pode usar strings no formato URL, chamadas de Paths (caminhos) como "/foo/bar/baz". Depois que começãmos a usar paths, nós podemos começar a aproveitar o sofisticado sistema de correspondência de Padrões do Sonic Pi para usar get e sync com paths ‘similares’ em vez de ‘idênticos’. Vamos dar uma olhada.

Correspondência com qualquer parte do caminho (path)

Vamos assumir que nós queiramos esperar pelo próximo evento que tem três segmentos no path:

sync "/*/*/*"

Isto irá corresponder a qualquer evento Time State com exatamente três segmento, independente de seus nomes. Por exemplo:

cue "/foo/bar/baz" cue "/foo/baz/quux" cue "/eggs/beans/toast" cue "/moog/synths/rule"

Entretanto, não irá corresponder a paths com menos ou mais segmentos. Os seguintes paths não serão localizados:

cue "/foo/bar" cue "/foo/baz/quux/quaax" cue "/eggs"

Cada * (asterisco) significa qualquer conteúdo. Então nós podemos encontrar paths com somente um segmento com /* ou paths com cinco segmentos com /*/*/*/*/*

Encontrando segmentos parciais

Se soubermos como o segmento irá começar ou terminar, nós podemos usar um asterisco * junto com o nome parcial do segmento. Por exemplo: "/foo/b*/baz" irá corresponder a qualquer path com três segmentos, onde o primeiro é foo, o último é baz e o segmento do meio pode ser qualquer coisa que comece com b. Então irá corresponder a:

cue "/foo/bar/baz" cue "/foo/baz/baz" cue "/foo/beans/baz"

Mas não irá corresponder a:

cue "/foo/flibble/baz" cue "/foo/abaz/baz" cue "/foo/beans/baz/eggs"

Você pode colocar o * no início do segmento para especificar os últimos caracteres de um segmento: "/foo/*zz/baz" que iráo corresponder a quaisquer 3 segmentos cue ou set onde o primeiro segmento for foo, o último for baz e o segmento do meio termine com zz, como "cue "/foo/whizz/baz".

Encontrando correspondências em segmentos de paths aninhados

As vezes você não sabe quantos segmentos do path você quer achar a correspondência. Nestes casos, você pode usar os poderosos duplos asteriscos: ** como em "/foo/**/baz" que irão corresponder a:

cue "/foo/bar/baz" cue "/foo/bar/beans/baz" cue "/foo/baz" cue "/foo/a/b/c/d/e/f/baz"

Correspondendo a Letras Sozinhas

Você pode usar o caracter ? para comparar com um caracter apenas, como em "/?oo/bar/baz" que irá corresponder a:

cue "/foo/bar/baz" cue "/goo/bar/baz" cue "/too/bar/baz" cue "/woo/bar/baz"

Correspondendo a Múltiplas Palavras

Se você sabe que um segmento pode ser uma palavra de um certo conjunto de palavras, você pode usar { e } para especificar uma lista de opções como em "/foo/{bar,beans,eggs}/quux" que irão corresponder aos seguintes padrões:

cue "/foo/bar/quux" cue "/foo/beans/quux" cue "/foo/eggs/quux"

Correspondendo a Múltiplas Letras

Por fim, você pode comparar com uma seleção de letras se você usar [ e ] para especificar uma lista de possibilidades como em "/foo/[abc]ux/baz" que irá corresponder somente a:

cue "/foo/aux/baz" cue "/foo/bux/baz" cue "/foo/cux/baz"

Você também pode utilizar o caracter - para especificar sequências de letras. Por exemplo"/foo/[a-e]ux/baz" que irá corresponder somente a:

cue "/foo/aux/baz" cue "/foo/bux/baz" cue "/foo/cux/baz" foo foo

Combinando Correspondências

Ao chamar sync ou get você está livre para combinar localizadores de correspondência em qualquer ordem que você achar necessário para encontrar qualquer evento Time State criado por cue ou set. Vamos ver um exemplo doido:

in_thread do
  sync "/?oo/[a-z]*/**/ba*/{quux,quaax}/"
  sample :loop_amen
end
sleep 1
cue "/foo/beans/a/b/c/d/e/bark/quux/"

Correspondência de Padrões OSC

Para os curiosos, estas regras de correspondência são baseados na especificação de correspondência de padrões do Open Sound Control (controle de som aberto), que é explicado com detalhes em: http://opensoundcontrol.org/spec-1_0


11 - MIDI

Uma vez que você tiver dominado a conversão de código em música, você pode pensar - o que vem depois? As vezes, as limitações de trabalhar puramente dentro da sintaxe e do sistema de som do Sonic Pi podem ser excitantes e te colocar em uma nova posição criativa. Entretanto, as vezes é essencial libertar o código para o mundo real. Não queremos duas coisas extras:

Sermos capazes de converter ações do mundo real em eventos codificáveis do Sonic Pi Sermos capazes de usar o forte modelo de temporização e semântica do Sonic Pi para controlar e manipular objetos no mundo real

Por sorte, existe um protocolo que está por aí desde os anos 80, que permite este tipo de interação - MIDI. Existe um número incrível de aparelhos externos, incluindo teclados, controladores, sequenciadores e software profissional que suportam MIDI. Nós podemos usar o MIDI para receber dados e também para enviar dados.

O Sonic Pi fornece suporte completo para o protocolo MIDI possibilitando que você conecte seu Código Ao Vivo com o mundo real. Vamos explorá-lo um pouco mais…


11.1 - Entrada MIDI

Nesta seção vamos aprender como conectar um controlador MIDI para enviar eventos para o Sonic Pi, para controlar nossos sintetizadores e sons. Vá e pegue um controlador MIDI, como um teclado ou tablet de controle e vamos começar!

Conectando um controlador MIDI

Para receber no Sonic Pi informações de um aparelho MIDI externo, primeiro nós precisamos conectá-lo ao computador. Tipicamente isso é feito através de uma conexão USB, apesar de que aparelhos antigos usam um conector DIN de 5 pinos, para o qual será necessário suporte de hardware em seu computador (por exemplo: algumas placas de áudio possuem conectores DIN). Uma vez que você tenha conectado seu aparelho, abra o Sonic Pi e dê uma olhada na seção IO (Entrada/Saída) do painel de Preferências. Você poderá ver seu aparelho listado lá. Caso não veja, tente o botão ‘Reiniciar MIDI’ e veja se aparece. Se ainda assim você não encontrar nada, a próxima coisa a tentar é consultar as configurações MIDI do seu sistema operacional para ver se ele enxerga seu aparelho. Se tudo isso falhar, sinta-se a vontade para perguntar na sala de chat: http://gitter.im/samaaron/sonic-pi

Recebendo eventos MIDI

Assim que seu aperelho esteja conectado, o Sonic Pi irá receber eventos automaticamente. Você mesmo pode confirmar manipulando seu aparelho MIDI e olhando no registro de Deixas (cue logger), na janela do app em baixo à direita, abaixo do registro (se isso não estiver visível, vá em Preferências > Editor > Mostrar & Ocultar e habilite a caixa ‘Mostrar o registro de deixas’). Você verá um fluxo de eventos como:

/midi/nanokey2_keyboard/0/1/note_off  [55, 64]
/midi/nanokey2_keyboard/0/1/note_on   [53, 102]
/midi/nanokey2_keyboard/0/1/note_off  [57, 64]
/midi/nanokey2_keyboard/0/1/note_off  [53, 64]
/midi/nanokey2_keyboard/0/1/note_on   [57, 87]
/midi/nanokey2_keyboard/0/1/note_on   [55, 81]
/midi/nanokey2_keyboard/0/1/note_on   [53, 96]
/midi/nanokey2_keyboard/0/1/note_off  [55, 64]

Quando você ver um fluxo de mensagens desta forma, você terá conectado com sucesso seu aparelho MIDI. Parabéns, vamos ver o que você consegue fazer com ele!

MIDI Time State

MIDI

Controlando o Código

Agora que você conectou seu aparelho MIDI, viu seus eventos no registro e descobriu que nosso conhecimento do Estado de Tempo (Time State) é tudo o que precisamos para trabalhar com eventos, podemos começar a nos divertir. Vamos construir um piano MIDI simples:

live_loop :midi_piano do 
  note, velocity = sync "/midi/nanokey2_keyboard/0/1/note_on"
  synth :piano, note: note
end

Temos algumas coisas acontecendo no código acima, incluindo alguns problemas. Primeiro, temos um live_loop simples, que irá se repetir para sempre, executando o código entre os blocos do/end. Isto foi apresentado na seção 9.2. Segundo, estamos chamando o comando sync para esperar pelo próximo evento Time State correspondente. Usamos uma string representando a mensagem MIDI que estamos procurando (que é a mesma que foi exibida no registro). Note que esta string longa é fornecida pela função autocompletar do Sonic Pi, desta forma você não precisa digitar tudo a mão. No registro nós vemos que haviam dois valorespara cada nota MIDI no evento, então nós atribuímos o resultado a duas variáveis note e velocity. Por fim, nós disparamos o sintetizador :piano passando nossa nota.

Agora tente você. Digite o código acima, substitua a chave de sincronização com uma string correspondente ao seu aparelho MIDI e clique em Executar. Pronto, você tem um piano funcionando! Entretanto, você provavelmente notará alguns problemas: primeiro, todas as notas possuem o mesmo volume, independente da força que você usa no teclado. Isso pode ser consertado facilmente usando o valor velocity do MIDI e convertendo-o para amplitude. Dado que MIDI possui uma variação entre 0 e 127, para converter este número para um valor entre 0 e 1 nós só precisamos dividi-lo por 127:

live_loop :midi_piano do 
  note, velocity = sync "/midi/nanokey2_keyboard/0/1/note_on"
  synth :piano, note: note, amp: velocity / 127.0
end

Atualize o código e clique em Executar novamente. Agora a força aplicada ao teclado é respeitada. Em seguida, vamos nos livrar desta pausa irritante.

Removendo a Latência

Antes de remover a pausa, nós precisamos entender porque ela acontece. Para manter todos os sintetizadores e Efeitos sincronizados através de uma variedade de CPUs com capacidades diferentes, o Sonic Pi agenda o áudio antecipadamente em 0.5s por padrão. (Note que esta latência adicional pode ser configurada pelas funções set_sched_ahead_time! e use_sched_ahead_time). Estes 0.5s de latência estão sendo adicionados ao disparador do nosso sintetizador :piano assim como está sendo adicionado a todos os sintetizadores disparados pelo Sonic Pi. Tipicamente nós realmente queremos manter esta latência, já que isso significa que todos os sintetizadores estarão sincronizados. Entretanto, isso só faz sentindo para sintetizadores disparados por código, usando play e sleep. No nosso caso, na realidade estamos disparando o sintetizador :piano pelo nosso aparelho MIDI e portanto não queremos que o Sonic Pi controle o tempo por nós. Podemos desligar esta latência com o comando use_real_time, que desabilita a latência para a thread atual. Isto significa que você pode usar o modo Real Time para loops ao vivo controlado por sync com aparelhos externos, e manter a latência padrâo para todos os outros loops. Vejamos:

live_loop :midi_piano do 
  use_real_time
  note, velocity = sync "/midi/nanokey2_keyboard/0/1/note_on"
  synth :piano, note: note, amp: velocity / 127.0
end

Atualize seu código para que ele corresponda ao código acima e clique em ‘Executar’ novamente. Agora nós temos um piano com baixa latência e sensibilidade variável, programado em apenas 5 linhas.

Recuperando valores

Finalmente, como nossos eventos MIDI estão indo diretamente para o Time State, nós também podemos usar a função get para recuperar o último valor recebido. Isso não bloqueia a thread atual e retorna nil se não houver valor para ser recuperado (o que você pode sobrescrever passando um valor padrão - veja a ajuda para get). Lembre-se que você pode chamar get em qualquer thread a qualquer momento para ver o valor mais recente correspondente ao Time State. Você pode até usar time_warp para voltar no tempo e chamar get para ver eventos passados…

Agora Você Está no Controle

O mais importante é que agora você pode usar as mesmas estruturas de código para sincronizar e recuperar (sync e get) informações MIDI de qualquer aparelho MIDI e fazer o que você quiser com os valores. Você pode agora escolher o que seu aparelho MIDI irá fazer!


11.2 - Saída MIDI

Além de receber eventos MIDI nõs podemos também enviar eventos MIDI para disparar e controlar hardware de sintetizadores externos, teclados e outros aparelho. O Sonic Pi fornece um conjunto completo de funções para enviar várias mensagens MIDI como:

Ligar nota - midi_note_on Desligar nota - midi_note_off Mudança de controle - midi_cc Pitch bend - midi_pitch_bend Tiques do relógio - midi_clock_tick

Também existem muitas outras mensagens MIDI suportadas - verifique a documentação da API para todas as outras funções que começam com midi_.

Conectando um aparelho MIDI

In order to send a MIDI message to an external device, we must first have connected it. Check out the subsection ‘Connecting a MIDI Controller’ in section 11.1 for further details. Note that if you’re using USB, connecting to a device which you’re sending to (rather than receiving from) is the same procedure. However, if you’re using the classic DIN connectors, make sure you connect to the MIDI out port of your computer. You should see your MIDI device listed in the preferences pane.

Enviando eventos MIDI

The many midi_* fns work just like play, sample and synth in that they send a message at the current (logical) time. For example, to spread out calls to the midi_* fns you need to use sleep just like you did with play. Let’s take a look:

midi_note_on :e3, 50

This will send a MIDI note on event to the connected MIDI device with velocity 50. (Note that Sonic Pi will automatically convert notes in the form :e3 to their corresponding MIDI number such as 52 in this case.)

If your connected MIDI device is a synthesiser, you should be able to hear it playing a note. To disable it use midi_note_off:

midi_note_off :e3

Selecionando um aparelho MIDI

By default, Sonic Pi will send each MIDI message to all connected devices on all MIDI channels. This is to make it easy to work with a single connected device without having to configure anything. However, sometimes a MIDI device will treat MIDI channels in a special way (perhaps each note has a separate channel) and also you may wish to connect more than one MIDI device at the same time. In more complicated setups, you may wish to be more selective about which MIDI device receives which message(s) and on which channel.

We can specify which device to send to using the port: opt, using the device name as displayed in the preferences:

midi_note_on :e3, port: "moog_minitaur"

We can also specify which channel to send to using the channel: opt (using a value in the range 1-16):

midi_note_on :e3, channel: 3

Of course we can also specify both at the same time to send to a specific device on a specific channel:

midi_note_on :e3, port: "moog_minitaur", channel: 5

MIDI Studio

Finally, a really fun thing to do is to connect the audio output of your MIDI synthesiser to one of the audio inputs of your soundcard. You can then control your synth with code using the midi_* fns and also manipulate the audio using live_audio and FX:

reverb,

(The fn midi is available as a handy shortcut to sending both note on and note off events with a single command. Check out its documentation for further information).


12 - OSC

In addition to MIDI, another way to get information in and out of Sonic Pi is via the network using a simple protocol called OSC - Open Sound Control. This will let you send messages to and from external programs (both running on your computer and on external computers) which opens up the potential for control way beyond MIDI which has limitations due to its 1980s design.

For example, you could write a program in another programming language which sends and receives OSC (there are OSC libraries for pretty much every common language) and work directly with Sonic Pi. What you can use this for is only limited by your imagination.


12.1 - Receiving OSC

MIDI

A Basic OSC Listener

Let’s build a basic OSC listener:

foo

In this example we described an OSC path "/osc*/trigger/prophet" which we’re syncing on. This can be any valid OSC path (all letters and numbers are supported and the / is used like in a URL to break up the path to multiple words). The /osc prefix is added by Sonic Pi to all incoming OSC messages, so we need to send an OSC message with the path /trigger/prophet for our sync to stop blocking and the prophet synth to be triggered.

Sending OSC to Sonic Pi

We can send OSC to Sonic Pi from any programming language that has an OSC library. For example, if we’re sending OSC from Python we might do something like this:

from pythonosc import osc_message_builder
from pythonosc import udp_client
sender = udp_client.SimpleUDPClient('127.0.0.1', 4560)
sender.send_message('/trigger/prophet', [70, 100, 8])

Or, if we’re sending OSC from Clojure we might do something like this from the REPL:

(use 'overtone.core)
(def c (osc-client "127.0.0.1" 4560))
(osc-send c "/trigger/prophet" 70 100 8)

Receiving from External Machines

For security reasons, by default Sonic Pi does not let remote machines send it OSC messages. However, you can enable support for remote machines in Preferences->IO->Network->Receive Remote OSC Messages. Once you’ve enabled this, you can receive OSC messages from any computer on your network. Typically the sending machine will need to know your IP address (a unique identifier for your computer on your network - kind of like a phone number or an email address). You can discover the IP address of your computer by looking at the IO section of the preferences pane. (If your machine happens to have more than one IP address, hovering the mouse over the listed address will pop up with a list of all known addresses).

Note, some programs such as TouchOSC for iPhone and Android support sending OSC as a standard feature. So, once you’re listening to remote machines and know your IP address you can instantly start sending messages from apps like TouchOSC which enable you to build your own custom touch controls with sliders, buttons, dials etc. This can provide you with an enormous range of input options.


12.2 - Sending OSC

In addition to receiving OSC and working with it using Time State, we can also send out OSC messages in time with our music (just like we can send out MIDI messages in time with our music). We just need to know which IP address and port we’re sending to. Let’s give it a try:

use_osc "localhost", 4560
osc "/hello/world"

If you run the code above, you’ll notice that Sonic Pi is sending itself an OSC message! This is because we set the IP address to the current machine and the port to the default OSC in port. This is essentially the same as posting a letter to yourself - the OSC packet is created, leaves Sonic Pi, gets to the network stack of the operating system which then routes the packed back to Sonic Pi and then it’s received as a standard OSC message and is visible in the cue logger as the incoming message /osc:127.0.0.1:4560/hello/world. (Notice how Sonic Pi automatically prefixes all incoming OSC messages with /osc and then the hostname and port of the sender.)

Sending OSC to other programs

Of course, sending OSC messages to ourselves may be fun but it’s not that useful. The real benefit starts when we send messages to other programs:

use_osc "localhost", 123456
osc "/hello/world"

In this case we’re assuming there’s another program on the same machine listening to port 123456. If there is, then it will receive a "/hello/world OSC message with which it can do what it wants.

If our program is running on another machine, we need to know its IP address which we use instead of "localhost":

use_osc "192.168.10.23", 123456
osc "/hello/world"

Now we can send OSC messages to any device reachable to us via our local networks and even the internet!


13 - Multichannel Audio

So far, in terms of sound production, we’ve explored triggering synths and recorded sounds via the fns play, synth and sample. These have then generated audio which has played through our stereo speaker system. However, many computers also have the ability to input sound, perhaps through a microphone, in addition to the ability to send sound out to more than two speakers. Often, this capability is made possible through the use of an external sound card - these are available for all platforms. In this section of the tutorial we’ll take a look at how we can take advantage of these external sound cards and effortlessly work with multiple channels of audio in and out of Sonic Pi.


13.1 - Sound In

One simple (and perhaps familiar) way of accessing sound inputs is using our friend synth by specifying the :sound_in synth:

synth :sound_in

This will operate just like any synth such as synth :dsaw with the exception that the audio generated will be read directly from the first input of your system’s sound card. On laptops, this is typically the built-in microphone, but if you have an external sound card, you can plug any audio input to the first input.

Duração

One thing you might notice is that just like synth :dsaw the :sound_in synth only lasts for 1 beat as it has a standard envelope. If you’d like to keep it open for a little longer, change the ADSR envelope settings. For example the following will keep the synth open for 8 beats before closing the connection:

synth :sound_in, sustain: 8

Adicionando efeitos

Of course, just like any normal synth, you can easily layer on effects with the FX block:

with_fx :reverb do
  with_fx :distortion do
    synth :sound_in, sustain: 8
  end
end

If you have plugged in a guitar to your first input, you should be able to hear it with distortion and reverb until the synth terminates as expected.

You are free to use the :sound_in synth as many times as you like concurrently (just like you would do with any normal synth). For example, the following will play two :sound_in synths at the same time - one through distortion and one through reverb:

with_fx :distortion do
  synth :sound_in, sustain: 8
end
with_fx :reverb do  
  synth :sound_in, sustain: 8
end

Múltiplas cadeias

You can select which audio input you want to play with the input: opt. You can also specify a stereo input (two consecutive inputs) using the :sound_in_stereo synth. For example, if you have a sound card with at least three inputs, you can treat the first two as a stereo stream and add distortion and the third as a mono stream and add reverb with the following code:

with_fx :distortion do
  synth :sound_in_stereo, sustain: 8, input: 1
end
with_fx :reverb do  
  synth :sound_in, sustain: 8, input: 3
end

Potential Issues

However, although this is a useful technique, there are a couple of limitations to this approach. Firstly, it only works for a specific duration (due to it having an ADSR envelope) and secondly, there’s no way to switch the FX around once the synth has been triggered. Both of these things are typical requests when working with external audio feeds such as microphones, guitars and external synthesisers. We’ll therefore take a look at Sonic Pi’s solution to the problem of manipulating a (potentially) infinite stream of live audio input: live_audio.


13.2 - Live Coding

The :sound_in synth as described in the previous section provides a very flexible and familiar method for working with input audio. However, as also discussed it has a few issues when working with a single input of audio as a single instrument (such as a voice or guitar). By far the best approach to working with a single continuous stream of audio is to use live_audio.

A Named Audio Input

live_audio shares a couple of core design constraints with live_loop (hence the similar name). Firstly it must have a unique name and secondly only one live_audio stream with that name may exist at any one time. Let’s take a look:

foo

This code will act in a similar fashion to synth :sound_in with some key differences: it runs forever (until you explicitly stop it) and you can move it to new FX contexts dynamically.

Working with FX

On initial triggering live_audio works exactly as you might expect it to work with FX. For example, to start a live audio stream with added reverb simply use a :reverb FX block:

foo

However, given that live_audio runs forever (at least until you stop it) it would be pretty limiting if, like typical synths, the live audio was bound within the :reverb FX for its entire existence. Luckily this is not the case and it was designed to be easy to move between different FX. Let’s try it. Run the code above to hear live audio coming directly from the first input of your sound card. Note, if you’re using a laptop, this will typically be out of your built-in microphone, so it’s recommended to use headphones to stop feedback.

reverb,

foo

Now, hit Run, and you’ll immediately hear the audio played through the echo FX and no longer through reverb. If you wanted them both, just edit the code again and hit Run:

foo

foo

Stopping live audio

Unlike standard synths, as live_audio has no envelope, it will continue running forever (even if you delete the code, just like a function is still defined in memory if you delete the code in the editor). To stop it, you need to use the :stop arg:

foo

It can easily be restarted by calling it without the :stop arg again:

foo

Additionally all running live audio synths are stopped when you hit the global Stop button (as with all other running synths and FX).

Stereo input

With respect to audio channels, by default live_audio acts similarly to the :sound_in synth in that it takes a single mono input stream of audio and converts it to a stereo stream using the specified panning. However, just like :sound_in_stereo it’s also possible to tell live_audio to read two consecutive audio inputs and treat them as the left and right channels directly. This is achieved via the :stereo opt. For example, to treat input 2 as the left signal and input 3 as the right signal, you need to configure the input: opt to 2 and enable stereo mode as follows:

foo

Note that once you have started a live audio stream in stereo mode, you cannot change it to mono without stopping and starting. Similarly, if you start it in the default mono mode, you can’t switch to stereo without starting and stopping the stream.


13.3 - Sound Out

So far in this section we’ve looked at how to get multiple streams of audio into Sonic Pi - either through the use of the :sound_in synth or via the powerful live_audio system. In addition to working with multiple streams of input audio, Sonic Pi can also output multiple streams of audio. This is achieved via the :sound_out FX.

Output contexts

Let’s quickly recap on how Sonic Pi’s synths and FX output their audio to their current FX context. For example, consider the following:

with_fx :reverb do    # C
  with_fx :echo do    # B
    sample :bd_haus   # A
  end
end

The simplest way to understand what’s happening with the audio stream is to start at the innermost audio context and work our way out. In this case, the innermost context is labelled A and is the :bd_haus sample being triggered. The audio for this goes directly into its context which is B - the :echo FX. This then adds echo to the incoming audio and outputs it to its context which is C - the :reverb FX. This then adds reverb to the incoming audio and outputs to its context which is the top level - the left and right speakers (outputs 1 and 2 in your audio card). The audio flows outwards with a stereo signal all the way through.

Sound Out FX

The above behaviour is true for all synths (including live_audio) and the majority of FX with the exception of :sound_out. The :sound_out FX does two things. Firstly it outputs its audio to its external context as described above. Secondly it also outputs its audio directly to an output on your sound card. Let’s take a look:

with_fx :reverb do      # C
  with_fx :sound_out, output: 3 do # B
    sample :bd_haus     # A
  end
end

In this example, our :bd_haus sample outputs its audio to its external context which is the :sound_out FX. This in turn outputs its audio to its external context the :reverb FX (as expected). However, it also outputs a mono mix to the 3rd output of the system’s soundcard. The audio generated within :sound_out therefore has two destinations - the :reverb FX and audio card output 3.

Mono and Stereo out

escolhe

Direct Out

As we have also seen, the default behaviour for :sound_out and :sound_out_stereo is to send the audio both to their external context (as is typical of all FX) and to the specified output on your soundcard. However, occasionally you may wish to only send to the output on your soundcard and not to the external context (and therefore not have any chance of the sound being mixed and sent to the standard output channels 1 and 2). This is possible by using the standard FX opt amp: which operates on the audio after the FX has been able to manipulate the audio:

sample :loop_amen

In the above example, the :loop_amen sample is sent to its outer context, the :sound_out FX. This then sends a mono mix to audio card output 3 and then multiplies the audio by 0 which essentially silences it. It is this silenced signal which is then sent out to the :sound_out’s outer context which is the standard output. Therefore with this code, the default output channels will not receive any audio, and channel 3 will receive a mono mix of the amen drum break.


12 - Conclusões

Isto conclui o tutorial introdutório do Sonic Pi. Espero que tenhas aprendido algo ao longo do caminho. Não te preocupes se sentires que não percebes tudo - apenas brinca e diverte-te e aprenderás ao teu tempo. Está a vontade de regressares se tiveres duvidas que poderão ser explicadas numa das secções.

Se tiveres alguma duvida que não foi coberta no tutorial, tenta os Sonic Pi foruns e coloca a tua questão lá. Encontrarás alguém amigável pronto a ajudar.

Finalmente, Também te convido a dares uma vista aprofundada ao resto da documentação no sistema de ajuda. Existem uma serie de coisas que não foram apresentadas neste tutorial e estão a espera que as descubras.

Brinca, diverte-te, partilha o teu código, actua para os teus amigos, mostra o ecrã e lembra-te:

Não existem erros, apenas oportunidades.

Sam Aaron


- Artigos na MagPi

Apêndice A colecção de todos os artigo do Sonic Pi para a revista MagPi.

Verifica os tópicos

Estes artigos não foram feitos para serem lidos numa ordem em particular e contêm muito material repetido do tutorial. Em vez de tentar e ensinar todo o Sonic Pi, eles estão focados num aspecto especifico do Sonic Pi e tentam explica-los de uma forma divertida e acessível.

Lê a MagPi

Poderás ver o typeset glorioso e profissional na forma de PDF para download da MagPi aqui: https://www.raspberrypi.org/magpi/

Sugerir um tópico

Se não veres um tópico que tenhas curiosidade nestes artigos - porque não sugerir um? A maneira mais fácil é tweetares a tua sugestão para @Sonic_Pi. A tua sugestão poderá ser o tema do próximo artigo!


- As cinco melhores dicas

1. Não existem erros

A coisa mais importante lição a aprender com o Sonic Pi é que realmente não existem erros. A melhor maneira é tentar e tentar. Tenta coisas diferentes, pára de te preocupar se o teu código soa bem ou não e começa a experimentar com diferentes synths, notas, efeitos e opções o máximo possível. Descobrirás muitas coisas que te farão rir porque soam mal e algumas pérolas que soam realmente bem. Simplesmente retira o que não gostas e fica com as que gostas. Quantos mais ‘erros’ te permitires mais rápido aprenderás e descobrirás o teu som pessoal no código.

2. Usa os efeitos

Digamos que já dominas o básico do Sonic Pi de fazer sons com sample, play? O que se segue? Sabias que o Sonic Pi suporta mais de 27 efeitos de estúdio para mudar o som do teu código? Efeitos são como filtros de imagens bonitos nos programas de desenho excepto que em vez de desfocar ou tornar algo a preto e branco, podes acrescentar reverb, distorção e eco ao teu som. Pensa que é como ligar o cabo de uma guitarra a um pedal de efeitos à tua escolha e depois ao amplificador. Felizmente, o Sonic Pi torna o uso de efeitos muito fácil e não requer cabos! Tudo o que tens que fazer é escolher que secção do código queres adicionar o efeito e embrulhares com o código do efeito. Vamos ver um exemplo. Imagina que tens o seguinte código:

sample :loop_garzul
16.times do
  sample :bd_haus
  sleep 0.5
end

Se quiseres acrescentar um efeito ao sample :loop_garzul, apenas tens que o colocar dentro de um bloco with_fx assim:

with_fx :flanger do
  sample :loop_garzul
end
16.times do
  sample :bd_haus
  sleep 0.5
end

Agora, se quiseres adicionar um efeito à bass drum, vai e embrulha isso com o with_fx também:

with_fx :flanger do
  sample :loop_garzul
end
with_fx :echo do
  16.times do
    sample :bd_haus
    sleep 0.5
  end
end

Lembra-te, podes embrulhar qualquer código com o with_fx e qualquer som criado passará pelo efeito.

3. Paramatriza os teus synths

De forma a realmente descobrires o teu som no código em breve quererás saber como modificar e controlar os synth e efeitos. Por exemplo, poderás querer mudar a duração de uma nota, adicionar mais reverb, ou mudar o tempo entre os ecos. Felizmente, o Sonic Pi dá-te um incrível nível de controlo para fazer isso com uma coisa especial chamada parâmetros opcionais ou opts como abreviatura. Vamos dar uma vista de olhos. Copia este código para o espaço de trabalho e carrega run:

sample :guit_em9

Ooh, um bonito som de guitarra! Agora, vamos começar a brincar com ele. Que tal mudar a sua rate?

sample :guit_em9, rate: 0.5

Hey, o que é essa rate: 0.5 que acrescentei no final? É chamada um opt. Todos os Synths do Sonic Py e efeitos suportam-no e existem muitos para brincar com eles. Eles também estão disponíveis para efeitos. Tenta isto:

with_fx :flanger, feedback: 0.6 do
  sample :guit_em9
end

Agora, tenta aumentar o feedback para 1 para ouvires alguns sons malucos! Lê a documentação para todos os detalhes de todas as opts disponíveis para ti.

5. Código ao vivo

A melhor maneira de experimentar e explorar o Sonic Pi é codificares ao vivo. Isto permite que comeces um código e o mudes e afines enquanto esta a ser tocado. Por exemplo, se não sabes o que o parâmetro cutoff faz a um sample, brinca com isso. Vamos experimentar! Copia este código para um espaço de trabalho do Sonic Pi:

live_loop :experiment do
  sample :loop_amen, cutoff: 70
  sleep 1.75
end

Agora, carrega run e ouvirás um drum break ligeiramente abafado. Agora, muda o valor de cutoff: para 80 e carrega outra vez em run. Consegues ouvir a diferença? Experimenta 90, 100, 110

Once you get the hang of using live_loops you’ll not turn back. Whenever I do a live coding gig I rely on live_loop as much as a drummer relies on their sticks. For more information about live coding check out Section 9 of the built-in tutorial.

5. Surf the random streams

Finally, one thing I love doing is cheating by getting Sonic Pi to compose things for me. A really great way to do this is using randomisation. It might sound complicated but it really isn’t. Let’s take a look. Copy this into a spare workspace:

live_loop :rand_surfer do
  use_synth :dsaw
  notes = (scale :e2, :minor_pentatonic, num_octaves: 2)
  16.times do
    play notes.choose, release: 0.1, cutoff: rrand(70, 120)
    sleep 0.125
  end
end

Now, when you play this, you’ll hear a constant stream of random notes from the scale :e2 :minor_pentatonic played with the :dsaw synth. “Wait, wait! That’s not a melody”, I hear you shout! Well, here’s the first part of the magic trick. Every time we go round the live_loop we can tell Sonic Pi to reset the random stream to a known point. This is a bit like going back in time in the TARDIS with the Doctor to a particular point in time and space. Let’s try it - add the line use_random_seed 1 to the live_loop:

live_loop :rand_surfer do
  use_random_seed 1
  use_synth :dsaw
  notes = (scale :e2, :minor_pentatonic, num_octaves: 2)
  16.times do
    play notes.choose, release: 0.1, cutoff: rrand(70, 120)
    sleep 0.125
  end
end

Now, every time the live_loop loops around, the random stream is reset. This means it chooses the same 16 notes every time. Hey presto! An instant melody. Now, here’s the really exciting bit. Change the seed value from 1 to another number. Say 4923. Wow! Another melody! So, just by changing one number (the random seed), you can explore as many melodic combinations as you can imagine! Now, that’s the magic of code.


- Live Coding

The laser beams sliced through the wafts of smoke as the subwoofer pumped bass deep into the bodies of the crowd. The atmosphere was ripe with a heady mix of synths and dancing. However something wasn’t quite right in this nightclub. Projected in bright colours above the DJ booth was futuristic text, moving, dancing, flashing. This wasn’t fancy visuals, it was merely a projection of Sonic Pi running on a Raspberry Pi. The occupant of the DJ booth wasn’t spinning disks, he was writing, editing and evaluating code. Live. This is Live Coding.

Live Coding

This may sound like a far fetched story from a futuristic night club but coding music like this is a growing trend and is often described as Live Coding (http://toplap.org). One of the recent directions this approach to music making has taken is the Algorave (http://algorave.com) - events where artists like myself code music for people to dance to. However, you don’t need to be in a nightclub to Live Code - with Sonic Pi v2.6+ you can do it anywhere you can take your Raspberry Pi and a pair of headphones or some speakers. Once you reach the end of this article, you’ll be programming your own beats and modifying them live. Where you go afterwards will only be constrained by your imagination.

Live Loop

The key to live coding with Sonic Pi is mastering the live_loop. Let’s look at one:

live_loop :beats do
  sample :bd_haus
  sleep 0.5
end

There are 4 core ingredients to a live_loop. The first is its name. Our live_loop above is called :beats. You’re free to call your live_loop anything you want. Go crazy. Be creative. I often use names that communicate something about the music they’re making to the audience. The second ingredient is the do word which marks where the live_loop starts. The third is the end word which marks where the live_loop finishes, and finally there is the body of the live_loop which describes what the loop is going to repeat - that’s the bit between the do and end. In this case we’re repeatedly playing a bass drum sample and waiting for half a beat. This produces a nice regular bass beat. Go ahead, copy it into an empty Sonic Pi buffer and hit run. Boom, Boom, Boom!.

Redefining On-the-fly

Ok, so what’s so special about the live_loop? So far it just seems like a glorified loop! Well, the beauty of live_loops is that you can redefine them on-the-fly. This means that whilst they’re still running, you can change what they do. This is the secret to live coding with Sonic Pi. Let’s have a play:

live_loop :choral_drone do
  sample :ambi_choir, rate: 0.4
  sleep 1
end

escolhe

Sleeping is important

One of the most important lessons about live_loops is that they need rest. Consider the following live_loop:

live_loop :infinite_impossibilities do
  sample :ambi_choir
end

If you try running this code, you’ll immediately see Sonic Pi complaining that the live_loop did not sleep. This is a safety system kicking in! Take a moment to think about what this code is asking the computer to do. That’s right, it’s asking the computer to play an infinite amount of choir samples in zero time. Without the safety system the poor computer will try and do this and crash and burn in the process. So remember, your live_loops must contain a sleep.

Combining Sounds

Music is full of things happening at the same time. Drums at the same time as bass at the same time as vocals at the same time as guitars… In computing we call this concurrency and Sonic Pi provides us with an amazingly simple way of playing things at the same time. Simply use more than one live_loop!

live_loop :beats do
  sample :bd_tek
  with_fx :echo, phase: 0.125, mix: 0.4 do
    sample  :drum_cymbal_soft, sustain: 0, release: 0.1
    sleep 0.5
  end
end
live_loop :bass do
  use_synth :tb303
  synth :tb303, note: :e1, release: 4, cutoff: 120, cutoff_attack: 1
  sleep 4
end

Here, we have two live_loops, one looping quickly making beats and another looping slowly making a crazy bass sound.

One of the interesting things about using multiple live_loops is that they each manage their own time. This means it’s really easy to create interesting polyrhythmical structures and even play with phasing Steve Reich style. Check this out:

# Steve Reich's Piano Phase
notes = (ring :E4, :Fs4, :B4, :Cs5, :D5, :Fs4, :E4, :Cs5, :B4, :Fs4, :D5, :Cs5)
live_loop :slow do
  play notes.tick, release: 0.1
  sleep 0.3
end
live_loop :faster do
  play notes.tick, release: 0.1
  sleep 0.295
end

Bringing it all together

In each of these tutorials, we’ll end with a final example in the form of a new piece of music which draws from all of the ideas introduced. Read this code and see if you can imagine what it’s doing. Then, copy it into a fresh Sonic Pi buffer and hit Run and actually hear what it sounds like. Finally, change one of the numbers or comment and uncomment things out. See if you can use this as a starting point for a new performance, and most of all have fun! See you next time…

with_fx :reverb, room: 1 do
  live_loop :time do
    synth :prophet, release: 8, note: :e1, cutoff: 90, amp: 3
    sleep 8
  end
end
live_loop :machine do
  sample :loop_garzul, rate: 0.5, finish: 0.25
  sample :loop_industrial, beat_stretch: 4, amp: 1
  sleep 4
end
live_loop :kik do
  sample :bd_haus, amp: 2
  sleep 0.5
end
with_fx :echo do
  live_loop :vortex do
    # use_random_seed 800
    notes = (scale :e3, :minor_pentatonic, num_octaves: 3)
    16.times do
      play notes.choose, release: 0.1, amp: 1.5
      sleep 0.125
    end
  end
end

- Coded Beats

One of the most exciting and disrupting technical developments in modern music was the invention of samplers. These were boxes that allowed you to record any sound into them and then manipulate and play back those sounds in many interesting ways. For example, you could take an old record, find a drum solo (or break), record it into your sampler and then play it back on repeat at half-speed to provide the foundation for your latest beats. This is how early hip-hop music was born and today it’s almost impossible to find electronic music that doesn’t incorporate samples of some kind. Using samples is a really great way of easily introducing new and interesting elements into your live coded performances.

So where can you get a sampler? Well you already have one - it’s your Raspberry Pi! The built-in live coding app Sonic Pi has an extremely powerful sampler built into its core. Let’s play with it!

The Amen Break

One of the most classic and recognisable drum break samples is called the Amen Break. It was first performed in 1969 in the song “Amen Brother” by the Winstons as part of a drum break. However, it was when it was discovered by early hip-hop musicians in the 80s and used in samplers that it started being heavily used in a wide variety of other styles such as drum and bass, breakbeat, hardcore techno and breakcore.

I’m sure you’re excited to hear that it’s also built right into Sonic Pi. Clear up a buffer and throw in the following code:

sample :loop_amen

Hit Run and boom! You’re listening to one of the most influential drum breaks in the history of dance music. However, this sample wasn’t famous for being played as a one-shot, it was built for being looped.

Beat Stretching

Let’s loop the Amen Break by using our old friend the live_loop introduced in this tutorial last month:

live_loop :amen_break do
  sample :loop_amen
  sleep 2
end

OK, so it is looping, but there’s an annoying pause every time round. That is because we asked it to sleep for 2 beats and with the default BPM of 60 the :loop_amen sample only lasts for 1.753 beats. We therefore have a silence of 2 - 1.753 = 0.247 beats. Even though it’s short, it’s still noticeable.

To fix this issue we can use the beat_stretch: opt to ask Sonic Pi to stretch (or shrink) the sample to match the specified number of beats.

Sonic Pi’s sample and synth fns give you a lot of control via optional parameters such as amp:, cutoff: and release:. However, the term optional parameter is a real mouthful so we just call them opts to keep things nice and simple.

live_loop :amen_break do
  sample :loop_amen, beat_stretch: 2
  sleep 2
end  

Now we’re dancing! Although, perhaps we want to speed it up or slow it down to suit the mood.

Playing with Time

OK, so what if we want to change styles to old school hip hop or breakcore? One simple way of doing this is to play with time - or in other words mess with the tempo. This is super easy in Sonic Pi - just throw in a use_bpm into your live loop:

live_loop :amen_break do
  use_bpm 30
  sample :loop_amen, beat_stretch: 2
  sleep 2
end 

Whilst you’re rapping over those slow beats, notice that we’re still sleeping for 2 and our BPM is 30, yet everything is in time. The beat_stretch opt works with the current BPM to make sure everything just works.

Now, here’s the fun part. Whilst the loop is still live, change the 30 in the use_bpm 30 line to 50. Woah, everything just got faster yet kept in time! Try going faster - up to 80, to 120, now go crazy and punch in 200!

Filtering

Now we can live loop samples, let’s look at some of the most fun opts provided by the sample synth. First up is cutoff: which controls the cutoff filter of the sampler. By default this is disabled but you can easily turn it on:

live_loop :amen_break do
  use_bpm 50
  sample :loop_amen, beat_stretch: 2, cutoff: 70
  sleep 2
end  

Go ahead and change the cutoff: opt. For example, increase it to 100, hit Run and wait for the loop to cycle round to hear the change in the sound. Notice that low values like 50 sound mellow and bassy and high values like 100 and 120 are more full-sounding and raspy. This is because the cutoff: opt will chop out the high frequency parts of the sound just like a lawn-mower chops off the top of the grass. The cutoff: opt is like the length setting - determining how much grass is left over.

Slicing

Another great tool to play with is the slicer FX. This will chop (slice) the sound up. Wrap the sample line with the FX code like this:

live_loop :amen_break do
  use_bpm 50
  with_fx :slicer, phase: 0.25, wave: 0, mix: 1 do
    sample :loop_amen, beat_stretch: 2, cutoff: 100
  end
  sleep 2
end

Notice how the sound bounces up and down a little more. (You can hear the original sound without the FX by changing the mix: opt to 0.) Now, try playing around with the phase: opt. This is the rate (in beats) of the slicing effect. A smaller value like 0.125 will slice faster and larger values like 0.5 will slice more slowly. Notice that successively halving or doubling the phase: opts val tends to always sound good. Finally, change the wave: opt to one of 0, 1, or 2 and hear how it changes the sound. These are the various wave shapes. 0 is a saw wave, (hard in, fade out) 1 is a square wave (hard in, hard out) and 2 is a triangle wave (fade in, fade out).

Bringing it all together

Finally, let’s go back in time and revisit the early Bristol drum and bass scene with this month’s example. Don’t worry too much about what all this means, just type it in, hit Run, then start live coding it by changing opt numbers and see where you can take it. Please do share what you create! See you next time…

use_bpm 100
live_loop :amen_break do
  p = [0.125, 0.25, 0.5].choose
  with_fx :slicer, phase: p, wave: 0, mix: rrand(0.7, 1) do
    r = [1, 1, 1, -1].choose
    sample :loop_amen, beat_stretch: 2, rate: r, amp: 2
  end
  sleep 2
end
live_loop :bass_drum do
  sample :bd_haus, cutoff: 70, amp: 1.5
  sleep 0.5
end
live_loop :landing do
  bass_line = (knit :e1, 3, [:c1, :c2].choose, 1)
  with_fx :slicer, phase: [0.25, 0.5].choose, invert_wave: 1, wave: 0 do
    s = synth :square, note: bass_line.tick, sustain: 4, cutoff: 60
    control s, cutoff_slide: 4, cutoff: 120
  end
  sleep 4
end

- Synth Riffs

Whether it’s the haunting drift of rumbling oscillators or the detuned punch of saw waves piercing through the mix, the lead synth plays an essential role on any electronic track. In last month’s edition of this tutorial series we covered how to code our beats. In this tutorial we’ll cover how to code up the three core components of a synth riff - the timbre, melody and rhythm.

OK, so power up your Raspberry Pi, crack open Sonic Pi v2.6+ and let’s make some noise!

Timbral Possibilities

An essential part of any synth riff is changing and playing with the timbre of the sounds. We can control the timbre in Sonic Pi in two ways - choosing different synths for a dramatic change and setting the various synth opts for more subtle modifications. We can also use FX, but that’s for another tutorial…

Let’s create a simple live loop where we continually change the current synth:

live_loop :timbre do
  use_synth (ring :tb303, :blade, :prophet, :saw, :beep, :tri).tick
  play :e2, attack: 0, release: 0.5, cutoff: 100
  sleep 0.5
end

Take a look at the code. We’re simply ticking through a ring of synth names (this will cycle through each of these in turn repeating the list over and over). We pass this synth name to the use_synth fn (function) which will change the live_loop’s current synth. We also play note :e2 (E at the second octave), with a release time of 0.5 beats (half a second at the default BPM of 60) and with the cutoff: opt set to 100.

Hear how the different synths have very different sounds even though they’re all playing the same note. Now experiment and have a play. Change the release time to bigger and smaller values. For example, change the attack: and release: opts to see how different fade in/out times have a huge impact on the sound. Finally change the cutoff: opt to see how different cutoff values also massively influence the timbre (values between 60 and 130 are good). See how many different sounds you can create by just changing a few values. Once you’ve mastered that, just head to the Synths tab in the Help system for a full list of all the synths and all the available opts each individual synth supports to see just how much power you have under your coding fingertips.

Timbre

Timbre is just a fancy word describing the sound of a sound. If you play the same note with different instruments such as a violin, guitar, or piano, the pitch (how high or low it sounds) would be the same, but the sound quality would be different. That sound quality - the thing which allows you to tell the difference between a piano and a guitar is the timbre.

Melodic Composition

Another important aspect to our lead synth is the choice of notes we want to play. If you already have a good idea, then you can simply create a ring with your notes in and tick through them:

live_loop :riff do
  use_synth :prophet
  riff = (ring :e3, :e3, :r, :g3, :r, :r, :r, :a3)
  play riff.tick, release: 0.5, cutoff: 80
  sleep 0.25
end

Here, we’ve defined our melody with a ring which includes both notes such as :e3 and rests represented by :r. We’re then using .tick to cycle through each note to give us a repeating riff.

Auto Melody

It’s not always easy to come up with a nice riff from scratch. Instead it’s often easier to ask Sonic Pi for a selection of random riffs and to choose the one you like the best. To do that we need to combine three things: rings, randomisation and random seeds. Let’s look at an example:

live_loop :random_riff do
  use_synth :dsaw
  use_random_seed 3
  notes = (scale :e3, :minor_pentatonic).shuffle
  play notes.tick, release: 0.25, cutoff: 80
  sleep 0.25
end

There’s a few things going on - let’s look at them in turn. First, we specify that we’re using random seed 3. What does this mean? Well, the useful thing is that when we set the seed, we can predict what the next random value is going to be - it’s the same as it was last time we set the seed to 3! Another useful thing to know is that shuffling a ring of notes works in the same way. In the example above we’re essentially asking for the ‘third shuffle’ in the standard list of shuffles - which is also the same every time as we’re always setting the random seed to the same value right before the shuffle. Finally we’re just ticking through our shuffled notes to play the riff.

Now, here’s where the fun starts. If we change the random seed value to another number, say 3000, we get an entirely different shuffling of the notes. So now it’s extremely easy to explore new melodies. Simply choose the list of notes we want to shuffle (scales are a great starting point) and then choose the seed we want to shuffle with. If we don’t like the melody, just change one of those two things and try again. Repeat until you like what you hear!

Pseudo Randomisation

Sonic Pi’s randomisation is not actually random it’s what’s called pseudo random. Imagine if you were to roll a dice 100 times and write down the result of each roll onto a piece of paper. Sonic Pi has the equivalent of this list of results which it uses when you ask for a random value. Instead of rolling an actual dice, it just picks the next value from the list. Setting the random seed is just jumping to a specific point in that list.

Finding your Rhythm

Another important aspect to our riff is the rhythm - when to play a note and when not to. As we saw above we can use :r in our rings to insert rests. Another very powerful way is to use spreads which we’ll cover in a future tutorial. Today we’ll use randomisation to help us find our rhythm. Instead of playing every note we can use a conditional to play a note with a given probability. Let’s take a look:

live_loop :random_riff do
  use_synth :dsaw
  use_random_seed 30
  notes = (scale :e3, :minor_pentatonic).shuffle
  16.times do
    play notes.tick, release: 0.2, cutoff: 90 if one_in(2)
    sleep 0.125
  end
end

A really useful fn to know is one_in which will give us a true or false value with the specified probability. Here, we’re using a value of 2 so on average one time every two calls to one_in it will return true. In other words, 50% of the time it will return true. Using higher values will make it return false more often introducing more space into the riff.

Notice that we’ve added some iteration in here with 16.times. This is because we only want to reset our random seed value every 16 notes so our rhythm repeats every 16 times. This doesn’t affect the shuffling as that is still done immediately after the seed is set. We can use the iteration size to alter the length of the riff. Try changing the 16 to 8 or even 4 or 3 and see how it affects the rhythm of the riff.

Bringing it all together

OK, so let’s combine everything we’ve learned together into one final example. See you next time!

live_loop :random_riff do
  #  uncomment to bring in:
  #  synth :blade, note: :e4, release: 4, cutoff: 100, amp: 1.5
  use_synth :dsaw
  use_random_seed 43
  notes = (scale :e3, :minor_pentatonic, num_octaves: 2).shuffle.take(8)
  8.times do
    play notes.tick, release: rand(0.5), cutoff: rrand(60, 130) if one_in(2)
    sleep 0.125
  end
end
 
live_loop :drums do
  use_random_seed 500
  16.times do
    sample :bd_haus, rate: 2, cutoff: 110 if rand < 0.35
    sleep 0.125
  end
end
 
live_loop :bd do
  sample :bd_haus, cutoff: 100, amp: 3
  sleep 0.5
end

- Acid Bass

It’s impossible to look through the history of electronic dance music without seeing the enormous impact of the tiny Roland TB-303 synthesiser. It’s the secret sauce behind the original acid bass sound. Those classic squealing and squelching TB-303 bass riffs can be heard from the early Chicago House scene through to more recent electronic artists such as Plastikman, Squarepusher and Aphex Twin.

Interestingly, Roland never intended for the TB-303 to be used in dance music. It was originally created as a practice aid for guitarists. They imagined that people would program them to play bass lines to jam along to. Unfortunately there were a number of problems: they were a little fiddly to program, didn’t sound particularly good as a bass-guitar replacement and were pretty expensive to buy. Deciding to cut their losses, Roland stopped making them after 10,000 units were sold and after a number of years sitting on guitarist’s shelves, they soon could be found in the windows of second hand shops. These lonely discarded TB-303s were waiting to be discovered by a new generation of experimenters who started using them in ways that Roland didn’t imagine to create new crazy sounds. Acid House was born.

Although getting your hands on an original TB-303 is not so easy you will be pleased to know that you can turn your Raspberry Pi into one using the power of Sonic Pi. Behold, fire up Sonic Pi and throw this code into an empty buffer and hit Run:

use_synth :tb303
play :e1

Instant acid bass! Let’s play around…

Squelch that Bass

First, let’s build a live arpeggiator to make things fun. In the last tutorial we looked at how riffs can just be a ring of notes that we tick through one after another, repeating when we get to the end. Let’s create a live loop that does exactly that:

use_synth :tb303
live_loop :squelch do
  n = (ring :e1, :e2, :e3).tick
  play n, release: 0.125, cutoff: 100, res: 0.8, wave: 0
  sleep 0.125
end

Take a look at each line.

On the first line we set the default synth to be tb303 with the use_synth fn. On line two we create a live loop called :squelch which will just loop round and round. Line three is where we create our riff - a ring of notes (E in octaves 1, 2, and 3) which we simply tick through with .tick. We define n to represent the current note in the riff. The equals sign just means to assign the value on the right to the name on the left. This will be different every time round the loop. The first time round, n will be set to :e1. The second time round it will be :e2, followed by :e3, and then back to :e1, cycling round forever. Line four is where we actually trigger our :tb303 synth. We’re passing a few interesting opts here: release:, cutoff:, res: and wave: which we’ll discuss below. Line five is our sleep - we’re asking the live loop to loop round every 0.125s or 8 times a second at the default BPM of 60. Line six is the end to the live loop. This just tells Sonic Pi where the end of the live loop is.

Whilst you’re still figuring out what’s going on, type in the code above and hit the Run button. You should hear the :tb303 kick into action. Now, this is where the action is: let’s start live coding.

Whilst the loop is still live, change the cutoff: opt to 110. Now hit the Run button again. You should hear the sound become a little harsher and more squelchy. Dial in 120 and hit run. Now 130. Listen how higher cutoff values make it sound more piercing and intense. Finally, drop it down to 80 when you feel like a rest. Then repeat as many times as you want. Don’t worry, I’ll still be here…

Another opt worth playing with is res:. This controls the level of resonance of the filter. A high resonance is characteristic of acid bass sounds. We currently have our res: set to 0.8. Try cranking it up to 0.85, then 0.9, and finally 0.95. You might find that a cutoff such as 110 or higher will make the differences easier to hear. Finally go crazy and dial in 0.999 for some insane sounds. At a res this high, you’re hearing the cutoff filter resonate so much it starts to make sounds of its own!

Finally, for a big impact on the timbre try changing the wave: opt to 1. This is the choice of source oscillator. The default is 0 which is a sawtooth wave. 1 is a pulse wave and 2 is a triangle wave.

Of course, try different riffs by changing the notes in the ring or even picking notes from scales or chords. Have fun with your first acid bass synth.

Deconstructing the TB-303

The design of the original TB-303 is actually pretty simple. As you can see from the following diagram there’s only 4 core parts.

TB-303 Design

First is the oscillator wave - the raw ingredients of the sound. In this case we have a square wave. Next there’s the oscillator’s amplitude envelope which controls the amp of the square wave through time. These are accessed in Sonic Pi by the attack:, decay:, sustain: and release: opts along with their level counterparts. For more information read Section 2.4 ‘Duration with Envelopes’ in the built-in tutorial. We then pass our enveloped square wave through a resonant low pass filter. This chops off the higher frequencies as well as having that nice resonance effect. Now this is where the fun starts. The cutoff value of this filter is also controlled by its own envelope! This means we have amazing control over the timbre of the sound by playing with both of these envelopes. Let’s take a look:

use_synth :tb303
with_fx :reverb, room: 1 do
  live_loop :space_scanner do
    play :e1, cutoff: 100, release: 7, attack: 1, cutoff_attack: 4, cutoff_release: 4
    sleep 8
  end
end

For each standard envelope opt, there’s a cutoff_ equivalent opt in the :tb303 synth. So, to change the cutoff attack time we can use the cutoff_attack: opt. Copy the code above into an empty buffer and hit Run. You’ll hear a crazy sound warble in and out. Now start to play. Try changing the cutoff_attack: time to 1 and then 0.5. Now try 8.

Notice that I’ve passed everything through a :reverb FX for extra atmosphere - try other FX to see what works!

Bringing it all together

Finally, here’s a piece I composed using the ideas in this tutorial. Copy it into an empty buffer, listen for a while and then start live coding your own changes. See what crazy sounds you can make with it! See you next time…

use_synth :tb303
use_debug false
 
with_fx :reverb, room: 0.8 do
  live_loop :space_scanner do
    with_fx :slicer, phase: 0.25, amp: 1.5 do
      co = (line 70, 130, steps: 8).tick
      play :e1, cutoff: co, release: 7, attack: 1, cutoff_attack: 4, cutoff_release: 4
      sleep 8
    end
  end
 
  live_loop :squelch do
    use_random_seed 3000
    16.times do
      n = (ring :e1, :e2, :e3).tick
      play n, release: 0.125, cutoff: rrand(70, 130), res: 0.9, wave: 1, amp: 0.8
      sleep 0.125
    end
  end
end

- Musical Minecraft

Hello and welcome back! In the previous tutorials we’ve focussed purely on the music possibilities of Sonic Pi - (turning your Raspberry Pi into a performance ready musical instrument). So far we’ve learned how to:

Live Code - changing the sounds on-the-fly, Code some huge beats, Generate powerful synth leads, Re-create the famous TB-303 acid-bass sound.

There’s so much more to show you (which we will explore in future editions). However, this month, let’s look at something Sonic Pi can do that you probably didn’t realise: control Minecraft.

Hello Minecraft World

OK, let’s get started. Boot up your Raspberry Pi, fire up Minecraft Pi and create a new world. Now start up Sonic Pi and re-size and move your windows so you can see both Sonic Pi and Minecraft Pi at the same time.

In a fresh buffer type the following:

mc_message "Hello Minecraft from Sonic Pi!"

Now, hit Run. Boom! Your message appeared in Minecraft! How easy was that? Now, stop reading this for a moment and play about with your own messages. Have fun!

Screen 0

Sonic Teleporter

Now let’s do some exploring. The standard option is to reach for the mouse and keyboard and start walking around. That works, but it’s pretty slow and boring. It would be far better if we had some sort of teleport machine. Well, thanks to Sonic Pi, we have one. Try this:

mc_teleport 80, 40, 100

Crikey! That was a long way up. If you weren’t in flying-mode then you would have fallen back down all the way to the ground. If you double-tap space to enter flying-mode and teleport again, you’ll stay hovering at the location you zap to.

Now, what do those numbers mean? We have three numbers which describe the coordinates of where in the world we want to go. We give each number a name - x, y and z:

x - how far left and right (80 in our example) y - how high we want to be (40 in our example) z - how far forward and back (100 in our example)

By choosing different values for x, y and z we can teleport anywhere in our world. Try it! Choose different numbers and see where you can end up. If the screen goes black it’s because you’ve teleported yourself under the ground or into a mountain. Just choose a higher y value to get back out above land. Keep on exploring until you find somewhere you like…

Using the ideas so far, let’s build a Sonic Teleporter which makes a fun teleport sound whilst it whizzes us across the Minecraft world:

mc_message "Preparing to teleport...."
sample :ambi_lunar_land, rate: -1
sleep 1
mc_message "3"
sleep 1
mc_message "2"
sleep 1
mc_message "1"
sleep 1
mc_teleport 90, 20, 10
mc_message "Whoooosh!"

Screen 1

Magic Blocks

Now you’ve found a nice spot, let’s start building. You could do what you’re used to and start clicking the mouse furiously to place blocks under the cursor. Or you could use the magic of Sonic Pi. Try this:

x, y, z = mc_location
mc_set_block :melon, x, y + 5, z

Now look up! There’s a melon in the sky! Take a moment to look at the code. What did we do? On line one we grabbed the current location of Steve as the variables x, y and z. These correspond to our coordinates described above. We use these coordinates in the fn mc_set_block which will place the block of your choosing at the specified coordinates. In order to make something higher up in the sky we just need to increase the y value which is why we add 5 to it. Let’s make a long trail of them:

live_loop :melon_trail do
  x, y, z = mc_location
  mc_set_block :melon, x, y-1, z
  sleep 0.125
end

Now, jump over to Minecraft, make sure you’re in flying-mode (double tap space if not) and fly all around the world. Look behind you to see a pretty trail of melon blocks! See what kind of twisty patterns you can make in the sky.

Live Coding Minecraft

Those of you that have been following this tutorial over the last few months will probably have your minds blown at this point. The trail of melons is pretty cool, but the most exciting part of the previous example is that you can use live_loop with Minecraft! For those that don’t know, live_loop is Sonic Pi’s special magic ability that no other programming language has. It lets you run multiple loops at the same time and allows you to change them whilst they run. They are incredibly powerful and amazing fun. I use live_loops to perform music in nightclubs with Sonic Pi - DJs use discs and I use live_loops :-) However, today we’re going to live code both music and Minecraft.

Let’s get started. Run the code above and start making your melon trail again. Now, without stopping the code, just simply change :melon to :brick and hit run. Hey presto, you’re now making a brick trail. How simple was that! Fancy some music to go with it? Easy. Try this:

live_loop :bass_trail do
  tick
  x, y, z = mc_location
  b = (ring :melon, :brick, :glass).look
  mc_set_block b, x, y -1, z
  note = (ring :e1, :e2, :e3).look
  use_synth :tb303
  play note, release: 0.1, cutoff: 70
  sleep 0.125
end

Now, whilst that’s playing start changing the code. Change the block types - try :water, :grass or your favourite block type. Also, try changing the cutoff value from 70 to 80 and then up to 100. Isn’t this fun?

Bringing it all together

Screen 2

Let’s combine everything we’ve seen so far with a little extra magic. Let’s combine our teleportation ability with block placing and music to make a Minecraft Music Video. Don’t worry if you don’t understand it all, just type it in and have a play by changing some of the values whilst it’s running live. Have fun and see you next time…

live_loop :note_blocks do
  mc_message "This is Sonic Minecraft"
  with_fx :reverb do
    with_fx :echo, phase: 0.125, reps: 32 do
      tick
      x = (range 30, 90, step: 0.1).look
      y = 20
      z = -10
      mc_teleport x, y, z
      ns = (scale :e3, :minor_pentatonic)
      n = ns.shuffle.choose
      bs = (knit :glass, 3, :sand, 1)
      b = bs.look
      synth :beep, note: n, release: 0.1
      mc_set_block b, x+20, n-60+y, z+10
      mc_set_block b, x+20, n-60+y, z-10
      sleep 0.25
    end
  end
end
live_loop :beats do
  sample :bd_haus, cutoff: 100
  sleep 0.5
end

- Bizet Beats

After our brief excursion to the fantastic world of coding Minecraft with Sonic Pi last month, let’s get musical again. Today we’re going to bring a classical operatic dance piece straight into the 21st century using the awesome power of code.

Outrageous and Disruptive

Let’s jump into a time machine back to the year 1875. A composer called Bizet had just finished his latest opera Carmen. Unfortunately like many exciting and disruptive new pieces of music people initially didn’t like it at all because it was too outrageous and different. Sadly Bizet died ten years before the opera gained huge international success and became one of the most famous and frequently performed operas of all time. In sympathy with this tragedy let’s take one of the main themes from Carmen and convert it to a modern format of music that is also too outrageous and different for most people in our time - live coded music!

Decoding the Habanera

Trying to live code the whole opera would be a bit of a challenge for this tutorial, so let’s focus on one of the most famous parts - the bass line to the Habanera:

Habanera Riff

This may look extremely unreadable to you if you haven’t yet studied music notation. However, as programmers we see music notation as just another form of code - only it represents instructions to a musician instead of a computer. We therefore need to figure out a way of decoding it.

Notes

The notes are arranged from left to right like the words in this magazine but also have different heights. The height on the score represents the pitch of the note. The higher the note on the score, the higher the pitch of the note.

In Sonic Pi we already know how to change the pitch of a note - we either use high or low numbers such as play 75 and play 80 or we use the note names: play :E and play :F. Luckily each of the vertical positions of the musical score represents a specific note name. Take a look at this handy look up table:

Notes

Rests

Music scores are an extremely rich and expressive kind of code capable of communicating many things. It therefore shouldn’t come as much of a surprise that musical scores can not only tell you what notes to play but also when not to play notes. In programming this is pretty much equivalent to the idea of nil or null - the absence of a value. In other words not playing a note is like the absence of a note.

If you look closely at the score you’ll see that it’s actually a combination of black dots with lines which represent notes to play and squiggly things which represent the rests. Luckily Sonic Pi has a very handy representation for a rest: :r, so if we run: play :r it actually plays silence! We could also write play :rest, play nil or play false which are all equivalent ways of representing rests.

Rhythm

Finally, there’s one last thing to learn how to decode in the notation - the timings of the notes. In the original notation you’ll see that the notes are connected with thick lines called beams. The second note has two of these beams which means it lasts for a 16th of a beat. The other notes have a single beam which means they last for an 8th of a beat. The rest has two squiggly beams which means it also represents a 16th of the beat.

When we attempt to decode and explore new things a very handy trick is to make everything as similar as possible to try and see any relationships or patterns. For example, when we re-write our notation purely in 16ths you can see that our notation just turns into a nice sequence of notes and rests.

Habanera Riff 2

Re-coding the Habanera

We’re now in a position to start translating this bass line to Sonic Pi. Let’s encode these notes and rests in a ring:

(ring :d, :r, :r, :a, :f5, :r, :a, :r)

Let’s see what this sounds like. Throw it in a live loop and tick through it:

live_loop :habanera do
  play (ring :d, :r, :r, :a, :f5, :r, :a, :r).tick
  sleep 0.25
end

Fabulous, that instantly recognisable riff springs to life through your speakers. It took a lot of effort to get here, but it was worth it - high five!

Moody Synths

Now we have the bass line, let’s re-create some of the ambience of the operatic scene. One synth to try out is :blade which is a moody 80s style synth lead. Let’s try it with the starting note :d passed through a slicer and reverb:

live_loop :habanera do
  use_synth :fm
  use_transpose -12
  play (ring :d, :r, :r, :a, :f5, :r, :a, :r).tick
  sleep 0.25
end
with_fx :reverb do
  live_loop :space_light do
    with_fx :slicer, phase: 0.25 do
      synth :blade, note: :d, release: 8, cutoff: 100, amp: 2
    end
    sleep 8
  end
end

Now, try the other notes in the bass line: :a and :f5. Remember, you don’t need to hit stop, just modify the code whilst the music is playing and hit run again. Also, try different values for the slicer’s phase: opt such as 0.5, 0.75 and 1.

Bringing it all together

Finally, let’s combine all the ideas so far into a new remix of the Habanera. You might notice that I’ve included another part of the bass line as a comment. Once you’ve typed it all into a fresh buffer hit Run to hear the composition. Now, without hitting stop, uncomment the second line by removing the # and hit run again - how marvellous is that! Now, start mashing it around yourself and have fun.

use_debug false
bizet_bass = (ring :d, :r, :r, :a, :f5, :r, :a, :r)
#bizet_bass = (ring :d, :r, :r, :Bb, :g5, :r, :Bb, :r)
 
with_fx :reverb, room: 1, mix: 0.3 do
  live_loop :bizet do
    with_fx :slicer, phase: 0.125 do
      synth :blade, note: :d4, release: 8,
        cutoff: 100, amp: 1.5
    end
    16.times do
      tick
      play bizet_bass.look, release: 0.1
      play bizet_bass.look - 12, release: 0.3
      sleep 0.125
    end
  end
end
 
live_loop :ind do
  sample :loop_industrial, beat_stretch: 1,
    cutoff: 100, rate: 1
  sleep 1
end
 
live_loop :drums do
  sample :bd_haus, cutoff: 110
  synth :beep, note: 49, attack: 0,
    release: 0.1
  sleep 0.5
end

- Become a Minecraft VJ

Screen 0

Everyone has played Minecraft. You will all have built amazing structures, designed cunning traps and even created elaborate cart lines controlled by redstone switches. How many of you have performed with Minecraft? We bet you didn’t know that you could use Minecraft to create amazing visuals just like a professional VJ.

If your only way of modifying Minecraft was with the mouse, you’d have a tough time changing things fast enough. Luckily for you your Raspberry Pi comes with a version of Minecraft that can be controlled with code. It also comes with an app called Sonic Pi which makes coding Minecraft not only easy but also incredibly fun.

In today’s article we’ll be showing you some of the tips and tricks that we’ve used to create performances in night clubs and music venues around the world.

Let’s get started…

Getting Started

Let’s start with a simple warm up exercise to refresh ourselves with the basics. First up, crack open your Raspberry Pi and then fire up both Minecraft and Sonic Pi. In Minecraft, create a new world, and in Sonic Pi choose a fresh buffer and write in this code:

mc_message "Let's get started..."

Hit the Run button and you’ll see the message over in the Minecraft window. OK, we’re ready to start, let’s have some fun……

Sand Storms

When we’re using Minecraft to create visuals we try and think about what will both look interesting and also be easy to generate from code. One nice trick is to create a sand storm by dropping sand blocks from the sky. For that all we need are a few basic fns:

sleep - for inserting a delay between actions mc_location - to find our current location mc_set_block- to place sand blocks at a specific location rrand - to allow us to generate random values within a range live_loop - to allow us to continually make it rain sand

If you’re unfamiliar with any of the built-in fns such as rrand, just type the word into your buffer, click on it and then hit the keyboard combo Control-i to bring up the built-in documentation. Alternatively you can navigate to the lang tab in the Help system and then look up the fns directly along with all the other exciting things you can do.

Let’s make it rain a little first before unleashing the full power of the storm. Grab your current location and use it to create a few sand blocks up in the sky nearby:

x, y, z = mc_location
mc_set_block :sand, x, y + 20, z + 5
sleep 2
mc_set_block :sand, x, y + 20, z + 6
sleep 2
mc_set_block :sand, x, y + 20, z + 7
sleep 2
mc_set_block :sand, x, y + 20, z + 8

When you hit Run, you might have to look around a little as the blocks may start falling down behind you depending on which direction you’re currently facing. Don’t worry, if you missed them just hit Run again for another batch of sand rain - just make sure you’re looking the right way!

Let’s quickly review what’s going on here. On the first line we grabbed Steve’s location as coordinates with the fn mc_location and placed them into the vars x, y, and z. Then on the next lines we used the mc_set_block fn to place some sand at the same coordinates as Steve but with some modifications. We chose the same x coordinate, a y coordinate 20 blocks higher and then successively larger z coordinates so the sand dropped in a line away from Steve.

Why don’t you take that code and start playing around with it yourself? Try adding more lines, changing the sleep times, try mixing :sand with :gravel and choose different coordinates. Just experiment and have fun!

Live Loops Unleashed

OK, it’s time to get the storm raging by unleashing the full power of the live_loop - Sonic Pi’s magical ability which unleashes the full power of live coding - changing code on-the-fly whilst it’s running!

live_loop :sand_storm do
  x, y, z = mc_location
  xd = rrand(-10, 10)
  zd = rrand(-10, 10)
  co = rrand(70, 130)
  synth :cnoise, attack: 0, release: 0.125, cutoff: co
  mc_set_block :sand, x + xd, y+20, z+zd
  sleep 0.125
end

What fun! We’re looping round pretty quickly (8 times a second) and during each loop we’re finding Steve’s location like before but then generating 3 random values:

xd - the difference for x which will be between -10 and 10 zd - the difference for z also between -10 and 10 co - a cutoff value for the low pass filter between 70 and 130

We then use those random values in the fns synth and mc_set_block giving us sand falling in random locations around Steve along with a percussive rain-like sound from the :cnoise synth.

For those of you new to live loops - this is where the fun really starts with Sonic Pi. Whilst the code is running and the sand is pouring down, try changing one of the values, perhaps the sleep time to 0.25 or the :sand block type to :gravel. Now hit run again. Hey Presto! Things changed without the code stopping. This is your gateway to performing like a real VJ. Keep practising and changing things around. How different can you make the visuals without stopping the code?

Epic Block Patterns

Screensman 1

Finally, another great way of generating interesting visuals is to generate huge patterned walls to fly towards and close by. For this effect we’ll need to move from placing the blocks randomly to placing them in an ordered manner. We can do this by nesting two sets of iteration (hit the Help button and navigate to section 5.2 of the tutorial “Iteration and Loops” for more background on iteration). The funny |xd| after the do means that xd will be set for each value of the iteration. So the first time it will be 0, then 1, then 2… etc. By nesting two lots of iteration together like this we can generate all the coordinates for a square. We can then randomly choose block types from a ring of blocks for an interesting effect:

x, y, z = mc_location
bs = (ring :gold, :diamond, :glass)
10.times do |xd|
  10.times do |yd|
    mc_set_block bs.choose, x + xd, y + yd, z
  end
end

Pretty neat. Whilst we’re having fun here, try changing bs.choose to bs.tick to move from a random pattern to a more regular one. Try changing the block types and the more adventurous of you might want to try sticking this within a live_loop so that the patterns keep changing automatically.

Now, for the VJ finale - change the two 10.times to 100.times and hit Run. Kaboom! A Huge gigantic wall of randomly placed bricks. Imagine how long it would take you to build that manually with your mouse! Double-tap space to enter fly-mode and start swooping by for some great visual effects. Don’t stop here though - use your imagination to conjure up some cool ideas and then use the coding power of Sonic Pi to make it real. When you’ve practised enough dim the lights and put on a VJ show for your friends!


- Surfing Random Streams

Back in episode 4 of this tutorial series we took a brief look at randomisation whilst coding up some sizzling synth riffs. Given that randomisation is such an important part of my live coding DJ sets I thought it would be useful to cover the fundamentals in much greater detail. So, get your lucky hat on and let’s surf some random streams!

There is no random

The first thing to learn which might really surprise you when playing with Sonic Pi’s randomisation functions is that they’re not actually really random. What does this actually mean? Well, let’s try a couple of tests. First, imagine a number in your head between 0 and 1. Keep it there and don’t tell me. Now let me guess… was it 0.321567? No? Bah, I’m clearly no good at this. Let me have another go, but let’s ask Sonic Pi to choose a number this time. Fire up Sonic Pi v2.7+ and ask it for a random number but again don’t tell me:

print rand

Now for the reveal… was it 0.75006103515625? Yes! Ha, I can see you’re a little sceptical. Perhaps it was just a lucky guess. Let’s try again. Press the Run button again and see what we get… What? 0.75006103515625 again? This clearly can’t be random! You’re right, it’s not.

What’s going on here? The fancy computer science word here is determinism. This just means that nothing is by chance and everything is destined to be. Your version of Sonic Pi is destined to always return 0.75006103515625 in the program above. This might sound pretty useless, but let me assure you that it’s one of the most powerful parts of Sonic Pi. If you stick at it you’ll learn how to rely on the deterministic nature of Sonic Pi’s randomisation as a fundamental building block for your compositions and live coded DJ sets.

A Random Melody

When Sonic Pi boots it actually loads into memory a sequence of 441,000 pre-generated random values. When you call a random function such as rand or rrand, this random stream is used to generate your result. Each call to a random function consumes a value from this stream. Therefore the 10th call to a random function will use the 10th value from the stream. Also, every time you press the Run button, the stream is reset for that run. This is why I could predict the result to rand and why the ‘random’ melody was the same every time. Everybody’s version of Sonic Pi uses the exact same random stream which is very important when we start sharing our pieces with each other.

Let’s use this knowledge to generate a repeatable random melody:

8.times do
 play rrand_i(50, 95)
 sleep 0.125
end

Type this into a spare buffer and hit Run. You’ll hear a melody consisting of ‘random’ notes between 50 and 95. When it’s finished, hit Run again to hear exactly the same melody again.

Handy Randomisation Functions

Sonic Pi comes with a number of useful functions for working with the random stream. Here’s a list of some of the most useful:

rand - Simply returns the next value in the random stream rrand - Returns a random value within a range rrand_i - Returns a random whole number within a range one_in - Returns true or false with the given probability dice - Imitates rolling a dice and returns a value between 1 and 6 choose - Chooses a random value from a list

Check out their documentation in the Help system for detailed information and examples.

Resetting the Stream

Whilst the ability to repeat a sequence of chosen notes is essential to allow you to replay a riff on the dance floor, it might not be exactly the riff you want. Wouldn’t it be great if we could try a number of different riffs and choose the one we liked best? This is where the real magic starts.

We can manually set the stream with the fn use_random_seed. In Computer Science, a random seed is the starting point from which a new stream of random values can sprout out and blossom. Let’s try it:

use_random_seed 0
3.times do
  play rrand_i(50, 95)
  sleep 0.125
end

Great, we get the first three notes of our random melody above: 84, 83 and 71. However, we can now change the seed to something else. How about this:

use_random_seed 1
3.times do
  play rrand_i(50, 95)
  sleep 0.125
end

Interesting, we get 83, 71 and 61 . You might notice that the first two numbers here are the same as the last two numbers before - this isn’t a coincidence.

Remember that the random stream is just a giant list of ‘pre-rolled’ values. Using a random seed simply jumps us to a point in that list. Another way of thinking about it is to imagine a huge deck of pre-shuffled cards. Using a random seed is cutting the deck at a particular point. The fabulous part of this is that it’s precisely this ability to jump around the random stream which gives us huge power when making music.

Let’s revisit our random melody of 8 notes with this new stream resetting power, but let’s also throw in a live loop so we can experiment live whilst it’s playing:

live_loop :random_riff do    
  use_random_seed 0
  8.times do
    play rrand_i(50, 95), release: 0.1
    sleep 0.125
  end
end

Now, whilst it’s still playing, change the seed value from 0 to something else. Try 100, what about 999. Try your own values, experiment and play around - see which seed generates the riff you like best.

Bringing it all together

This month’s tutorial has been quite a technical dive into the workings of Sonic Pi’s randomisation functionality. Hopefully it has given you some insight into how it works and how you can start using randomisation in a reliable way to create repeatable patterns within your music. It’s important to stress that you can use repeatable randomisation anywhere you want. For example, you can randomise the amplitude of notes, the timing of the rhythm, the amount of reverb, the current synth, the mix of an FX, etc. etc. In the future we’ll take a close look at some of these applications, but for now let me leave you with a short example.

Type the following into a spare buffer, hit Run, and then start changing the seeds around, hit Run again (whilst it’s still playing) and explore the different sounds, rhythms and melodies you can make. When you find a nice one, remember the seed number so you can get back to it. Finally, when you’ve found a few seeds you like, put on a live coded performance for your friends by simply switching between your favourite seeds to create a full piece.

live_loop :random_riff do
  use_random_seed 10300
  use_synth :prophet
  s = [0.125, 0.25, 0.5].choose
  8.times do
    r = [0.125, 0.25, 1, 2].choose
    n = (scale :e3, :minor).choose
    co = rrand(30, 100)
    play n, release: r, cutoff: co
    sleep s
  end
end
live_loop :drums do
  use_random_seed 2001
  16.times do
    r = rrand(0.5, 10)
    sample :drum_bass_hard, rate: r, amp: rand
    sleep 0.125
  end
end

- Controlling Your Sound

So far during this series we’ve focussed on triggering sounds. We’ve discovered that we can trigger the many synths built into Sonic Pi with play or synth and how to trigger pre-recorded samples with sample. We’ve also looked at how we can wrap these triggered sounds within studio FX such as reverb and distortion using the with_fx command. Combine this with Sonic Pi’s incredibly accurate timing system and you can produce a vast array of sounds, beats and riffs. However, once you’ve carefully selected a particular sound’s options and triggered it, there’s no ability to mess with it whilst it’s playing right? Wrong! Today you’re going to learn something very powerful - how to control running synths.

A Basic Sound

Let’s create a nice simple sound. Fire up Sonic Pi and in a fresh buffer type the following:

synth :prophet, note: :e1, release: 8, cutoff: 100

Now press the Run button at the top left to hear a lovely rumbling synth sound. Go ahead, press it again a few times to get a feel for it. OK, done? Let’s start controlling it!

Synth Nodes

A little known feature in Sonic Pi is that the fns play, synth and sample, return something called a SynthNode which represents a running sound. You can capture one of these SynthNodes using a standard variable and then control it at a later point in time. For example, let’s change the value of the cutoff: opt after 1 beat:

sn = synth :prophet, note: :e1, release: 8, cutoff: 100
sleep 1
control sn, cutoff: 130

Let’s look at each line in turn:

Firstly we trigger the :prophet synth using the synth fn as normal. However we also capture the result in a variable called sn. We could have called this variable something completely different such as synth_node or jane - the name doesn’t matter. However, it’s important to choose a name that’s meaningful to you for your performances and for people reading your code. I chose sn as it’s a nice short mnemonic for synth node.

On line 2 we have a standard sleep command. This does nothing special - it just asks the computer to wait for 1 beat before moving onto the next line.

Line 3 is where the control fun starts. Here, we use the control fn to tell our running SynthNode to change the cutoff value to 130. If you hit the Run button, you’ll hear the :prophet synth start playing as before, but after 1 beat it will shift to sound a lot brighter.

Modulatable Options

Most of Sonic Pi’s synths and FX opts may be changed after being triggered. However, this isn’t the case for all of them. For example, the envelope opts attack:, decay:, sustain: and release: can only be set when triggering the synth. Figuring out which opts can and can’t be changed is simple - just head to the documentation for a given synth or FX and then scroll down to the individual option documentation and look for the phrases “May be changed whilst playing” or “Can not be changed once set”. For example, the documentation for the :beep synth’s attack: opt makes it clear that it’s not possible to change it:

Default: 0 Must be zero or greater Can not be changed once set Scaled with current BPM value

Multiple Changes

Whilst a synth is running you’re not limited to changing it only once - you’re free to change it as many times as you like. For example, we can turn our :prophet into a mini arpeggiator with the following:

notes = (scale :e3, :minor_pentatonic)
sn = synth :prophet, note: :e1, release: 8, cutoff: 100
sleep 1
16.times do
  control sn, note: notes.tick
  sleep 0.125
end

In this snippet of code we just added a couple of extra things. First we defined a new variable called notes which contains the notes we’d like to cycle through (an arpeggiator is just a fancy name for something that cycles through a list of notes in order). Secondly we replaced our single call to control with an iteration calling it 16 times. In each call to control we .tick through our ring of notes which will automatically repeat once we get to the end (thanks to the fabulous power of Sonic Pi’s rings). For a bit of variety try replacing .tick with .choose and see if you can hear the difference.

Note that we can change multiple opts simultaneously. Try changing the control line to the following and listen for the difference:

control sn, note: notes.tick, cutoff: rrand(70, 130)

Sliding

When we control a SynthNode, it responds exactly on time and instantly changes the value of the opt to the new one as if you’d pressed a button or flicked a switch requesting the change. This can sound rhythmical and percussive - especially if the opt controls an aspect of the timbre such as cutoff:. However, sometimes you don’t want the change to happen instantaneously. Instead, you might want to smoothly move from the current value to the new one as if you’d moved a slider or dial. Of course, Sonic Pi can also do this too using the _slide: opts.

Each opt that can be modified also has a special corresponding _slide: opt that allows you to specify a slide time. For example, amp: has amp_slide: and cutoff: has cutoff_slide:. These slide opts work slightly differently than all the other opts in that they tell the synth note how to behave next time they are controlled. Let’s take a look:

sn = synth :prophet, note: :e1, release: 8, cutoff: 70, cutoff_slide: 2
sleep 1
control sn, cutoff: 130

Notice how this example is exactly the same as before except with the addition of cutoff_slide:. This is saying that next time this synth has its cutoff: opt controlled, it will take 2 beats to slide from the current value to the new one. Therefore, when we use control you can hear the cutoff slide from 70 to 130. It creates an interesting dynamic feel to the sound. Now, try changing the cutoff_slide: time to a shorter value such as 0.5 or a longer value such as 4 to see how it changes the sound. Remember, you can slide any of the modifiable opts in exactly this way and each _slide: value can be totally different so you can have the cutoff sliding slowly, the amp sliding fast and the pan sliding somewhere in between if that’s what you’re looking to create…

Bringing it all together

Let’s look at a short example which demonstrates the power of controlling synths after they’ve been triggered. Notice that you can also slide FX just like synths although with a slightly different syntax. Check out section 7.2 of the built-in tutorial for more information on controlling FX.

Copy the code into a spare buffer and take a listen. Don’t stop there though - play around with the code. Change the slide times, change the notes, the synth, the FX and the sleep times and see if you can turn it into something completely different!

live_loop :moon_rise do
  with_fx :echo, mix: 0, mix_slide: 8 do |fx|
    control fx, mix: 1
    notes = (scale :e3, :minor_pentatonic, num_octaves: 2).shuffle
    sn = synth :prophet , sustain: 8, note: :e1, cutoff: 70, cutoff_slide: 8
    control sn, cutoff: 130
    sleep 2
    32.times do
      control sn, note: notes.tick, pan: rrand(-1, 1)
      sleep 0.125
    end
  end
end

- Tracking the Beat

Last month in this series we took a deep technical dive into the randomisation system underpinning Sonic Pi. We explored how we can use it to deterministically add new levels of dynamic control over our code. This month we’re going to continue our technical dive and turn our attention to Sonic Pi’s unique tick system. By the end of this article you’ll be ticking your way through rhythms and riffs on your way to being a live coding DJ.

Beat Counting

When making music we often want to do a different thing depending on which beat it is. Sonic Pi has a special beat counting system called tick to give you precise control over when a beat actually occurs and even supports multiple beats with their own tempos.

Let’s have a play - to advance the beat we just need to call tick. Open up a fresh buffer, type in the following and hit Run:

puts tick #=> 0

This will return the current beat: 0. Notice that even if you press the Run button a few times it will always return 0. This is because each run starts a fresh beat counting from 0. However, whilst the run is still active, we can advance the beat as many times as we want:

puts tick #=> 0
puts tick #=> 1
puts tick #=> 2

Whenever you see the symbol #=> at the end of a line of code it means that that line will log the text on the right-hand-side. For example, puts foo #=> 0 means the code puts foo prints 0 to the log at that point in the program.

Checking the Beat

We’ve seen that tick does two things. It increments (adds one) and returns the current beat. Sometimes we just want to look at the current beat without having to increment it which we can do via look:

puts tick #=> 0
puts tick #=> 1
puts look #=> 1
puts look #=> 1

In this code we tick the beat up twice and then call look twice. We’ll see the following values in the log: 0, 1, 1, 1. The first two ticks returned 0, then 1 as expected, then the two looks just returned the last beat value twice which was 1.

Anéis

So now we can advance the beat with tick and check the beat with look. What next? We need something to tick over. Sonic Pi uses rings for representing riffs, melodies and rhythms and the tick system has been specifically designed to work very closely with them. In fact, rings have their own dot version of tick which does two things. Firstly, it acts like a regular tick and increments the beat. Secondly it looks up the ring value using the beat as the index. Let’s take a look:

puts (ring :a, :b, :c).tick #=> :a

.tick is a special dot version of tick which will return the first value of the ring :a. We can grab each of the values in the ring by calling .tick multiple times:

puts (ring :a, :b, :c).tick #=> :a
puts (ring :a, :b, :c).tick #=> :b
puts (ring :a, :b, :c).tick #=> :c
puts (ring :a, :b, :c).tick #=> :a
puts look                   #=> 3

Take a look at the log and you’ll see :a, :b, :c and then :a again. Notice that look returns 3. Calls to .tick act just like they are regular calls to tick - they increment the local beat.

Um Live Loop Arpegiador

O poder real surge quando você mistura tick com anéis (rings) e live_loops. Quando combinados nós temos todas as ferramentas que nós precisamos para tanto construir quanto entender um arpejador simples. Precisamos somente de 4 coisas:

Um anel (ring) contendo as notas que queremos arpejar. Uma forma de incrementar e obter a batida. A habilidade de tocar uma nota baseada na batida atual. Uma estrutura de loop para manter o arpejador repetindo.

Todos estes conceitos podem ser encontrados no seguinte código:

notes = (ring 57, 62, 55, 59, 64)
live_loop :arp do
  use_synth :dpulse
  play notes.tick, release: 0.2
  sleep 0.125
end

Let’s look at each of these lines. First we define our ring of notes which we’ll continually play. We then create a live_loop called :arp which loops round for us. Each time round the live_loop we set our synth to :dpulse and then play the next note in our ring using .tick. Remember that this will increment our beat counter and use the latest beat value as an index into our notes ring. Finally, we wait for an eighth of a beat before looping round again.

Multiple Simultaneous Beats

A really important thing to know is that ticks are local to the live_loop. This means that each live_loop has its own independent beat counter. This is much more powerful than having a global metronome and beat. Let’s take a look at this in action:

notes = (ring 57, 62, 55, 59, 64)
with_fx :reverb do
  live_loop :arp do
    use_synth :dpulse
    play notes.tick + 12, release: 0.1
    sleep 0.125
  end
end
live_loop :arp2 do
  use_synth :dsaw
  play notes.tick - 12, release: 0.2
  sleep 0.75
end

Clashing Beats

A big cause of confusion with Sonic Pi’s tick system is when people want to tick over multiple rings in the same live_loop:

use_bpm 300
use_synth :blade
live_loop :foo do
  play (ring :e1, :e2, :e3).tick
  play (scale :e3, :minor_pentatonic).tick
  sleep 1
end

Even though each live_loop has its own independent beat counter, we’re calling .tick twice within the same live_loop. This means that the beat will be incremented twice every time round. This can produce some interesting polyrhythms but is often not what you want. There are two solutions to this problem. One option is to manually call tick at the start of the live_loop and then use .look to look up the current beat in each live_loop. The second solution is to pass a unique name to each call to .tick such as .tick(:foo). Sonic Pi will then create and track a separate beat counter for each named tick you use. That way you can work with as many beats as you need! See the section on named ticks in 9.4 of the built-in tutorial for more information.

Bringing it all together

Let’s bring all this knowledge of ticks, rings and live_loops together for a final fun example. As usual, don’t treat this as a finished piece. Start changing things and play around with it and see what you can turn it into. See you next time…

use_bpm 240
notes = (scale :e3, :minor_pentatonic).shuffle
live_loop :foo do
  use_synth :blade
  with_fx :reverb, reps: 8, room: 1 do
    tick
    co = (line 70, 130, steps: 32).tick(:cutoff)
    play (octs :e3, 3).look, cutoff: co, amp: 2
    play notes.look, amp: 4
    sleep 1
  end
end
live_loop :bar do
  tick
  sample :bd_ada if (spread 1, 4).look
  use_synth :tb303
  co = (line 70, 130, steps: 16).look
  r = (line 0.1, 0.5, steps: 64).mirror.look
  play notes.look, release: r, cutoff: co
  sleep 0.5
end

- Cortando Amostras

Way back in episode 3 of this Sonic Pi series we looked at how to loop, stretch and filter one of the most famous drum breaks of all time - the Amen Break. In this tutorial we’re going to take this one step further and learn how to slice it up, shuffle the slices and glue it back together in a completely new order. If that sounds a bit crazy to you, don’t worry, it will all become clear and you’ll soon master a powerful new tool for your live coded sets.

Sound as Data

Before we get started let’s just take a brief moment to understand how to work with samples. By now, you’ve all hopefully played with Sonic Pi’s powerful sampler. If not, there’s no time like the present! Boot up your Raspberry Pi, launch Sonic Pi from the Programming menu, type the following into a fresh buffer and then hit the Run button to hear a pre-recorded drum beat:

sample :loop_amen

A recording of a sound is simply represented as data - lots of numbers between -1 and 1 which represent the peaks and troughs of the sound wave. If we play those numbers back in order, we get the original sound. However, what’s to stop us from playing them back in a different order and creating a new sound?

How are samples actually recorded? It’s actually pretty simple once you understand the basic physics of sound. When you make a sound - for example by hitting a drum, the noise travels through the air in a similar fashion to how the surface of a lake ripples when you throw a pebble into it. When those ripples reach your ears, your eardrum moves sympathetically and converts those movements into the sound you hear. If we wish to record and play back the sound, we therefore need a way of capturing, storing and reproducing those ripples. One way is to use a microphone which acts like an eardrum and moves back and forth as the sound ripples hit it. The microphone then converts its position into a tiny electric signal which is then measured many times a second. These measurements are then represented as a series of numbers between -1 and 1.

If we were to plot a visualisation of the sound it would be a simple graph of data with time on the x axis and microphone/speaker position as a value between -1 and 1 on the y axis. You can see an example of such a graph at the top of the diagram.

Playing Part of a Sample

So, how do we code Sonic Pi to play a sample back in a different order? To answer this question we need to take a look at the start: and finish: opts for sample. These let us control the start and finish positions of our playback of the numbers which represent the sound. The values for both of these opts are represented as a number between 0 and 1 where 0 represents the start of the sample and 1 is the end. So, to play the first half of the Amen Break, we just need to specify a finish: of 0.5:

sample :loop_amen, finish: 0.5

We can add in a start: value to play an even smaller section of the sample:

sample :loop_amen, start: 0.25, finish: 0.5

For fun, you can even have the finish: opt’s value be before start: and it will play the section backwards:

sample :loop_amen, start: 0.5, finish: 0.25

Re-ordering Sample Playback

Now that we know that a sample is simply a list of numbers that can be played back in any order and also how to play a specific part of a sample we can now start having fun playing a sample back in the ‘wrong’ order.

Amen Slices

Let’s take our Amen Break and chop it up into 8 equally-sized slices and then shuffle the pieces around. Take a look at the diagram: at the top A) represents the graph of our original sample data. Chopping it into 8 slices gives us B) - notice that we’ve given each slice a different colour to help distinguish them. You can see each slice’s start and finish values at the top. Finally C) is one possible re-ordering of the slices. We can then play this back to create a new beat. Take a look at the code to do this:

live_loop :beat_slicer do
  slice_idx = rand_i(8)
  slice_size = 0.125
  s = slice_idx * slice_size
  f = s + slice_size
  sample :loop_amen, start: s, finish: f
  sleep sample_duration :loop_amen, start: s, finish: f
end

we choose a random slice to play which should be a random number between 0 and 7 (remember that we start counting at 0). Sonic Pi has a handy function for exactly this: rand_i(8). We then store this random slice index in the variable slice_idx. We define our slice_size which is 1/8 or 0.125. The slice_size is necessary for us to convert our slice_idx into a value between 0 and 1 so we can use it as our start: opt. We calculate the start position s by multiplying the slice_idx by the slice_size. We calculate the finish position f by adding the slice_size to the start position s. We can now play the sample slice by plugging in the s and f values into the start: and finish: opts for sample. Before we play the next slice we need to know how long to sleep which should be the duration of the sample slice. Luckily, Sonic Pi has us covered with sample_duration which accepts all the same opts as sample and simply returns the duration. Therefore, by passing sample_duration our start: and finish: opts, we can find out the duration of a single slice. We wrap all of this code in a live_loop so that we continue to pick new random slices to play.

Bringing it all together

Let’s combine everything we’ve seen so far into a final example which demonstrates how we can take a similar approach to combine randomly sliced beats with some bass to create the start of an interesting track. Now it’s your turn - take the code below as a starting point and see if you can take it in your own direction and create something new…

live_loop :sliced_amen do
  n = 8
  s =  line(0, 1, steps: n).choose
  f = s + (1.0 / n)
  sample :loop_amen, beat_stretch: 2, start: s, finish: f
  sleep 2.0  / n
end
live_loop :acid_bass do
  with_fx :reverb, room: 1, reps: 32, amp: 0.6 do
    tick
    n = (octs :e0, 3).look - (knit 0, 3 * 8, -4, 3 * 8).look
    co = rrand(70, 110)
    synth :beep, note: n + 36, release: 0.1, wave: 0, cutoff: co
    synth :tb303, note: n, release: 0.2, wave: 0, cutoff: co
    sleep (ring 0.125, 0.25).look
  end
end

- Code a Probabilistic Sequencer

In a previous episode of this Sonic Pi series we explored the power of randomisation to introduce variety, surprise and change into our live coded tracks and performances. For example, we randomly picked notes from a scale to create never-ending melodies. Today we’re going to learn a new technique which uses randomisation for rhythm - probabilistic beats!

Probability

Before we can start making new beats and synth rhythms we need to take a quick dive into the basics of probability. This might sound daunting and complicated, but really it’s just as simple as rolling a dice - honestly! When you take a regular 6 sided board game dice and roll it what’s actually happening? Well, firstly you’ll roll either a 1, 2, 3, 4, 5 or 6 with exactly the same chance of getting any of the numbers. In fact, given that it’s a 6 sided dice, on average (if you roll lots and lots of times) you’ll throw a 1 every 6 throws. This means you have a 1 in 6 chance of throwing a 1. We can emulate dice rolls in Sonic Pi with the fn dice. Let’s roll one 8 times:

8.times do
  puts dice
  sleep 1
end

Notice how the log prints values between 1 and 6 just as if we’d rolled a real dice ourselves.

Random Beats

Now imagine you had a drum and every time you were about to hit it you rolled a dice. If you rolled a 1, you hit the drum and if you rolled any other number you didn’t. You now have a probabilistic drum machine working with a probability of 1/6! Let’s hear what that sounds like:

live_loop :random_beat do
  sample :drum_snare_hard if dice == 1
  sleep 0.125
end

Let’s quickly go over each line to make sure everything is very clear. First we create a new live_loop called :random_beat which will continually repeat the two lines between do and end. The first of these lines is a call to sample which will play a pre-recorded sound (the :drum_snare_hard sound in this case). However, this line has a special conditional if ending. This means that the line will only be executed if the statement on the right hand side of the if is true. The statement in this case is dice == 1. This calls our dice function which, as we have seen, returns a value between 1 and 6. We then use the equality operator == to check to see if this value is 1. If it is 1, then the statement resolves to true and our snare drum sounds, if it isn’t 1 then the statement resolves to false and the snare is skipped. The second line simply waits for 0.125 seconds before rolling the dice again.

Changing Probabilities

Those of you that have played role play games will be familiar with lots of strangely shaped dice with different ranges. For example there is the tetrahedron shaped dice which has 4 sides and even a 20 sided dice in the shape of a icosahedron. The number of sides on the dice changes the chance, or probability of rolling a 1. The fewer sides, the more likely you are to roll a 1 and the more sides the less likely. For example, with a 4 sided dice, there’s a one in 4 chance of rolling a 1 and with a 20 sided dice there’s a one in 20 chance. Luckily, Sonic Pi has the handy one_in fn for describing exactly this. Let’s play:

live_loop :different_probabilities do
  sample :drum_snare_hard if one_in(6)
  sleep 0.125
end

Start the live loop above and you’ll hear the familiar random rhythm. However, don’t stop the code running. Instead, change the 6 to a different value such as 2 or 20 and hit the Run button again. Notice that lower numbers mean the snare drum sounds more frequently and higher numbers mean the snare triggers fewer times. You’re making music with probabilities!

Combining Probabilities

Things get really exciting when you combine multiple samples being triggered with different probabilities. For example:

live_loop :multi_beat do
  sample :elec_hi_snare if one_in(6)
  sample :drum_cymbal_closed if one_in(2)
  sample :drum_cymbal_pedal if one_in(3)
  sample :bd_haus if one_in(4)
  sleep 0.125
end

Again, run the code above and then start changing the probabilities to modify the rhythm. Also, try changing the samples to create an entirely new feel. For example try changing :drum_cymbal_closed to :bass_hit_c for extra bass!

Repeatable Rhythms

Next, we can use our old friend use_random_seed to reset the random stream after 8 iterations to create a regular beat. Type the following code to hear a much more regular and repeating rhythm. Once you hear the beat, try changing the seed value from 1000 to another number. Notice how different numbers generate different beats.

live_loop :multi_beat do
  use_random_seed 1000
  8.times do
    sample :elec_hi_snare if one_in(6)
    sample :drum_cymbal_closed if one_in(2)
    sample :drum_cymbal_pedal if one_in(3)
    sample :bd_haus if one_in(4)
    sleep 0.125
  end
end

One thing I tend to do with this kind of structure is to remember which seeds sound good and make a note of them. That way I can easily re-create my rhythms in future practice sessions or performances.

Bringing it all together

Finally, we can throw in some random bass to give it some nice melodic content. Notice that we can also use our newly discovered probabilistic sequencing method on synths just as well as samples. Don’t leave it at that though - tweak the numbers and make your own track with the power of probabilities!

live_loop :multi_beat do
  use_random_seed 2000
  8.times do
    c = rrand(70, 130)
    n = (scale :e1, :minor_pentatonic).take(3).choose
    synth :tb303, note: n, release: 0.1, cutoff: c if rand < 0.9
    sample :elec_hi_snare if one_in(6)
    sample :drum_cymbal_closed if one_in(2)
    sample :drum_cymbal_pedal if one_in(3)
    sample :bd_haus, amp: 1.5 if one_in(4)
    sleep 0.125
  end
end

- Amplitude Modulation

This month we’re going to take a deep dive into one of Sonic Pi’s most powerful and flexible audio FX - the :slicer. By the end of this article you will have learned how to manipulate the overall volume of parts of our live coded sound in powerful new ways. This will allow you to create new rhythmic and timbral structures and broaden your sonic possibilities.

Slice that Amp

So, what does the :slicer FX actually do? One way to think about it is that it’s just like having someone play around with the volume control on your TV or home hi-fi. Let’s take a look but first, listen to the deep growl of the following code which triggers the :prophet synth:

synth :prophet, note: :e1, release: 8, cutoff: 70
synth :prophet, note: :e1 + 4, release: 8, cutoff: 80

Now, let’s pipe it through the :slicer FX:


with_fx :slicer do
  synth :prophet, note: :e1, release: 8, cutoff: 70
  synth :prophet, note: :e1 + 4, release: 8, cutoff: 80
end

Hear how the slicer acts like it’s muting and unmuting the audio with a regular beat. Also, notice how the :slicer affects all the audio generated between the do/end blocks. You can control the speed at which it turns the audio on and off with the phase: opt which is short for phase duration. Its default value is 0.25 which means 4 times a second at the default BPM of 60. Let’s make it faster:

with_fx :slicer, phase: 0.125 do
  synth :prophet, note: :e1, release: 8, cutoff: 70
  synth :prophet, note: :e1 + 4, release: 8, cutoff: 80
end

Now, play with different phase: durations yourself. Try longer and shorter values. See what happens when you choose a really short value. Also, try different synths such as :beep or :dsaw and different notes. Take a look at the following diagram to see how different phase: values change the number of amplitude changes per beat.

Duração

Phase duration is the length of time for one on/off cycle. Therefore smaller values will make the FX switch on and off much faster than larger values. Good values to start playing with are 0.125, 0.25, 0.5 and 1.

Control Waves

By default, the :slicer FX uses a square wave to manipulate the amplitude through time. This is why we hear the amplitude on for a period, then immediately off for a period, then back on again. It turns out that the square wave is just one of 4 different control waves that are supported by :slicer. The others are saw, triangle and (co)sine. Take a look at the diagram below to see what these look like. We can also hear what they sound like. For example, the following code uses (co)sine as the control wave. Hear how the sound doesn’t turn on and off abruptly but instead smoothly fades in and out:

with_fx :slicer, phase: 0.5, wave: 3 do
  synth :dsaw, note: :e3, release: 8, cutoff: 120
  synth :dsaw, note: :e2, release: 8, cutoff: 100
end

Have a play with the different wave forms by changing the wave: opt to 0 for saw, 1 for square, 2 for triangle and 3 for sine. See how different waves sound with different phase: opts too.

Each of these waves can be inverted with the invert_wave: opt which flips it on the y axis. For example, in a single phase the saw wave typically starts high, and slowly goes down before jumping back to the top. With invert_wave: 1 it will start low and slowly go up before jumping back down again. Additionally, the control wave can be started at different points with the phase_offset: opt which should be a value between 0 and 1. By playing around with phase:, wave:, invert_wave: and phase_offset opts you can dramatically change how the amplitude is modified through time.

Duração

Setting your levels

By default, :slicer switches between amplitude values 1 (fully loud) and 0 (silent). This can be changed with the amp_min: and amp_max: opts. You can use this alongside the sine wave setting to create a simple tremolo effect:

with_fx :slicer, amp_min: 0.25, amp_max: 0.75, wave: 3, phase: 0.25 do
  synth :saw, release: 8
end

This is just like grabbing the volume knob on your hi-fi and moving it up and down just a little so the sound ‘wobbles’ in and out.

Probabilities

One of :slicer’s powerful features is its ability to use probability to choose whether or not to turn the slicer on or off. Before the :slicer FX starts a new phase it rolls a dice and based on the result either uses the selected control wave or keeps the amplitude off. Let’s take a listen:

with_fx :slicer, phase: 0.125, probability: 0.6  do
  synth :tb303, note: :e1, cutoff_attack: 8, release: 8
  synth :tb303, note: :e2, cutoff_attack: 4, release: 8
  synth :tb303, note: :e3, cutoff_attack: 2, release: 8
end

Hear how we now have an interesting rhythm of pulses. Try changing the probability: opt to a different value between 0 and 1. Values closer to 0 will have more space between each sound due to the likelihood of the sound being triggered being much lower.

Another thing to notice is that the probability system in the FX is just like the randomisation system accessible via fns such as rand and shuffle. They are both completely deterministic. This means that each time you hit Run you’ll hear exactly the same rhythm of pulses for a given probability. If you would like to change things around you can use the seed: opt to select a different starting seed. This works exactly the same as use_random_seed but only affects that particular FX.

Finally, you can change the ‘resting’ position of the control wave when the probability test fails from 0 to any other position with the prob_pos: opt:

with_fx :slicer, phase: 0.125, probability: 0.6, prob_pos: 1  do
  synth :tb303, note: :e1, cutoff_attack: 8, release: 8
  synth :tb303, note: :e2, cutoff_attack: 4, release: 8
  synth :tb303, note: :e3, cutoff_attack: 2, release: 8
end

Slicing Beats

One really fun thing to do is to use :slicer to chop a drum beat in and out:

with_fx :slicer, phase: 0.125 do
  sample :loop_mika
end

This allows us to take any sample and create new rhythmical possibilites which is a lot of fun. However, one thing to be careful about is to make sure that the tempo of the sample matches the current BPM in Sonic Pi otherwise the slicing will sound totally off. For example, try swapping :loop_mika with the loop_amen sample to hear how bad this can sound when the tempos don’t align.

Mudar a Velocidade (Rate)

As we have already seen, changing the default BPM with use_bpm will make all the sleep times and synth envelope durations grow or shrink to match the beat. The :slicer FX honours this too, as the phase: opt is actually measured in beats not seconds. We can therefore fix the issue with loop_amen above by changing the BPM to match the sample:

sample :loop_amen

Bringing it all together

Let’s apply all these ideas into a final example that only uses the :slicer FX to create an interesting combination. Go ahead, start changing it and make it into your own piece!

sample :guit_em9, rate: 0.5

- Programar em tempo Real

Last month we took a look at five important techniques for mastering live coding - in other words, we explored how we could use Sonic Pi to approach code in the same way we would approach a musical instrument. One of the important concepts that we discussed was practice. This month we’re going to take a deeper dive into understanding why live coding practice is important and how you might start.

Practice regularly

The most important piece of advice is to make sure you practice regularly. As a rule I typically practice for 1-2 hours a day, but 20 mins is just fine when you’re starting out. Little but often is what you’re aiming for - so if you can only manage 10 minutes, that’s a great start.

Practice tip #1 - start to develop a practice routine. Find a nice time in the day that works for you and try and practice at that time as many days of the week as you can. Before long you’ll be looking forward to your regular session.

Learn to Touch Type

If you watch a professional musician performing on stage you’ll likely notice a few things. Firstly, when they play they don’t stare at their instrument. Their fingers, arms and bodies know which keys to press, strings to pluck or drums to hit without them having to think about it too much. This is known as “muscle memory” and although it might sound like something only professionals can do - it’s just the same as when you first learned to walk or ride a bike - practicing through repetition. Live coders use muscle memory to free their minds from having to think about where to move their fingers so they can focus on the music. This is called touch-typing - typing without having to look at the keyboard.

Practice tip #2 - learn how to touch type. There are many apps, websites and even games which can help you achieve this. Find one you like the look of and stick at it until you can code without looking down.

Code whilst standing

The body of a musician is conditioned for playing their instrument. For example, a trumpet player needs to be able to blow hard, a guitar player needs to be able to grip the fretboard with strength and a drummer needs to be able to continually hit the drums for long periods of time. So, what’s physical about live coding? Just like DJs, live coders typically perform whilst standing up and some even dance whilst they code! If you practice live coding whilst sitting at a desk and then have to get up and stand at a gig, you’ll likely find the difference very difficult and frustrating.

Practice tip #3 - stand whilst you practice. The easiest way to do this is to use a standing height desk. However, if like me you don’t have one at home, there’s a couple of low-fi options. The approach I take is to use an ironing board which happens to work rather well. Another is to stack some boxes or large books on a normal desk and place your keyboard on top of that. Also, make sure you stretch before you start practicing and try and dance a little during the session. Remember, nobody is watching you, so have fun and you’ll feel much more natural on stage.

Practice setting up

Most instruments require some assembly and tuning before they can be played. Unless you’re a rockstar with a bus full of roadies, you’ll have to set up your own instrument before your gig. This is often a stressful time and it is easy for problems to occur. One way to help with this is to incorporate the setup process into your practice sessions.

Practice tip #4 - treat setting up as an important part of your practice. For example, have a box or bag that you can keep your Raspberry Pi and keyboard in etc. Before each practice session, take out all the parts, connect everything, and work through the boot process until you have Sonic Pi running and can make sounds. Once you’ve finished practicing, take the time to carefully pack everything away afterwards. This may take some time at first, but before long you’ll be able to setup and pack everything away incredibly quickly without having to think about it.

Experiment Musically

Once you’ve set up and are ready to start making music, you might find yourself struggling to know where to start. One problem many people face is that they might have a good idea of the kinds of sounds they want to make, but are frustrated that they can’t produce them. Some people don’t even know what kind of sounds they want to make! The first thing to do is not to worry - this is very common and happens to every musician - even if they’ve been practicing for a long time. It is much more important to be making sounds you don’t like than not making any sounds at all.

Practice tip #5 - spend time making sounds and music you don’t like. Try to make time to explore new sounds and ideas. Don’t worry that it might sound terrible if it’s not the style you’re looking for. When you’re experimenting like this you increase the chance of stumbling over a sound or combination of sounds which you love! Even if 99% of the sounds you make are bad, that 1% might be the riff or intro to your new track. Forget the things you don’t like and remember the parts you do. This is even easier when you’re making music with code - just hit save!

Hear the Code

rand

Practice tip #6 - write some code into Sonic Pi but don’t hit the Run button. Instead, try to imagine what sound it is going to produce. Then, hit Run, listen, and think about what you got right and what you didn’t. Keep repeating this until it become a natural part of your coding process. When I practice I normally have a good idea of what the code will sound like. However, I still am occasionally surprised, and then I’ll stop and spend some time thinking about why I was wrong. Each time this happens, I learn new tricks which allow me to express myself in new ways.

Remove all distractions

A common problem when practicing is to become distracted with other things. Practicing is hard and requires real discipline regardless of the kind of music you’re making - from jazz to classical to EDM. If you’re struggling to get started or make progress, it’s often too easy to hop on social media, or look something up on the internet etc. If you’ve set yourself a target of 20 minutes of practice, it’s important to try and spend all that time being as productive as possible.

Practice tip #7 - before you start practicing remove as many distractions as possible. For example, disconnect from the internet, put your phone in another room and try to practice in a quiet place where you’re unlikely to be disturbed. Try to focus on coding music and you can return to your distractions when you’ve finished.

Keep a practice diary

When you are practicing, you’ll often find your mind is full of new exciting ideas - new musical directions, new sounds to try out, new functions to write, etc. These ideas are often so interesting that you might stop what you’re doing and start working on the idea. This is another form of distraction!

Practice tip #8 - keep a practice diary by your keyboard. When you get an exciting new idea, temporarily pause your practice session, quickly jot the idea down, then forget about it and carry on practicing. You can then spend some quality time thinking about and working on your ideas after you’ve finished practicing.

Bringing it all together

Try to establish a practice routine which incorporates as many of these ideas as possible. Try to keep the sessions as fun as possible but be aware that some practice sessions will be hard and feel a little like work. However, it will all be worth it once you’ve created your first piece or given your first performance. Remember, practice is the key to success!


- Sample Stretching

When people discover Sonic Pi, one of the first things they learn is how simple it is to play pre-recorded sounds using the sample function. For example, you can play an industrial drum loop, hear the sound of a choir or even listen to a vinyl scratch all via a single line of code. However, many people don’t realise that you can actually vary the speed that the sample is played back at for some powerful effects and a whole new level of control over your recorded sounds. So, fire up a copy of Sonic Pi and let’s get started stretching some samples!

Samples

To modify the playback rate of a sample we need to use the rate: opt:

sample :guit_em9, rate: 0.5

If we specify a rate: of 1 then the sample is played back at the normal rate. If we want to play it back at half speed we simply use a rate: of 0.5:

sample :guit_em9, rate: 0.5

escolhe

Samples

In addition to making the sound longer and lower using a small rate, we can use higher rates to make the sound shorter and higher. Let’s play with a drum loop this time. First, take a listen to how it sounds at the default rate of 1:

sample :loop_amen, rate: -1

Now, let’s speed it up a little:

sample :loop_amen, rate: 1.5

Ha! We just moved musical genres from old-skool techno to jungle. Notice how the pitch of each drum hit is higher as well as how the whole rhythm speeds up. Now, try even higher rates and see how high and short you can make the drum loop. For example, if you use a rate of 100, the drum loop turns into a click!

Reverse Gear

Now, I’m sure many of you are thinking the same thing right now… “what if you use a negative number for the rate?”. Great question! Let’s think about this for a moment. If our rate: opt signifies the speed with which the sample is played back, 1 being normal speed, 2 being double speed, 0.5 being half speed, -1 must mean backwards! Let’s try it on a snare. First, play it back at the normal rate:

sample :elec_filt_snare, rate: 1

Porreiro! Toca em sentido contrário!

sample :elec_filt_snare, rate: -1

Of course, you can play it backwards twice as fast with a rate of -2 or backwards at half speed with a rate of -0.5. Now, play around with different negative rates and have fun. It’s particularly amusing with the :misc_burp sample!

Sample, Rate and Pitch

One of the effects of rate modification on samples is that faster rates result in the sample sounding higher in pitch and slower rates result in the sample sounding lower in pitch. Another place you may have heard this effect in every day life is when you’re cycling or driving past a beeping pedestrian crossing - as you’re heading towards the sound source the pitch is higher than when you’re moving away from the sound - the so-called Doppler effect. Why is this?

Let’s consider a simple beep which is represented by a sine wave. If we use an oscilloscope to plot a beep, we’ll see something like Figure A. If we plot a beep an octave higher, we’ll see Figure B and an octave lower will look like Figure C. Notice that the waves of higher notes are more compact and the waves of lower notes are more spread out.

A sample of a beep is nothing more than a lot of numbers (x, y, coordinates) which when plotted onto a graph will re-draw the original curves. See figure D where each circle represents a coordinate. To turn the coordinates back into audio, the computer works through each x value and sends the corresponding y value to the speakers. The trick here is that the rate at which the computer works through the x numbers does not have to be the same as the rate with which they were recorded. In other words, the space (representing an amount of time) between each circle can be stretched or compressed. So, if the computer walks through the x values faster than the original rate, it will have the effect of squashing the circles closer together which will result in a higher sounding beep. It will also make the beep shorter as we will work through all the circles faster. This is shown in Figure E.

Finally, one last thing to know is that a mathematician called Fourier proved that any sound is actually lots and lots of sine waves all combined together. Therefore, when we compress and stretch any recorded sound we’re actually stretching and compressing many sine waves all at the same time in exactly this manner.

Pitch Bending

As we’ve seen, using a faster rate will make the sound higher in pitch and a slower rate will make the sound lower in pitch. A very simple and useful trick is to know that doubling the rate actually results in the pitch being an octave higher and inversely halving the rate results in the pitch being an octave lower. This means that for melodic samples, playing it alongside itself at double/half rates actually sounds rather nice:

sample :bass_trance_c, rate: 1
sample :bass_trance_c, rate: 2
sample :bass_trance_c, rate: 0.5

However, what if we just want to alter the rate such that the pitch goes up one semitone (one note up on a piano)? Sonic Pi makes this very easy via the rpitch: opt:

sample :bass_trance_c
sample :bass_trance_c, rpitch: 3
sample :bass_trance_c, rpitch: 7

If you take a look at the log on the right, you’ll notice that an rpitch: of 3 actually corresponds to a rate of 1.1892 and a rpitch: of 7 corresponds to a rate of 1.4983. Finally, we can even combine rate: and rpitch: opts:

sample :ambi_choir, rate: 0.25, rpitch: 3
sleep 3
sample :ambi_choir, rate: 0.25, rpitch: 5
sleep 2
sample :ambi_choir, rate: 0.25, rpitch: 6
sleep 1
sample :ambi_choir, rate: 0.25, rpitch: 1

Bringing it all together

Let’s take a look at a simple piece which combines these ideas. Copy it into an empty Sonic Pi buffer, hit play, listen to it for a while and then use it as a starting point for your own piece. See how much fun it is to manipulate the playback rate of samples. As an added exercise try recording your own sounds and play around with the rate to see what crazy sounds you can make.

sample :guit_em9

- Additive Synthesis

This is the first of a short series of articles on how to use Sonic Pi for sound design. We’ll be taking a quick tour of a number of different techniques available for you to craft your own unique sound. The first technique we’ll look at is called additive synthesis. This may sound complicated - but if we expand each word slightly the meaning pops right out. Firstly, additive means a combination of things and secondly synthesis means to create sound. Additive synthesis therefore means nothing more complicated than combining existing sounds to create new ones. This synthesis technique dates back a very long time - for example, pipe organs in the middle ages had lots of slightly different sounding pipes which you could enable or disable with stops. Pulling out the stop for a given pipe ‘added it to the mix’ making the sound richer and more complex. Now, let’s see how we can pull out all the stops with Sonic Pi.

Simple Combinations

Let’s start with the most basic sound there is - the humble pure-toned sine wave:

synth :sine, note: :d3

Now, let’s see how this sounds combined with a square wave:

synth :sine, note: :d3
synth :square, note: :d3

Notice how the two sounds combine to form a new, richer sound. Of course, we don’t have to stop there, we can add as many sounds as we need. However, we need to be careful with how many sounds we add together. Just like when we mix paints to create new colours, adding too many colours will result in a messy brown, similarly - adding too many sounds together will result in a muddy sound.

Blending

Let’s add something to make it sound a little brighter. We could use a triangle wave at an octave higher (for that high bright sound) yet only play it at amp 0.4 so it adds something extra to the sound rather than taking it over:

synth :sine, note: :d3
synth :square, note: :d3
synth :tri, note: :d4, amp: 0.4

Now, try creating your own sounds by combining 2 or more synths at different octaves and amplitudes. Also, note that you can play around with each synth’s opts to modify each source sound before it is mixed in for even more combinations of sounds.

Detuning

So far, when combining our different synths we’ve used either the same pitch or switched octave. How might it sound if we didn’t stick to octaves but instead chose a slightly higher or lower note? Let’s try it:

detune = 0.7
synth :square, note: :e3
synth :square, note: :e3 + detune

If we detune our square waves by 0.7 notes we hear something that perhaps doesn’t sound in tune or correct - a ‘bad’ note. However, as we move closer to 0 it will sound less and less out of tune as the pitches of the two waves get closer and more similar. Try it for yourself! Change the detune: opt value from 0.7 to 0.5 and listen to the new sound. Try 0.2, 0.1, 0.05, 0. Each time you change the value, take a listen and see if you can hear how the sound is changing. Notice that low detune values such as 0.1 produce a really nice ‘thick’ sound, with both slightly different pitches interacting with each other in interesting, often surprising, ways.

‘:dsaw’

Amplitude

Another way we can finely craft our sound is to use a different envelope and options for each synth trigger. For example this will allow you to make some aspects of the sound percussive and other aspects ring out for a period of time.

detune = 0.1
synth :square, note: :e1, release: 2
synth :square, note: :e1 + detune, amp: 2, release: 2
synth :gnoise, release: 2, amp: 1, cutoff: 60
synth :gnoise, release: 0.5, amp: 1, cutoff: 100
synth :noise, release: 0.2, amp: 1, cutoff: 90

In the example above I have mixed in a noisy percussive element to the sound along with some more persistent background rumbling. This was achieved firstly by using two noise synths with middling cutoff values (90 and 100) using short release times along with a noise with a longer release time but with a low cutoff value (which makes the noise less crisp and more rumbly.)

Bringing it all together

Let’s combine all these techniques to see if we can use additive synthesis to re-create a basic bell sound. I’ve broken this example into four sections. Firstly we have the ‘hit’ section which is the initial onset part of the bell sound - so uses a short envelope (e.g. a release: of around 0.1). Next we have the long ringing section in which I’m using the pure sound of the sine wave. Notice that I’m often increasing the note by roughly 12 and 24 which are the number of notes in one and two octaves. I have also thrown in a couple of low sine waves to give the sound some bass and depth. Finally, I used define to wrap my code in a function which I can then use to play a melody. Try playing your own melody and also messing around with the contents of the :bell function until you create your own crazy sound to play with!

define :bell do |n|
  # Triangle waves for the 'hit'
  synth :tri, note: n - 12, release: 0.1
  synth :tri, note: n + 0.1, release: 0.1
  synth :tri, note: n - 0.1, release: 0.1
  synth :tri, note: n, release: 0.2
  # Sine waves for the 'ringing'
  synth :sine, note: n + 24, release: 2
  synth :sine, note: n + 24.1, release: 2
  synth :sine, note: n + 24.2, release: 0.5
  synth :sine, note: n + 11.8, release: 2
  synth :sine, note: n, release: 2
  # Low sine waves for the bass
  synth :sine, note: n - 11.8, release: 2
  synth :sine, note: n - 12, release: 2
end
# Play a melody with our new bell!
bell :e3
sleep 1
bell :c2
sleep 1
bell :d3
sleep 1
bell :g2

- Subtractive Synthesis

This is the second in a series of articles on how to use Sonic Pi for sound design. Last month we looked at additive synthesis which we discovered was the simple act of playing multiple sounds at the same time to make a new combined sound. For example we could combine different sounding synths or even the same synth at different pitches to build a new complex sound from simple ingredients. This month we’ll look at a new technique commonly called subtractive synthesis which is simply the act of taking an existing complex sound and removing parts of it to create something new. This is a technique which is commonly associated with the sound of analog synthesisers of the 1960s and 1970s but also with the recent renaissance of modular analog synths through popular standards such as Eurorack.

Despite this sounding like a particularly complicated and advanced technique, Sonic Pi makes it surprisingly simple and easy - so let’s dive right in.

Complex Source Signal

For a sound to work well with subtractive synthesis, it typically needs to be fairly rich and interesting. This doesn’t mean we need something hugely complex - in fact, just a standard :square or :saw wave will do:

synth :saw, note: :e2, release: 4

Notice that this sound is already pretty interesting and contains many different frequencies above :e2 (the second E on a piano) which add to create the timbre. If that didn’t make much sense to you, try comparing it with the :beep:

synth :beep, note: :e2, release: 4

As the :beep synth is just a sine wave, you’ll hear a much purer tone and only at :e2 and none of the high crispy/buzzy sounds which you heard in the :saw. It’s this buzziness and variation from a pure sine wave that we can play with when we use subtractive synthesis.

Filtros

Once we have our raw source signal, the next step is to pass it through a filter of some kind which will modify the sound by removing or reducing parts of it. One of the most common filters used for subtractive synthesis is something called a low pass filter. This will allow all the low parts of the sound through but will reduce or remove the higher parts. Sonic Pi has a powerful yet simple to use FX system that includes a low pass filter, called :lpf. Let’s play with it:

with_fx :lpf, cutoff: 100 do
  synth :saw, note: :e2, release: 4
end

If you listen carefully you’ll hear how some of that buzziness and crispiness has been removed. In fact, all the frequencies in the sound above note 100 have been reduced or removed and only the ones below are still present in the sound. Try changing that cutoff: point to lower notes, say 70 and then 50 and compare the sounds.

Of course, the :lpf isn’t the only filter you can use to manipulate the source signal. Another important FX is the high pass filter referred to as :hpf in Sonic Pi. This does the opposite to :lpf in that it lets the high parts of the sound through and cuts off the low parts.

with_fx :hpf, cutoff: 90 do
  synth :saw, note: :e2, release: 4
end

Notice how this sounds much more buzzy and raspy now that all the low frequency sounds have been removed. Play around with the cutoff value - notice how lower values let more of the original bass parts of the source signal through and higher values sound increasingly tinny and quiet.

Low Pass Filter

‘:prophet’

Filter Modulation

So far we’ve just produced fairly static sounds. In other words, the sound doesn’t change in any way for the entirety of its duration. Often you might want some movement in the sound to give the timbre some life. One way to achieve this is via filter modulation - changing the filter’s options through time. Luckily Sonic Pi gives you powerful tools to manipulate an FX’s opts through time. For example, you can set a slide time to each modulatable opt to specify how long it should take for the current value to linearly slide to the target value:

with_fx :lpf, cutoff: 50 do |fx|
  control fx, cutoff_slide: 3, cutoff: 130
  synth :prophet, note: :e2, sustain: 3.5
end

Let’s take a quick look at what’s going on here. Firstly we start an :lpf FX block as normal with an initial cutoff: of a very low 20. However, the first line also finishes with the strange |fx| at the end. This is an optional part of the with_fx syntax which allows you to directly name and control the running FX synth. Line 2 does exactly this and controls the FX to set the cutoff_slide: opt to 4 and the new target cutoff: to be 130. The FX will now start sliding the cutoff: opt’s value from 50 to 130 over a period of 3 beats. Finally we also trigger a source signal synth so we can hear the effect of the modulated low pass filter.

Bringing it all together

This is just a very basic taster of what’s possible when you use filters to modify and change a source sound. Try playing with Sonic Pi’s many built-in FX to see what crazy sounds you can design. If your sound feels too static, remember you can start modulating the options to create some movement.

Let’s finish by designing a function which will play a new sound created with subtractive synthesis. See if you can figure out what’s going on here - and for the advanced Sonic Pi readers out there - see if you can work out why I wrapped everything inside a call to at (please send answers to @samaaron on Twitter).

rrand

- Creative coding in the classroom with Sonic Pi

(This article was published in issue 9 of the Hello World Magazine)

Code is one of the most creative media that humans have created. The initially obscure symbols of parentheses and lambdas are not just deeply rooted in science and mathematics, they are the closest we have managed to get to casting the same kind of magical spells as Gandalf and Harry Potter. I believe that this provides a powerful means of engagement in our learning spaces. Through the magic of code we are able to conjure up individually meaningful stories and learning experiences.

We are surrounded by magical experiences. From the sleight of hand of a stage magician making the ball disappear into thin air, to the wonder of seeing your favourite band perform on a big stage. It is these “wow” moments that inspire us to pick up a magic book and learn the French Drop or to start jamming power chords on an old guitar. How might we create similarly deep and lasting senses of wonder that will motivate people to practice and learn the fundamentals of programming?

Musical Engines and Notation

The histories of music and computers have been intricately woven together since the inception of computing machines, or “engines” as Charles Babbage’s powerful analytical engine was called. Back in 1842 the Mathematician Ada Lovelace, who worked very closely with Babbage, saw the creative potential of these engines. Whilst these first engines had originally been designed to accurately solve hard maths problems, Ada dreamt about making music with them:

”..the engine might compose elaborate and scientific pieces of music of any degree of complexity or extent.” Ada Lovelace, 1842.

Of course, today in 2019 much of our music, regardless of genre, has either been composed, produced or mastered with a digital computer. Ada’s dream came true. It is even possible to trace the history back even further. If you see coding as the art of writing sequences of special symbols that instruct a computer to do specific things, then musical composition is a very similar practice. In Western music, the symbols are black dots positioned on a stave of lines that tell the musician which notes to play and when. Intriguingly, if we trace the roots of Western music notation back to the Italian Benedictine monk, Guido d’Arezzo, we find that the dots and lines system that modern orchestras use is just one of a number of notation systems he worked on. Some of the others were much closer to what we might now see as code.

In education, magical meaningful experiences with computers and programming languages have been explored since the late ’60s. Computer education pioneers Seymour Papert, Marvin Minsky and Cynthia Solomon explored simple Lisp-based languages that moved pens over large pieces of paper. With just a few simple commands it was possible to program the computer to draw any picture. They even experimented by extending their Logo language from drawing to music. Papert wrote about learning through experiencing the reconstruction of knowledge rather than its transmission. Getting people to play with things directly was an important part of his group’s work.

Sonic Pi Performances

Live Coding

Sonic Pi has been used to perform in a wide range of venues such as school halls, nightclubs, outdoor stages at musical festivals, college chapels and prestigious music venues. For example the amazing Convo project which brought 1000 children together in the Royal Albert Hall to perform an ambitious new composition by composer Charlotte Harding. The piece was written for traditional instruments, choirs, percussion and Sonic Pi code. The pop-artist Jylda also performed with Sonic Pi in the Sage Gateshead for the Thinking Digital Conference, where she created a unique live-coded improvised remix of her song Reeled.

Sonic Pi in the Royal Albert Hall Sonic Pi used as one of the instruments as part of Convo at the Royal Albert Hall. Photo credit: Pete Jones.

Live coding in the classroom

Sonic Pi is a code-based music creation and performance tool that builds on all of these ideas. Unlike the majority of computing education software, it is both simple enough to use for education and also powerful enough for professionals. It has been used to perform in international music festivals, used to compose in a range of styles from classical, EDM and heavy metal, and was even reviewed in the Rolling Stone magazine. It has a diverse community of over 1.5 million live coders with a variety of backgrounds all learning and sharing their ideas and thoughts through the medium of code. It is free to download for Mac, PC and Raspberry Pi and includes a friendly tutorial that assumes you know nothing about either code or music.

Sonic Pi was initially conceived as a response to the UK’s newly released Computing curriculum in 2014. The goal was to find a motivating and fun way to teach the fundamentals of programming. It turns out that there is a lot in common and it’s huge fun to explain sequencing as melody, iteration as rhythm, conditionals as musical variety. I developed the initial designs and first iterations of the platform with Carrie Anne Philbin, who brought a teacher’s perspective to the project. Since then, Sonic Pi has undergone iterative improvements thanks to the feedback gained from observing learners and collaborating directly with educators in the classroom. A core design philosophy was to never add a feature that couldn’t be easily taught to a 10 year old child. This meant that most ideas had to be heavily refined and reworked until they were simple enough. Making things simple whilst keeping them powerful continues to be the hardest part of the project.

In order to provide the magical motivation, Sonic Pi’s design was never limited to a pure focus on education. Ideally there would be famous musicians and performers using Sonic Pi as a standard instrument alongside guitars, drums, vocals, synths, violins, etc. These performers would then act as motivational role models demonstrating the creative potential of code. For this to be possible sufficient focus and effort therefore had to be placed on making it a powerful instrument whilst still keeping it simple enough for 10 year olds to pick up. In addition to educators, I also worked directly with a variety of different artists in classrooms, art galleries, studios and venues in the early stages of Sonic Pi’s development. This provided essential feedback which enabled Sonic Pi to grow and ultimately flourish as a tool for creative expression.

There were a number of exciting and unexpected side effects of this dual focus on education and professional musicians. Many of the features are beneficial to both groups. For example, a lot of effort has been put into making error messages more friendly and useful (rather than being a huge complicated mess of jargon). This turns out to be very useful when you write a bug while performing in front of thousands of people. Additionally, functionality such as playing studio quality audio samples, adding audio effects, providing access to live audio from the microphone all turn out to make the learning experience more fun, rewarding and ultimately meaningful.

The Sonic Pi community continues to grow and share amazing code compositions, lesson plans, musical algorithms, and much more. Much of this happens on our friendly forum in_thread (in-thread.sonic-pi.net) which is home to a very diverse group of people that includes educators, musicians, programmers, artists and makers. It is a real joy to see people learn to use code to express themselves in new ways and for that in turn to inspire others to do the same.

- Some fun capabilities

From a Computer Science perspective, Sonic Pi provides you with the building blocks to teach you the basics as found in the UK’s curriculum such as sequencing, iteration, conditionals, functions, data structures, algorithms, etc. However, it also builds on a number of important and relevant concepts which have become adopted in mainstream industry such as concurrency, events, pattern matching, distributed computing and determinism - all whilst keeping things simple enough to explain to a 10 year old child.

Getting started is as simple as:

play 70

A melody can be constructed with one more command, sleep:

play 72
sleep 0.5
play 75
sleep 0.5
play 79

In this example, we play the note 70 (roughly the 70th note on a piano), wait for 1 second, play note 72, wait for half a second and then play note 75. What’s interesting here is that with just two commands we have access to pretty much all of Western notation (which notes to play and when) and learners can code any melody they’ve ever heard. This leads to huge variety in expressive outcomes whilst focussing on the same computing concept: sequencing in this case.

Taking ideas from the professional music world, we can also play back any recorded sound. Sonic Pi can play any audio file on your computer but also has a number of sounds built-in to make things easy to get started:

sample :loop_amen

This code will play back the drum break which was a pillarstone to early hip-hop, Drum and Bass and Jungle. For example, a number of early hip-hop artists played this drum break back at half speed to give it a more laid-back feeling:

sample :loop_amen, rate: 0.5

In the 90s a number of music scenes burst out of new technology which enabled artists to take drum breaks like this apart and reassemble in a different order. For example:

sample :loop_amen

rand


- Conhecimento essencial

Esta secção descreve algum conhecimento útil - aliás essencial para retirares o máximo da tua experiência com o Sonic Pi.

Falaremos de como podes tiras partido de muitos atalhos de teclado disponíveis para ti, como partilhar o teu trabalho e algumas dicas sobre performance no Sonic Pi.


10.1 - Usando atalhos

O Sonic Pi é tanto um instrumento como um ambiente de codificação. Atalhos podem fazer com que tocar o Sonic Pi seja muito mais eficiente e natural - especialmente se estiveres a tocar em frente a uma audiência.

Muito do Sonic Pi pode ser controlado através do teclado. Quanto mais familiaridade tiveres trabalhando e actuando com o Sonic Pi mais tendência terás de usar atalhos. Eu pessoalmente uso o teclado (eu recomendo considerares aprenderes também) sinto-me frustrado quando tenho que alcançar o rato pois isso atrasa-me. Por isso uso todos estes atalhos de uma forma bastante regular!

Assim, se aprenderes os atalhos, aprenderás a usar o teclado de forma efectiva e estarás a fazer live coding como um profissional em tempo record.

No entanto, não tentes aprende-los todos de uma só vez, apenas tenta lembrar-te dos que mais usas e continua a adicionar mais à medida que os praticas.

Consistência entre plataformas

Imagina que estas a aprender o clarinete. Esperas que todos os clarinetes tenham os mesmos controles e botões. Se não tiverem, terás um tempo difícil a mudar entre vários clarinetes ou ficaras retido em usar só um.

Infelizmente a maioria dos sistemas operativos (Linux, Mac OS X e Windows) vêm com os seus próprios padrões para acções como o copy e paste etc. Sonic Pi tenta honrar estes padrões. no entanto a prioridade é colocada na consistência entre plataformas dentro do Sonic Pi em vez de tentar adaptar-se aos padrões de uma determinada plataforma. Isto significa que quando aprenderes os atalhos enquanto tocas com o Sonic Pi no teu Raspberry Pi, podes mudar para um Mac ou um PC e sentires-te em casa.

Control e Meta

Parte da noção de consistência é o nome dos atalhos. No Sonic Pi usamos o nome Control e Meta para referir as 2 principais teclas de combinações. Em todas as plataformas o Control é o mesmo. No entanto, no Linux e no Windows Meta é a tecla Alt enquanto que no Mac Meta é a tecla Command. Para consistência usaremos o termo Meta - Lembra-te apenas de mapear para a tecla apropriada no teu sistema operativo.

Abreviações

Para ajudar a manter as coisas simples e legíveis, usaremos as abreviaturas C- para Control mais uma outra tecla e M- para Meta mais outra tecla. Por exemplo, se um atalho requer que primas simultaneamente Meta e r escreveremos como M-r. O - significa apenas “ao mesmo tempo”.

Os seguintes são alguns dos atalhos que considero mais úteis.

Parando e iniciando

Em vez de alcançar o rato cada vez que se quer correr o código, podes simplesmente pressionar M-r. Da mesma forma podes parar o código carregando M-s.

Fico mesmo perdido sem os atalhos de navegação. Recomendo vivamente que passes algum tempo a aprende-los. Estes atalhos trabalhas extremamente bem quando aprendes a teclar sem mexer as mãos pois eles usam letras standard e não requerem que mexas as mãos para alcançar o rato ou as setas do teu teclado.

Podes mover para o inicio da linha com C-a, para o final da linha com C-e, subir uma linha com C-p, para baixo uma linha com C-n, um carácter para a frente com C-f, e um carácter para trás com C-b. Podes até apagar todos os caracteres do cursor até ao final da linha com C-k.

Código limpo

Para auto-alinhar o teu código simplesmente carrega M-m.

Sistema de ajuda

Para comutar o sistema de ajuda podes premir M-i- No entanto, um atalho muito mais útil é C-i em que irá verificar a palavra por baixo do cursor e mostra os documentos se descobrir algo. Ajuda instantânea!

Para uma listagem completa vê a secção 10.2 com uma folha de ajuda de atalhos.


10.2 - Folha de ajuda de atalhos

O seguinte é um sumário dos principais atalhos disponíveis no Sonic Pi. Por favor vê a secção 10.1 para motivação e contexto.

Convenções

Nesta lista, usamos a seguinte convenção (onde Meta ou é o Alt em Windows/Linux ou o Cmd no Mac):

C-a significa carregar na tecla Control e depois carrega a tecla a estando as duas pressionadas ao mesmo tempo, depois libertando. M-r significa pressionar a tecla Meta e depois pressionar a tecla r ao mesmo tempo, depois libertando. S-M-z significa presionar a tecla Shift, depois a tecla Meta, e finalmente a tecla z todas ao mesmo tempo, depois libertando. C-M-f significa premir a tecla Control, e depois premir a tecla Meta, finalmente a tecla f todas ao mesmo tempo, depois libertando.

Manipulação da Aplicação principal

M-r - Correr código M-s - Parar código M-i- Comutar o sistema de ajuda M-p- Comutar preferencias M-{ - Mudar para a buffer da esquerda M-} - Mudar para a buffer da direita M-+ - Aumentar tamanho do texto da buffer corrente M-- - Reduzir o tamanho de texto na corrente buffer

Selecionar/copiar/colar

M-a - Selecionar tudo M-c- Copiar selecção para colar na buffer M-] - Copiar seleção para colar no buffer M-x - Cortar seleção para colar na buffer C-] - Cortar seleção para a colar na buffer C-k- Cortar até ao fim da linha M-v- Colar para o editor C-y - Colar para o editor C-SPACE - Colocar marca. A navegação irá agora manipular a região sublinhada. Usar C-gpara escapar.

Manipulação de texto

M-m - Alinhar todo o texto Tab- Alinha a corrente linha ou seleção (ou escolhe autocompletion) C-l - Centra o editor M-/ - Comuta os comentários da linha actual ou seleção C-t - Transpõe/troca caracteres M-u- Converte a próxima palavra (ou selecção) para maiúsculas. M-l - Converte a próxima palavra (ou selecção) para minúsculas.

C-a - Mover para o inicio da linha C-e - Mover para o final da linha C-p - Mover para a linha anterior C-n - Mover para a próxima linha C-f - Mover para a frente um caractere C-b - Mover para trás um caractere M-f - Mover para a frente uma palavra M-b- Mover para trás uma palavra C-M-n - Mover uma linha ou selecção para baixo C-M-p - Mover linha ou selecção para cima S-M-u - Mover para cima 10 linhas S-M-d- Mover para baixo 10 linhas M-< - Mover para o inicio da buffer M-> - Mover para o final da buffer

Remoção

C-h - Remove o caractere anterior C-d - Remove o proximo caractere

Características avançadas do editor

C-i - Mostra documentação sobre a palavra por baixo do cursor M-z - Undo S-M-z - Refazer C-g - Escapar S-M-f - comutar ecrã total S-M-b - Comutar visibilidade dos botões S-M-l - Comuta visibilidade do registo S-M-m - Comuta entre o modo claro/escuro S-M-s- Salva o conteúdo de uma buffer para um ficheiro S-M-o - Carrega o conteúdo de uma buffer para um ficheiro


10.3 - Partilha

No Sonic Pi é tudo sobre partilha e aprendendo uns com os outros.

Depois de aprenderes a codificar musica, partilhar as tuas composições é tão simples como mandar um email contendo o teu código. Por favor partilha o teu código com outro para que eles possam aprender com o teu trabalho ou mesmo usar num novomash-up.

Se estás inseguro da melhor maneira de partilhar o teu trabalho com outros eu recomendo colocar o código no [GitHub] (https://github.com) e a tua música no SoundCloud. Dessa forma poderás facilmente chegar a uma grande audiência.

Código -> GitHub

GitHub é um site para trabalhar e partilhar código. É usado por criadores bem como artistas para partilhar e colaborar no código. A maneira mais simples de partilhar uma nova peça de código (ou mesmo uma peça inacabada) é criar um Gist. Um Gist é uma maneira simples de enviar o teu código numa maneira simples para os outros o verem, copiarem e partilharem.

Audio -> SoundCloud

Uma outra maneira importante de partilhares o teu trabalho é gravares o audio e o enviares para o SoundCloud. Depois de enviares a tua peça, outro utilizadores podem comentar e discutir o teu trabalho. Eu recomendo também colocares uma ligação para o Gist do teu código na descrição da faixa.

Para gravares o teu trabalho, clica no botão Rec na barra de ferramentas e a gravação começa imediatamente. Clica Run para começar a correr o teu código se não estiver já a correr. Quando estiver pronta a gravação, clica no botão Rec a piscar a vermelho outra vez, e será pedido para dar o nome ao ficheiro. A gravação será salva como ficheiro WAV, que pode ser editado e convertido para MP3 por diversos programas grátis (experimenta o Audacity por exemplo).

Esperança

Eu encorajo-te a partilhares o teu trabalho e tenho esperança que todos aprendamos uns com os outros truques novos para o Sonic Pi. Estou mesmo excitado com o que tens para me mostrar.


10.4 - Performance

Um dos aspectos mais excitantes no Sonic Pi é que permite usares código como um instrumento musical. Isto significa que escrever código ao vivo pode agora ser visto como uma performance musical.

Chamamos a isso Live Coding.

Mostra o teu ecrã

Quando codificas ao vivo eu recomendo mostrares o teu ecrã. De outro modo é como tocar guitarra mas esconderes os teus dedos e as cordas. Quando pratico em casa eu uso o Raspberry Pi e um pequeno projector na minha sala de estar. Poderás usar uma Tv ou um projector para dares um espectáculo. Experimenta, é muito divertido.

Forma uma banda

Don’t just play on your own - form a live coding band! It’s a lot of fun jamming with others. One person could do beats, another ambient background, etc. Use the live_audio functionality to combine code with traditional instruments such as a guitar or a microphone.

See what interesting combinations of sounds you can create with code.

TOPLAP

Live coding não é uma coisa completamente nova . Um pequeno número de pessoas têm estado a fazer durante alguns anos, tipicamente usando sistemas que eles proprios criaram. Um excelente sitio para descobrir mais sobre live coders e sistemas é TOPLAP.

Algorave

Outro grande recurso para explorar o mundo do live coding é Algorave. Onde podes descobrir tudo sobre um tipo especifico de live coding para a criação de musica em clubes nocturnos.


- Minecraft Pi

O Sonic Pi suporta agora um simples API para interagir com o Minecraft Pi - uma edição especial do Minecraft que vem instalada por default no sistema operativo baseado no Raspian Linux instalado no Raspberry Pi.

Não é necessário importar bibliotecas

A integração do Minecraft Pi foi desenhada para ser extremamente fácil de usar. Tudo o que necessitas é correr o minecraft Pi e criar um mundo. Então podes usar a função mc_* tal como poderias usar o play e synth. Não é necessário importar nada ou instalar bibliotecas - está pronto a ser usado e funciona “out of the box”.

Conexão automática

O API do Minecraft Pi trata de gerir a conexão à aplicação do Minecaft Pi. Isso significa que não precisas de te preocupar com nada. Se tentares usar o API do Minecraft Pi quando o Minecraft Pi ainda não está a correr, o Sonic Pi educadamente vai-te avisar. Similarmente, se fechares o Minecraft Pi enquanto ainda estiveres a correr um live_loop que usa o API, o live loop irá parar e dirá que não se consegue conectar. Para reconectar basta correres o Minecraft Pi outra vez e o Sonic Pi irá detectar e recriar a conexão por ti.

Desenhado para ser codificado ao vivo

O API do Minecraft Pi foi desenhado para trabalhar sem falhas dentro dos live_loops. Isto significa que é possível sincronizar modificações nos teus mundos do Minecraft Pi com modificações nos teus sons do Sonic Pi. Videos musicais baseados no Minecraft instantâneos! Nota no entanto que o Minecraft Pi é um software alpha e pode ter bugs. Se encontrares alguns problemas, simplesmente reinicia o Minecraft Pi e continua como anteriormente. A conexão automática do Sonic Pi encarrega-se do resto.

Requer o Raspberry Pi 2.0

É altamente recomendado que uses o Raspberry Pi 2 se quiseres correr ao mesmo tempo o Sonic Pi e o Minecraft - especialmente se quiseres utilizar as capacidades sonoras do Sonic Pi.

Suporte de API

Nesta fase, o Sonic Pi suporta blocos básicos e manipulação pelo jogador que são detalhadas na secção 11.1. Suporte para chamada de eventos despoletadas pelo jogador no mundo está planeado para futuras edições.


11.1 - API básico do Minecraft Pi

O Sonic Pi suporta as seguintes iterações básicas com o Minecraft Pi:

Visualizar mensagens de chat Definir a posição do jogador Receber a posição do jogador Colocar um determinado tipo de bloco numa determinada coordenada Verificar o tipo de bloco de determinada coordenada

Vamos ver cada uma delas à vez.

Visualizar mensagens de chat

Vamos ver como é fácil controlar o Minecraft Pi a partir do Sonic Pi. Primeiro, verifica que temos o Minecraft Pi e o Sonic Pi abertos ao mesmo tempo e que entramos no mundo do Minecraft e nos podemos deslocar.

Numa nova buffer do Sonic Pi coloca o seguinte código:

mc_message "Hello from Sonic Pi"

Quando pressionamos o botão Run, verás uma mensagem a piscar na janela do Minecraft. Parabéns, escreveste o teu primeiro código no Minecraft! Isto foi fácil não foi.

Definir a posição do jogador

Agora vamos experimentar uma pequena magia. Vamos teleportar para outro sitio! Experimenta o seguinte:

mc_teleport 50, 50, 50

Quando carregares no Run - Boom! És instantaneamente teleportado para um novo sitio. Mais provável algures no céu e caíste em terra seca ou para a água. Agora, o que são estes números: 50, 50, 50? Eles são as coordenadas da localização que estás a tentar teleportar. Vamos tomar algum tempo para explorar que coordenadas são e como funcionam porque elas são realmente importante para programares o Minecraft.

Coordenadas

Imagina um mapa de um pirata com um X grande marcando o local de algum tesouro. A localização exacta do X pode ser descrita com dois números - quando ao longo do mapa da esquerda para a direita e quanto ao longo do mapa do fundo para o topo. Por exemplo 10 cm ao longo e 8 cm para cima. Estes dois números 10 e 8 são coordenadas. Podes imaginar facilmente descreveres a localização de outros tesouros com outros pares de números. Talvez exista um grande baú de ouro em 2 ao longo e 9 para cima…

Agora, no Minecraft dois números não são suficientes. Necessitamos também saber a altura que estamos. Assim necessitamos 3 números:

Quanto ao longo da direita para a esquerda estamos no mundo - x Quando ao longo da frente para trás estamos no mundo - z Quando alto estamos no mundo - y

Uma coisa a mais - tipicamente descrevemos estas coordenadas nesta ordem x,y,z.

Descobrindo as coordenadas actuais

Vamos brincar com estas coordenadas. Navega para um sitio agradável no mapa do Minecraft e depois muda para o Sonic Pi. Agora escreve o seguinte:

puts mc_location

Quando carregares no botão Run verás que as coordenadas da tua posição actual apresentadas na janela de log. Toma nota delas, depois move-te para a frente no mundo e tenta outra vez. Repara como as coordenadas mudaram! Agora, recomendo que passes algum tempo a repetir isto - move-te um pouco pelo mundo, verifica as coordenadas e repete. Faz isso até perceberes como as coordenadas mudam enquanto te moves. Uma vez que percebas isso, programar com o API do Minecraft será muito fácil.

Vamos construir!

Agora que sabemos encontrar a posição actual e teleportar usando coordenadas, terás todas as ferramentas para começar a construir coisas com código Minecraft. Digamos que queres criar um bloco de vidro com coordenadas 40, 50, 60`. É muito fácil:

mc_set_block :glass, 40, 50, 60

Haha, foi muito fácil. Para ver o resultado teleporta-te para uma zona perto e dá uma olhada:

mc_teleport 35, 50, 60

Agora volta-te e verás o teu bloco de vidro! Tenta muda-lo para um diamante:

mc_set_block :diamond, 40, 50, 60

Se tiveres voltado para o lado correcto poderás ter visto a mudança a frente dos teus olhos! Isto é o principio de algo excitante…

Observando os blocos

Vamos ver uma ultima coisa antes de seguirmos para algo mais evoluido. Dado um conjunto de coordenadas podemos perguntar ao Minecraft que tipo especifico de bloco é. Vamos experimentar com o bloco de diamante que acabamos de criar:

puts mc_get_block 40, 50, 60

Yey! É um :diamond. Tenta mudar do movo para vidro e perguntar outra vez - agora diz :glass? Tenho a certeza que sim :-)

Tipo de blocos disponíveis

Antes de ires num diluvio de código no Minecraft Pi, poderás achas a seguinte lista de tipo de blocos disponíveis útil:

    :air
    :stone
    :grass
    :dirt
    :cobblestone
    :wood_plank
    :sapling
    :bedrock
    :water_flowing
    :water
    :water_stationary
    :lava_flowing
    :lava
    :lava_stationary
    :sand
    :gravel
    :gold_ore
    :iron_ore
    :coal_ore
    :wood
    :leaves
    :glass
    :lapis
    :lapis_lazuli_block
    :sandstone
    :bed
    :cobweb
    :grass_tall
    :flower_yellow
    :flower_cyan
    :mushroom_brown
    :mushroom_red
    :gold_block
    :gold
    :iron_block
    :iron
    :stone_slab_double
    :stone_slab
    :brick
    :brick_block
    :tnt
    :bookshelf
    :moss_stone
    :obsidian
    :torch
    :fire
    :stairs_wood
    :chest
    :diamond_ore
    :diamond_block
    :diamond
    :crafting_table
    :farmland
    :furnace_inactive
    :furnace_active
    :door_wood
    :ladder
    :stairs_cobblestone
    :door_iron
    :redstone_ore
    :snow
    :ice
    :snow_block
    :cactus
    :clay
    :sugar_cane
    :fence
    :glowstone_block
    :bedrock_invisible
    :stone_brick
    :glass_pane
    :melon
    :fence_gate
    :glowing_obsidian
    :nether_reactor_core