Ruby como ferramenta de composição: Sonic Pi
(bhmt.dev)- Sonic Pi é apresentado como um ambiente para criar música mesmo sem instrumentos ou equipamentos, permitindo escrever diretamente notas, acordes, escalas e timing com uma DSL baseada em Ruby
- Ao aproveitar funções, arrays, condicionais, loops e escopo do Ruby, é possível combinar
play,sleep,play_pattern_timed,chordescalepara construir padrões repetitivos e arpejos de forma concisa - Combinando
in_thread,ring,flatten, o operador splat ewith_fx, é possível executar vários “instrumentos” ao mesmo tempo e aplicar camadas de notas sobrepostas e ritmos diferentes - O ajuste de
attack,decay,sustainereleasedo envelope ADSR se concentra menos em reproduzir um coral real e mais em acertar tempo de sustentação e separação live_looppermite atualizar e repetir o código durante a reprodução, transformando o Sonic Pi em uma ferramenta para performance ao vivo e levando a ver o código como texto legível e ato criativo
Sonic Pi controlado por código
- Sonic Pi, diferentemente de aplicações de áudio convencionais, é um sintetizador de software controlado apenas por código
- Sua linguagem de controle própria é uma linguagem específica de domínio (DSL) que estende Ruby e mapeia conceitos de música e áudio sobre a sintaxe de Ruby
- Os elementos básicos são compostos por valores Ruby e funções do Sonic Pi
- Nomes de notas como
:c4são usados como símbolos correspondentes ao respectivo código MIDI - É possível criar acordes recebendo como argumentos a nota raiz e a estrutura do acorde, como em
chord(:d3, :maj7) playtoca uma nota, e, junto comsleepdo Ruby, controla intervalos de tempoplay_pattern_timedrecebe uma lista de notas e intervalos de tempo, reduzindo o código de reprodução repetida
- Nomes de notas como
- O objetivo do exemplo é criar por código um acompanhamento de demonstração usando apenas os recursos básicos do Sonic Pi, sem MIDI externo nem samples
- Ao instalar o app Sonic Pi, é possível colar o código de exemplo e acompanhar; a documentação da linguagem e tutoriais também vêm incluídos
Criando padrões repetitivos com sintaxe Ruby
- O exemplo básico altera o BPM com
use_bpm 70e usa o sintetizador pulse comuse_synth :pulse, em vez da onda senoidal padrão - Repetindo
play :c2esleep 0.25, é possível tocar notas em sequência; complay_pattern_timed [ :c3, :d3, :e3, :g3 ], 0.25, a mesma estrutura pode ser escrita de forma mais curta - Como a linguagem de controle está sobre Ruby, é possível abstrair padrões com funções e loops
- A função
arpeggiaterecebe uma nota raiz e a informação opcional de modo menor, criando um padrão ascendente e descendente - O loop
4.timesexecuta o mesmo padrão ao longo de várias oitavas - Uma condicional altera a terça quando o modo é menor, e o
mapdo array soma intervalos à nota raiz para gerar a lista de notas
- A função
- É possível configurar primeiro as opções padrão do sintetizador, como em
use_synth_defaults amp: 0.1, ou passar opções diretamente paraplayouplay_pattern_timed - Em Ruby, os parênteses em chamadas de função são opcionais, mas em casos como
play chord(:a3, maj7)pode ser necessário deixar a separação clara
Execução paralela e camadas
- O bloco
in_thread doé usado no Sonic Pi para executar código em paralelo - Com blocos
in_threaddiferentes, é possível executar dois “instrumentos” separados ao mesmo tempo- Uma thread pode ficar responsável pelo padrão de arpejo
- Outra thread pode tocar uma melodia separada usando
use_synth :saw, um array de melodia e um array de ritmo
play_pattern_timedpode receber não só uma lista de notas, mas também uma lista de intervalos de tempo[1] * 2aumenta o tamanho do array repetindo seu conteúdo, como em[1, 1]- Como
play_pattern_timednão aceita arrays aninhados diretamente, usa-seflattenpara transformá-los em um array de uma só camada
- Para criar notas sobrepostas, como em um coral, é possível agrupar várias notas com
ring(:c5, :e5) flattenpode acabar juntando também a lista interna doring; nesse caso, usa-se o operador splat*para expandir o conteúdo da lista dentro do array pai
Escopo, efeitos e composição de partes de coral
- Com
in_threadaninhados, é possível compartilhar fragmentos rítmicos do escopo externo e, ao mesmo tempo, reutilizar o mesmo nome de variável em cada thread interna - Ao separar partes como soprano e contralto em threads diferentes, cada bloco tem seu próprio escopo e não acessa diretamente as variáveis dos outros
with_fx :reverb, mix: 0.2cria um bloco de efeito, e o fluxo do sinal começa na camada mais interna e segue para a cadeia de efeitos externamixindica o grau de mistura entre o sinal wet e o sinal dry- O sinal wet é o sinal com efeito aplicado
- O sinal dry é o sinal sem efeito
- Envolver todo o grupo em um único efeito pode ser usado de forma parecida com um bus em uma DAW, mas roteamentos mais profundos são manuais e, por causa do escopo, em geral precisam ser organizados de cima para baixo
- É mais natural tratar o Sonic Pi como um instrumento, em vez de uma ferramenta sofisticada de produção
Ajustando a duração das notas com envelope ADSR
play_pattern_timedadiciona o valor desustain, permitindo ajustar diretamente o tempo de sustentação de acordes longos e curtosattack,decay,sustainereleaseformam o envelope ADSR, que representa como o volume muda ao longo do tempoattacké o tempo para ir de 0 até o primeiro pico, correspondendo ao ataque inicial, como o momento em que uma corda de violão é pinçada ou o martelo de um piano toca a cordadecayé o tempo de queda a partir do primeiro pico, correspondendo ao trecho em que o som diminui gradualmente mesmo mantendo uma tecla de piano ou uma corda de violão pressionadasustainé o tempo em que o som se mantém em um volume estável, como em uma corda tocada com arco ou em um vocal sustentadoreleaseé o tempo desde soltar o som até ele efetivamente ficar silencioso
- Nem todos os sons têm todos os elementos de ADSR
- Tons de sintetizador são sons gerados, portanto não necessariamente têm build-up inicial ou reverberação
- Em instrumentos naturais, a proporção dos elementos varia conforme a forma de tocar
- A simulação de coral do exemplo se concentra menos em realismo e mais em fazer com que as notas sejam sustentadas pelo tempo correto e haja um pouco de separação entre os acordes
- A função
choral_rings notes, susrecebe uma lista de notas e o tempo de sustentação, toca-as juntas comring(*notes), calculasustainereleasee então espera até o próximo evento comsleep sus
Live coding com live_loop
- Com
live_loop, é possível executar código repetidamente por tempo indeterminado - O Sonic Pi é uma ferramenta bastante voltada a performance ao vivo, e o código dentro de
live_looproda até o programa ser interrompido - Mesmo durante a reprodução, é possível alterar o conteúdo do loop; ao executar novamente o comando de início, o loop atualizado passa a valer a partir da próxima repetição
- Os loops externos existentes com
in_threadpodem ser transformados no formatolive_loop :some_unique_name - Como a cadeia de efeitos é recriada a cada volta do loop, quanto mais efeitos forem empilhados, mais barato em termos de recursos é colocá-los fora de
live_loop - O exemplo final é composto por
live_loop :harpelive_loop :choir- O loop
:harpusa o sintetizador:squaree um padrão de arpejo de duração 0.25 - O loop
:choirtoca acordes de coral usando o sintetizador:saw,sleep 64,with_fx :reverb, mix: 0.75e chamadas à funçãochoral_rings
- O loop
Ver programação como ato criativo
- O trabalho técnico costuma ser discutido pela perspectiva da ciência da computação, mas programação também pode ser arte
- Ela não é artística apenas quando cria resultados intencionalmente criativos, como geração de áudio ou layouts em CSS
- Código não é só um conjunto de instruções otimizadas para a máquina, mas também texto organizado lido por outras pessoas e pelo seu eu do futuro
- Bom código é aquele escrito para que outra pessoa, ou você mesmo daqui a seis meses, consiga entendê-lo de imediato
- Às vezes, a qualidade artística do código se torna um fim em si mesma, e o exemplo do Sonic Pi mostra esse ponto por meio da criação musical
1 comentários
Opiniões no Hacker News
Se você tem interesse em live coding, Glicol(https://glicol.org) também vale a pena experimentar
Também existe o TidalCycles, e a capacidade de Haskell e Ruby de criar DSLs é realmente digna de elogios
O Glicol se concentra em uma sintaxe inspirada em sintetizadores, velocidade de composição e conveniência no design de som. A ideia é trazer hábitos de programação existentes, mas projetar uma DSL que não fique presa a uma linguagem específica
https://github.com/tidalcycles/strudel
Alguns anos atrás, vi no YouTube um vídeo de alguém recriando o THX Deep Note com Sonic Pi
No começo, a pessoa não explicava o que ia criar; fazia um único “tom” de som e o chamava de abelha. Depois de ajustar e tocar esse som de abelha aos poucos, no fim ela seguia algo como “vamos criar algumas centenas dessas abelhas e ver como soa dentro de uma colmeia”, e naquele momento o Deep Note surgia
Eu gostei muito daquele vídeo, mas nunca mais consegui encontrá-lo. Se alguém souber o link, seria ótimo se compartilhasse
Acho que este é um dos casos em que Ruby brilha. Graças à metaprogramação, dá para fazer a sintaxe parecer quase inglês
Alguns anos atrás, vi Sam Aaron, ou seja, o criador do Sonic Pi, fazendo uma apresentação ao vivo com Sonic Pi
A música continuava evoluindo cada vez que o código mudava em tempo real, e era realmente boa
Se você quiser exemplos de artistas que usam Sonic Pi, conheci a DJ_Dave há algum tempo, e acho que ela é um ótimo exemplo de uma musicista talentosa e experiente usando bem essa ferramenta
Ela também fez um AMA no Reddit há um tempo, e parece ter trabalhos no GitHub
[1] https://www.youtube.com/watch?v=JiQHclg_648
[2] https://www.reddit.com/r/audius/comments/19dxmy6/hey_audius_...
[3] https://github.com/algorave-dave
Como desenvolvedor Ruby, isso parece muito legal. Acho que seria divertido usar para música generativa algorítmica, e eu queria transformar eventos barulhentos de um repositório git em algum tipo de música algorítmica; isso parece se encaixar bem
Mas, do ponto de vista de um músico com vários instrumentos de teclado, se for para compor uma música, basta tocar em um teclado MIDI ou gravar um instrumento acústico e criar loops; não vejo muito motivo para programar sequências musicais em Ruby. Entendo que dá para digitar o que se quer com uma DSL em Ruby, mas é difícil dizer que a experiência de usuário seja melhor do que a de um teclado de piano
Em outras palavras, acho que eu não usaria isso para substituir o Logic. Claro, é uma preferência pessoal
Referência: http://listen.hatnote.com/
Na prática, às vezes pensamos algo como “agora um arpejo em dó menor, agora um arpejo em fá maior”, e é bom poder compor essa intenção de forma bem explícita com funções
O ponto central parece estar em gerar por algoritmo, em vez de tocar nota por nota
Ainda assim, usar de forma interessante uma ferramenta que você normalmente não usaria, por causa de restrições incomuns, combina bastante com os interesses do Hacker News
Tenho um teclado de que gosto e, em teoria, poderia usá-lo para esse trabalho, mas pessoalmente, por circunstâncias complicadas, todos os meus instrumentos estão guardados em um depósito há algum tempo
Coincidentemente, há alguns dias eu estava pensando no Sonic Pi e vi alguns vídeos online
Eu só tinha mexido nele um pouco alguns anos atrás, e naquela época tentei tocar músicas clássicas como Old MacDonald e Hot Cross Buns
Se você tiver curiosidade sobre outra abordagem para programação musical, embora não seja ao vivo, vale a pena ver o scamp[0] para Python
O criador postou no YouTube muitos vídeos do que fez com ele; um exemplo é o vídeo Fourier Elise[1]
[0] http://scamp.marcevanstein.com/
[1] https://www.youtube.com/watch?v=zq32bIud3OM
Parece que os comentários HTML não estão sendo aplicados. O editor deve ter trocado dois hífens
--por um único travessão—Também recomendo minha live coder favorita de Sonic Pi, alsoknownasrox
https://www.youtube.com/watch?v=wXIvXrBQFkE