{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", " \n", " \n", " \n", " \n", "
\n", "\n", "
\n", " \n", "\n", "
\n", "

Introducció a Sonic Pi

\n", "

Festa OpenSource Girona - 23 Octubre 2021

\n", "

@victormartin

\n", "

\n", "
\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "\n", "# Què és Sonic Pi?\n", "\n", "\n", "\n", "\n", "\n", "* Instrument musical electrònic (sintetitzador) _open source_ que es programa en directe\n", "\n", "Creat al laboratori de computació de la Universitat de Cambridge" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Què es pot fer amb Sonic Pi? 😮😮😮😮" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "live_loop :low do |idx|\n", " # idx = 0\n", " synth :zawa, wave: 1, invert_wave: 1, phase: 0.25, release: 5, note: :e1, cutoff: (range 60, 120, 10)[idx]\n", " sleep 4\n", " idx += 1\n", "end\n", "\n", "live_loop :lands, auto_cue: false do |idx|\n", " use_synth :dsaw\n", " use_random_seed 66679\n", " with_fx :reverb, room: 1 do\n", " 16.times do\n", " ns = (scale :e2, :minor_pentatonic, num_octaves: 3)\n", " play ns.choose, detune: 12, release: 0.1, amp: 2, amp: rand + 0.5, cutoff: rrand(70, 120)\n", " sleep 0.125\n", " end\n", " end\n", "end\n", "\n", "live_loop :bikes do |idx|\n", " sleep 0.25\n", " sample :guit_em9, rate: -1\n", " sleep 7.75\n", "end\n", "\n", "live_loop :time, auto_cue: false do |idx|\n", " sample :bd_haus, amp: 2.5\n", " sleep 0.5\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Missió de Sonic Pi\n", "\n", "Dissenyat sota els principis:\n", "\n", "* __Fácil__ per a que un nen de 10 anys el pugui utilitzar\n", "* __Divertit__ per a que fins i tot puguis perdre la noció del temps mentre jugues amb ell\n", "* __Potent__ per a que puguis expressar-te artísticament a través d'ell" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Va començar com un experiment per _ensenyar conceptes de programació_ a les escoles, tot jugant amb el procés de crear _nous sons_\n", "\n", "Ha evolucionat en un potent _instrument musical programat_, utilitzat per artistes professionals i DJs" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Curset ràpid de Sonic Pi\n", "\n", "L'aprenentatge de Sonic Pi es basa amb la exploració. No hi ha errors, només descubriments. I per sobre de tot, es tracta de divertir-se.\n", "\n", "Recorda això: **Passa-t'ho bé, explora i hackeja!** 😋😋\n", "\n", "Xerrada basada en http://sonic-pi.mehackit.org - *Creative programming workshop with Sonic Pi*" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# L'aplicació - Entorn de desenvolupament\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Fer sonar una nota" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "play 60" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "Provem diferents valors. Com canvia el so?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Notes Midi\n", "\n", "Sonic Pi entén:\n", "1. notes MIDI (valors de *0* a *127*) \n", "2. notació musical tradicional (*:C4*, *:Eb3*, *:G5*...)\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Tocar una melodía\n", "\n", "Escriu aquest codi al buffer i pulsa **Run** (Ctrl+R):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "play :C4\n", "play 67\n", "play 69" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Efectivament, Sonic Pi ha tocat les 3 notes a la vegada. Això no es una melodía, es un acord!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Si volem que Sonic Pi reprodueixi les notes sequencialment, li hem de dir que descansi de tant en tant. Prova amb la comanda **sleep**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "play :C4\n", "sleep 1\n", "play 67\n", "sleep 1\n", "play 69" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Silencis\n", "\n", "La comanda *sleep 1* li diu a Sonic Pi que esperi un \"beat\" (en català *polsació*)\n", "\n", "En cas que estiguis familiaritzat amb la notació musical, així es com les diferents notes es representen a Sonic Pi:\n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Ara sí, toquem la melodía!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "use_bpm 40\n", "\n", "play 72\n", "sleep 0.25\n", "play 76\n", "sleep 0.25\n", "play 76\n", "sleep 0.25\n", "play 72\n", "sleep 0.5\n", "play 83\n", "sleep 0.25\n", "play 74\n", "sleep 0.25\n", "play 83\n", "sleep 0.25\n", "play 79\n", "play 84" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Repetint melodíes\n", "\n", "Per sort, hi ha una forma fàcil de repetir melodíes (o parts de la mateixa) i evitar-nos el *copy&paste* 😅😅" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "2.times do\n", " play :c4\n", " sleep 0.5\n", " play :d4\n", " sleep 0.5\n", " play :e4\n", " sleep 0.5\n", " play :c4\n", " sleep 0.5\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "També podem fer servir repeticions dins de repeticions:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "4.times do\n", " 4.times do\n", " play :c4\n", " sleep 0.25\n", " end\n", " play :d4\n", " sleep 0.5\n", " play :f4\n", " sleep 0.5\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Creem una cançó! 🎼🕺🎶🎶\n", "\n", "Composem la nostra propia cançó en 3 passes:\n", "\n", "* **Drum beat**\n", "* **Bass track**\n", "* **Lead track**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Drum beat\n", "\n", "Anem a crear un ritme de batería simple, format per bombo (*kick*), caixa (*snare*) i charles (*hi-hat*). \n", "Necessitem dues coses noves **live_loop** i **sample**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "live_loop :drums do\n", " sample :drum_heavy_kick\n", " sleep 1\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **live_loop** es un bucle sense fi, que pot ser sincronitzat amb altres *live_loops*. Com a mínim ha de tenir un *sleep*\n", "* **:drums** es l'identificador (o el nom) del bucle. Pots anomenar-lo com vulguis, només serveix per identificar-ho de forma fàcil\n", "* **sample** li diu a Sonic Pi que reprodueixi un sample (fitxer d'àudio)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Ritme backbeat simple\n", "\n", "El bucle comença amb un *kick*, *caixa* en el segon temps, *kick* en el tercer, *caixa* en el quart i torna a començar" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "use_bpm 100\n", "\n", "live_loop :drums do\n", " sample :drum_heavy_kick\n", " sleep 1\n", " sample :drum_snare_hard\n", " sleep 1\n", " sample :drum_heavy_kick\n", " sleep 1\n", " sample :drum_snare_hard\n", " sleep 1\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Afegim hi-hat " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "use_bpm 100\n", "\n", "live_loop :drums do\n", " sample :drum_heavy_kick\n", " sleep 1\n", " sample :drum_snare_hard\n", " sleep 1\n", " sample :drum_heavy_kick\n", " sleep 1\n", " sample :drum_snare_hard\n", " sleep 1\n", "end\n", "\n", "live_loop :hats do\n", " sample :drum_cymbal_closed\n", " sleep 0.5\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Bonus! dembow rhythm (Reggaeton) \n", "# ☢️☠️ 💃🕺👯💃 ☠️☢️" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "use_bpm 95\n", "\n", "live_loop :kick do\n", " sample :bd_haus\n", " sleep 1\n", "end\n", "\n", "live_loop :snare do\n", " sleep 0.75\n", " sample :drum_snare_hard\n", " sleep 0.75\n", " sample :drum_snare_hard\n", " sleep 0.5\n", "end\n", "\n", "live_loop :hats do\n", " sample :drum_cymbal_closed\n", " sleep 0.5\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Bass track\n", "\n", "Afegim un altre *live_loop* per els nostres baixos. Composarem un groove de baix simple però sòlid. \n", "\n", "Pots fer servir aquest [piano dins el browser](http://sonic-pi.mehackit.org/exercises/en/09-keys-chords-and-scales/01-piano.html) per ajudar-te a escollir les notes:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "use_bpm 95\n", "\n", "live_loop :bass do\n", " play :c2\n", " sleep 0.25\n", " play :c2\n", " sleep 2\n", " play :e2\n", " sleep 0.75\n", " play :f2\n", " sleep 1\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Canvi de sinte\n", "\n", "És el moment de fer que la nostra cançó soni més interessant! Podem fer-ho canviant el sons que el sintetitzador està fent servir. \n", "El synth per defecte que fa servir Sonic Pi es diu *beep*. Podem canviar-lo amb el codi *use_synth*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "live_loop :bass do\n", " use_synth :fm\n", " play :c2\n", " sleep 0.25\n", " play :c2\n", " sleep 2\n", " play :e2\n", " sleep 0.75\n", " play :f2\n", " sleep 1\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Hem utilitzat el synth :fm, però Sonic Pi en conté molts d'altres. Podem veure el llistat amb una mica d'explicació de cada *sinte* a la ajuda" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Canviar la durada de les notes\n", "\n", "En ocasions, voldrem produir sons més llargs o a velocitat diferent. Ho podem fer amb els paràmetres opcionals **attack** i **release**, que controlen la amplitud d'una nota en funció del temps\n", "\n", "" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# Exemple 1 - Nota de 4 'beats' de durada:\n", "play 60, attack: 1, release: 3\n", "\n", "# Exemple 2 - Petit 'staccato':\n", "play 60, attack: 0, release: 0.2" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# El nostre groove de baix" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "live_loop :bass do\n", " use_synth :fm\n", " play :c2, attack: 0, release: 0.25\n", " sleep 0.25\n", " play :c2, attack: 0, release: 0.3\n", " sleep 2\n", " play :e2\n", " sleep 0.75\n", " play :f2\n", " sleep 1\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Lead track\n", "\n", "Ha arribat el moment de crear la nostra melodía. En comptes de escriure una pila de comandes *play* i *sleep*, farem servir una dreçera: **play_pattern_timed**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "en comptes de:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "play :c2\n", "sleep 0.5\n", "play :d2\n", "sleep 0.25\n", "play :e2\n", "sleep 0.75\n", "play :d2\n", "sleep 0.5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "pots escriure:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "play_pattern_timed [:c2, :d2, :e2, :d2], [0.5, 0.25, 0.75, 0.5]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# La nostra melodia" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "live_loop :melody do\n", " play_pattern_timed [:c4, :e4, :f4, :g4, :f4, :e4, :f4, :g4, :f4, :e4, :f4], \\\n", " [0.25, 0.25, 0.25, 1.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], attack: 0, release: 0.2\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Ja tenim la nostra cançó acabada 🤘😎🤘" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "use_bpm 100\n", "\n", "### ===== DRUMS ==========\n", "\n", "live_loop :drums do\n", " sample :drum_heavy_kick\n", " sleep 1\n", " sample :drum_snare_hard\n", " sleep 1\n", " sample :drum_heavy_kick\n", " sleep 1\n", " sample :drum_snare_hard\n", " sleep 1\n", "end\n", "\n", "live_loop :hats do\n", " sample :drum_cymbal_closed\n", " sleep 0.5\n", "end\n", "\n", "### ===== BASS ==========\n", "\n", "live_loop :bass do\n", " use_synth :fm\n", " play :c2, attack: 0, release: 0.25\n", " sleep 0.25\n", " play :c2, attack: 0, release: 0.3\n", " sleep 2\n", " play :e2\n", " sleep 0.75\n", " play :f2\n", " sleep 1\n", "end\n", "\n", "### ===== LEAD ==========\n", "\n", "live_loop :melody do\n", " play_pattern_timed [:c4, :e4, :f4, :g4, :f4, :e4, :f4, :g4, :f4, :e4, :f4], \\\n", " [0.25, 0.25, 0.25, 1.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25], attack: 0, release: 0.2\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Aleatorització i música generativa\n", "\n", "Aquí rau la verdadera potència de Sonic Pi! Podem afegir components aleatoris a la nostra música per a que es generi *en directe*!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "use_bpm 50\n", "\n", "live_loop :multi_beat do\n", " use_random_seed 2000\n", " 8.times do\n", " c = rrand(70, 130)\n", " n = (scale :e1, :minor_pentatonic).take(3).choose\n", " synth :tb303, note: n, release: 0.1, cutoff: c if rand < 0.9\n", " sample :elec_hi_snare if one_in(6)\n", " sample :drum_cymbal_closed if one_in(2)\n", " sample :drum_cymbal_pedal if one_in(3)\n", " sample :bd_haus, amp: 1.5 if one_in(4)\n", " sleep 0.125\n", " end\n", "end" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Altres funcionalitats avançades de Sonic Pi\n", "\n", "* Escales i acords\n", "* Efectes de so - FX (reverb, delay, overdrive...)\n", "* variables i mètodes\n", "* Estructures de dades especials (*ring*, *tick*...)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "## Gràcies per escoltar! Preguntes?\n", "\n", "Ens veiem al fòrum oficial de Sonic Pi! https://in-thread.sonic-pi.net/\n", "\n", "\n", "- https://github.com/victormartingarcia\n", "- \n", "- [@victormartin](https://twitter.com/victormartin)\n", "\n", "\n", "Codi font / Transparències: https://github.com/GeeksCAT/2021-intro-sonicpi\n", "\n" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Ruby 2.4.1", "language": "ruby", "name": "ruby" }, "language_info": { "file_extension": ".rb", "mimetype": "application/x-ruby", "name": "ruby", "version": "2.4.1" } }, "nbformat": 4, "nbformat_minor": 1 }