{"id":23337404,"url":"https://github.com/gkvoelkl/python-sonic","last_synced_at":"2025-05-15T10:07:30.134Z","repository":{"id":46810127,"uuid":"50776648","full_name":"gkvoelkl/python-sonic","owner":"gkvoelkl","description":"Programming Music with Python, Sonic Pi and Supercollider","archived":false,"fork":false,"pushed_at":"2025-01-19T19:25:37.000Z","size":97,"stargazers_count":319,"open_issues_count":9,"forks_count":47,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-04-14T19:56:49.079Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gkvoelkl.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-01-31T13:49:30.000Z","updated_at":"2025-04-12T17:04:56.000Z","dependencies_parsed_at":"2024-06-19T09:53:38.421Z","dependency_job_id":"4d93a429-3c03-4595-b68b-0b7d5094e13f","html_url":"https://github.com/gkvoelkl/python-sonic","commit_stats":{"total_commits":57,"total_committers":9,"mean_commits":6.333333333333333,"dds":0.6666666666666667,"last_synced_commit":"18165fa7a86fd63e0192628e514d9eb90bee42c8"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkvoelkl%2Fpython-sonic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkvoelkl%2Fpython-sonic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkvoelkl%2Fpython-sonic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gkvoelkl%2Fpython-sonic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gkvoelkl","download_url":"https://codeload.github.com/gkvoelkl/python-sonic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319720,"owners_count":22051073,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-21T02:17:17.304Z","updated_at":"2025-05-15T10:07:25.102Z","avatar_url":"https://github.com/gkvoelkl.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"python-sonic - Programming Music with Python, Sonic Pi or Supercollider\n=======================================================================\n\nPython-Sonic is a simple Python interface for Sonic Pi, which is a real\ngreat music software created by Sam Aaron (http://sonic-pi.net).\n\nAt the moment Python-Sonic works with Sonic Pi. It is planned, that it\nwill work with Supercollider, too.\n\nThis version supports Sonic Pi versions \u003e 4 when OSC run-code security\nwas added. \n\nIf you like it, use it. If you have some suggestions, tell me\n(gkvoelkl@nelson-games.de).\n\nInstallation\n------------\n\n-  First you need Python 3 (https://www.python.org, ) - Python 3.5\n   should work, because it’s the development environment\n-  Then Sonic Pi (https://sonic-pi.net) - That makes the sound\n-  Modul python-osc (https://pypi.python.org/pypi/python-osc) -\n   Connection between Python and Sonic Pi Server\n-  Add the module `python-sonic` - simply copy the source, or try `pip install python-sonic` That should work.\n\nFor local development you might want to locally install using \n\n$ pip install -e .\n\nLimitations\n-----------\n\n-  You have to start *Sonic Pi* first before you can use it with\n   python-sonic\n-  Only the notes from C2 to C6\n\nChangelog\n---------\n\n+--------+-------------------------------------------------------------+\n| V      |                                                             |\n| ersion |                                                             |\n+========+=============================================================+\n| 0.2.0  | Some changes for Sonic Pi 2.11. Simpler multi-threading     |\n|        | with decorator *@in_thread*. Messaging with *cue* and       |\n|        | *sync*.                                                     |\n+--------+-------------------------------------------------------------+\n| 0.3.0  | OSC Communication                                           |\n+--------+-------------------------------------------------------------+\n| 0.3.1. | Update, sort and duration of samples                        |\n+--------+-------------------------------------------------------------+\n| 0.3.2. | Restructured                                                |\n+--------+-------------------------------------------------------------+\n| 0.4.0  | Changes communication ports and recording                   |\n+--------+-------------------------------------------------------------+\n| 0.4.4  | Enables GUI Token                                           |\n+--------+-------------------------------------------------------------+\n\nCommunication\n-------------\n\nThe API *python-sonic* communications with *Sonic Pi* over UDP and two\nports. One port is an internal *Sonic Pi* GUI port and the second is the \nexternal OSC cue port.\n\nFor \u003ev4 a Token is needed to communicate with Sonic Pi. This token is generated\nrandomly at runtime when Sonic-Pi is started. The Token is extracted from the sonic-pi log files. \nSimilarly, the GUI udp port is now randomised at start and must be read from the log file too. \nIn order to play notes (and not just send OSC cues), a connection must be made to the GUI udp port \nusing the Token as the first argument in the message. The Token is automatically used on send. \n\n.. code-block:: python\n\n    from psonic import *\n    set_server_parameter('127.0.0.1', -2005799440, 30129, 4560)\n\n\nThese values are found from the file `~/.sonic-pi/log/spider.log`\n::\n    Sonic Pi Spider Server booting...\n    The time is 2023-10-01 11:01:41 +0100\n    Using primary protocol: udp\n    Detecting port numbers...\n    Ports: {:server_port=\u003e30129, :gui_port=\u003e30130, :scsynth_port=\u003e30131, :scsynth_send_port=\u003e30131, :osc_cues_port=\u003e4560, :tau_port=\u003e30132, :listen_to_tau_port=\u003e30136}\n    Token: -2005799440\n    Opening UDP Server to listen to GUI on port: 30129\n    Spider - Pulling in modules...\n    Spider - Starting Runtime Server\n    ...\n\nThis can be automated by using the function `set_server_parameter_from_log`\n\n.. code-block:: python\n\n    from psonic import *\n    set_server_parameter_from_log('127.0.0.1')\n    set_server_parameter_from_log('127.0.0.1', \"path-to-log-file\")\n\nNote if the `set_server_parameter` functions are not used, a default connection is created which will not work.\n\nThere is a simple example file `psonic_example.py` which you can run to check that things work. First open sonic-pi, then run the following:\n\n$ python psonic_example.py\n\nand a note should be played.\n\nExamples\n--------\n\nMany of the examples are inspired from the help menu in *Sonic Pi*.\n\n.. code-block:: python\n\n    from psonic import *\n\nThe first sound\n\n.. code-block:: python\n\n    play(70) #play MIDI note 70\n\nSome more notes\n\n.. code-block:: python\n\n    play(72)\n    sleep(1)\n    play(75)\n    sleep(1)\n    play(79) \n\nIn more tratitional music notation\n\n.. code-block:: python\n\n    play(C5)\n    sleep(0.5)\n    play(D5)\n    sleep(0.5)\n    play(G5) \n\nPlay sharp notes like *F#* or dimished ones like *Eb*\n\n.. code-block:: python\n\n    play(Fs5)\n    sleep(0.5)\n    play(Eb5)\n\nPlay louder (parameter amp) or from a different direction (parameter\npan)\n\n.. code-block:: python\n\n    play(72,amp=2)\n    sleep(0.5)\n    play(74,pan=-1) #left\n\nDifferent synthesizer sounds\n\n.. code-block:: python\n\n    use_synth(SAW)\n    play(38)\n    sleep(0.25)\n    play(50)\n    sleep(0.5)\n    use_synth(PROPHET)\n    play(57)\n    sleep(0.25)\n\nADSR *(Attack, Decay, Sustain and Release)* Envelope\n\n.. code-block:: python\n\n    play (60, attack=0.5, decay=1, sustain_level=0.4, sustain=2, release=0.5) \n    sleep(4)\n\nPlay some samples\n\n.. code-block:: python\n\n    sample(AMBI_LUNAR_LAND, amp=0.5)\n\n.. code-block:: python\n\n    sample(LOOP_AMEN,pan=-1)\n    sleep(0.877)\n    sample(LOOP_AMEN,pan=1)\n\n.. code-block:: python\n\n    sample(LOOP_AMEN,rate=0.5)\n\n.. code-block:: python\n\n    sample(LOOP_AMEN,rate=1.5)\n\n.. code-block:: python\n\n    sample(LOOP_AMEN,rate=-1)#back\n\n.. code-block:: python\n\n    sample(DRUM_CYMBAL_OPEN,attack=0.01,sustain=0.3,release=0.1)\n\n.. code-block:: python\n\n    sample(LOOP_AMEN,start=0.5,finish=0.8,rate=-0.2,attack=0.3,release=1)\n\nPlay some random notes\n\n.. code-block:: python\n\n    import random\n    \n    for i in range(5):\n        play(random.randrange(50, 100))\n        sleep(0.5)\n\n.. code-block:: python\n\n    for i in range(3):\n        play(random.choice([C5,E5,G5]))\n        sleep(1)\n\nSample slicing\n\n.. code-block:: python\n\n    from psonic import *\n    \n    number_of_pieces = 8\n    \n    for i in range(16):\n        s = random.randrange(0,number_of_pieces)/number_of_pieces #sample starts at 0.0 and finishes at 1.0\n        f = s + (1.0/number_of_pieces)\n        sample(LOOP_AMEN,beat_stretch=2,start=s,finish=f)\n        sleep(2.0/number_of_pieces)\n\nAn infinite loop and if\n\n.. code-block:: python\n\n    while True:\n      if one_in(2):\n        sample(DRUM_HEAVY_KICK)\n        sleep(0.5)\n      else:\n        sample(DRUM_CYMBAL_CLOSED)\n        sleep(0.25)\n\n\n::\n\n\n    ---------------------------------------------------------------------------\n\n    KeyboardInterrupt                         Traceback (most recent call last)\n\n    \u003cipython-input-18-d8759ac2d27e\u003e in \u003cmodule\u003e()\n          5   else:\n          6     sample(DRUM_CYMBAL_CLOSED)\n    ----\u003e 7     sleep(0.25)\n    \n\n    /mnt/jupyter/python-sonic/psonic.py in sleep(duration)\n        587     :return:\n        588     \"\"\"\n    --\u003e 589     time.sleep(duration)\n        590     _debug('sleep', duration)\n        591 \n\n\n    KeyboardInterrupt: \n\n\nIf you want to hear more than one sound at a time, use Threads.\n\n.. code-block:: python\n\n    import random\n    from psonic import *\n    from threading import Thread\n    \n    def bass_sound():\n        c = chord(E3, MAJOR7)\n        while True:\n            use_synth(PROPHET)\n            play(random.choice(c), release=0.6)\n            sleep(0.5)\n    \n    def snare_sound():\n        while True:\n            sample(ELEC_SNARE)\n            sleep(1)\n    \n    bass_thread = Thread(target=bass_sound)\n    snare_thread = Thread(target=snare_sound)\n    \n    bass_thread.start()\n    snare_thread.start()\n    \n    while True:\n        pass\n\n\n::\n\n\n    ---------------------------------------------------------------------------\n\n    KeyboardInterrupt                         Traceback (most recent call last)\n\n    \u003cipython-input-19-5b8671a783d6\u003e in \u003cmodule\u003e\n         22 \n         23 while True:\n    ---\u003e 24     pass\n    \n\n    KeyboardInterrupt: \n\n\nEvery function *bass_sound* and *snare_sound* have its own thread. Your\ncan hear them running.\n\n.. code-block:: python\n\n    from psonic import *\n    from threading import Thread, Condition\n    from random import choice\n    \n    def random_riff(condition):\n        use_synth(PROPHET)\n        sc = scale(E3, MINOR)\n        while True:\n            s = random.choice([0.125,0.25,0.5])\n            with condition:\n                condition.wait() #Wait for message\n            for i in range(8):\n                r = random.choice([0.125, 0.25, 1, 2])\n                n = random.choice(sc)\n                co = random.randint(30,100)\n                play(n, release = r, cutoff = co)\n                sleep(s)\n    \n    def drums(condition):\n        while True:\n            with condition:\n                condition.notifyAll() #Message to threads\n            for i in range(16):\n                r = random.randrange(1,10)\n                sample(DRUM_BASS_HARD, rate=r)\n                sleep(0.125)\n    \n    condition = Condition()\n    random_riff_thread = Thread(name='consumer1', target=random_riff, args=(condition,))\n    drums_thread = Thread(name='producer', target=drums, args=(condition,))\n    \n    random_riff_thread.start()\n    drums_thread.start()\n    \n    input(\"Press Enter to continue...\")\n\n\n.. parsed-literal::\n\n    Press Enter to continue... \n\n\n\n\n.. parsed-literal::\n\n    ''\n\n\n\nTo synchronize the thread, so that they play a note at the same time,\nyou can use *Condition*. One function sends a message with\n*condition.notifyAll* the other waits until the message comes\n*condition.wait*.\n\nMore simple with decorator \\_\\_@in_thread_\\_\n\n.. code-block:: python\n\n    from psonic import *\n    from random import choice\n    \n    tick = Message()\n    \n    @in_thread\n    def random_riff():\n        use_synth(PROPHET)\n        sc = scale(E3, MINOR)\n        while True:\n            s = random.choice([0.125,0.25,0.5])\n            tick.sync()\n            for i in range(8):\n                r = random.choice([0.125, 0.25, 1, 2])\n                n = random.choice(sc)\n                co = random.randint(30,100)\n                play(n, release = r, cutoff = co)\n                sleep(s)\n                \n    @in_thread\n    def drums():\n        while True:\n            tick.cue()\n            for i in range(16):\n                r = random.randrange(1,10)\n                sample(DRUM_BASS_HARD, rate=r)\n                sleep(0.125)\n    \n    random_riff()\n    drums()\n    \n    input(\"Press Enter to continue...\")\n\n\n.. parsed-literal::\n\n    Press Enter to continue... \n\n\n.. code-block:: python\n\n    from psonic import *\n    \n    tick = Message()\n    \n    @in_thread\n    def metronom():\n        while True:\n            tick.cue()\n            sleep(1)\n            \n    @in_thread\n    def instrument():\n        while True:\n            tick.sync()\n            sample(DRUM_HEAVY_KICK)\n    \n    metronom()\n    instrument()\n    \n    while True:\n        pass\n\nPlay a list of notes\n\n.. code-block:: python\n\n    from psonic import *\n    \n    play ([64, 67, 71], amp = 0.3) \n    sleep(1)\n    play ([E4, G4, B4])\n    sleep(1)\n\nPlay chords\n\n.. code-block:: python\n\n    play(chord(E4, MINOR)) \n    sleep(1)\n    play(chord(E4, MAJOR))\n    sleep(1)\n    play(chord(E4, MINOR7))\n    sleep(1)\n    play(chord(E4, DOM7))\n    sleep(1)\n\nPlay arpeggios\n\n.. code-block:: python\n\n    play_pattern( chord(E4, 'm7')) \n    play_pattern_timed( chord(E4, 'm7'), 0.25) \n    play_pattern_timed(chord(E4, 'dim'), [0.25, 0.5]) \n\nPlay scales\n\n.. code-block:: python\n\n    play_pattern_timed(scale(C3, MAJOR), 0.125, release = 0.1) \n    play_pattern_timed(scale(C3, MAJOR, num_octaves = 2), 0.125, release = 0.1) \n    play_pattern_timed(scale(C3, MAJOR_PENTATONIC, num_octaves = 2), 0.125, release = 0.1)\n\nThe function *scale* returns a list with all notes of a scale. So you\ncan use list methodes or functions. For example to play arpeggios\ndescending or shuffeld.\n\n.. code-block:: python\n\n    import random\n    from psonic import *\n    \n    s = scale(C3, MAJOR)\n    s\n\n\n\n\n.. parsed-literal::\n\n    [48, 50, 52, 53, 55, 57, 59, 60]\n\n\n\n.. code-block:: python\n\n    s.reverse()\n\n.. code-block:: python\n\n    \n    play_pattern_timed(s, 0.125, release = 0.1)\n    random.shuffle(s)\n    play_pattern_timed(s, 0.125, release = 0.1)\n\nLive Loop\n~~~~~~~~~\n\nOne of the best in SONIC PI is the *Live Loop*. While a loop is playing\nmusic you can change it and hear the change. Let’s try it in Python,\ntoo.\n\n.. code-block:: python\n\n    from psonic import *\n    from threading import Thread\n    \n    def my_loop():\n      play(60)\n      sleep(1)\n    \n    def looper():\n      while True:\n        my_loop()\n    \n    looper_thread = Thread(name='looper', target=looper)\n    \n    looper_thread.start()\n    \n    input(\"Press Enter to continue...\")\n\n\n.. parsed-literal::\n\n    Press Enter to continue...Y\n\n\n\n\n.. parsed-literal::\n\n    'Y'\n\n\n\nNow change the function *my_loop* und you can hear it.\n\n.. code-block:: python\n\n    def my_loop():\n      use_synth(TB303)\n      play (60, release= 0.3)\n      sleep (0.25)\n\n.. code-block:: python\n\n    def my_loop():\n      use_synth(TB303)\n      play (chord(E3, MINOR), release= 0.3)\n      sleep(0.5)\n\n.. code-block:: python\n\n    def my_loop():\n        use_synth(TB303)\n        sample(DRUM_BASS_HARD, rate = random.uniform(0.5, 2))\n        play(random.choice(chord(E3, MINOR)), release= 0.2, cutoff=random.randrange(60, 130))\n        sleep(0.25)\n\nTo stop the sound you have to end the kernel. In IPython with Kernel –\u003e\nRestart\n\nNow with two live loops which are synch.\n\n.. code-block:: python\n\n    from psonic import *\n    from threading import Thread, Condition\n    from random import choice\n    \n    def loop_foo():\n      play (E4, release = 0.5)\n      sleep (0.5)\n    \n    \n    def loop_bar():\n      sample (DRUM_SNARE_SOFT)\n      sleep (1)\n        \n    \n    def live_loop_1(condition):\n        while True:\n            with condition:\n                condition.notifyAll() #Message to threads\n            loop_foo()\n                \n    def live_loop_2(condition):\n        while True:\n            with condition:\n                condition.wait() #Wait for message\n            loop_bar()\n    \n    condition = Condition()\n    live_thread_1 = Thread(name='producer', target=live_loop_1, args=(condition,))\n    live_thread_2 = Thread(name='consumer1', target=live_loop_2, args=(condition,))\n    \n    live_thread_1.start()\n    live_thread_2.start()\n    \n    input(\"Press Enter to continue...\")\n\n\n.. parsed-literal::\n\n    Press Enter to continue...y\n\n\n\n\n.. parsed-literal::\n\n    'y'\n\n\n\n.. code-block:: python\n\n    def loop_foo():\n      play (A4, release = 0.5)\n      sleep (0.5)\n\n.. code-block:: python\n\n    def loop_bar():\n      sample (DRUM_HEAVY_KICK)\n      sleep (0.125)\n\nIf would be nice if we can stop the loop with a simple command. With\nstop event it works.\n\n.. code-block:: python\n\n    from psonic import *\n    from threading import Thread, Condition, Event\n    \n    def loop_foo():\n      play (E4, release = 0.5)\n      sleep (0.5)\n    \n    \n    def loop_bar():\n      sample (DRUM_SNARE_SOFT)\n      sleep (1)\n        \n    \n    def live_loop_1(condition,stop_event):\n        while not stop_event.is_set():\n            with condition:\n                condition.notifyAll() #Message to threads\n            loop_foo()\n                \n    def live_loop_2(condition,stop_event):\n        while not stop_event.is_set():\n            with condition:\n                condition.wait() #Wait for message\n            loop_bar()\n    \n    \n    \n    condition = Condition()\n    stop_event = Event()\n    live_thread_1 = Thread(name='producer', target=live_loop_1, args=(condition,stop_event))\n    live_thread_2 = Thread(name='consumer1', target=live_loop_2, args=(condition,stop_event))\n    \n    \n    live_thread_1.start()\n    live_thread_2.start()\n    \n    input(\"Press Enter to continue...\")\n\n\n.. parsed-literal::\n\n    Press Enter to continue...y\n\n\n\n\n.. parsed-literal::\n\n    'y'\n\n\n\n.. code-block:: python\n\n    stop_event.set()\n\nMore complex live loops\n\n.. code-block:: python\n\n    sc = Ring(scale(E3, MINOR_PENTATONIC))\n    \n    def loop_foo():\n      play (next(sc), release= 0.1)\n      sleep (0.125)\n    \n    sc2 = Ring(scale(E3,MINOR_PENTATONIC,num_octaves=2))\n               \n    def loop_bar():\n      use_synth(DSAW)\n      play (next(sc2), release= 0.25)\n      sleep (0.25)\n\nNow a simple structure with four live loops\n\n.. code-block:: python\n\n    import random\n    from psonic import *\n    from threading import Thread, Condition, Event\n    \n    def live_1():\n        pass\n    \n    def live_2():\n        pass\n        \n    def live_3():\n        pass\n    \n    def live_4():\n        pass\n    \n    def live_loop_1(condition,stop_event):\n        while not stop_event.is_set():\n            with condition:\n                condition.notifyAll() #Message to threads\n            live_1()\n                \n    def live_loop_2(condition,stop_event):\n        while not stop_event.is_set():\n            with condition:\n                condition.wait() #Wait for message\n            live_2()\n    \n    def live_loop_3(condition,stop_event):\n        while not stop_event.is_set():\n            with condition:\n                condition.wait() #Wait for message\n            live_3()\n    \n    def live_loop_4(condition,stop_event):\n        while not stop_event.is_set():\n            with condition:\n                condition.wait() #Wait for message\n            live_4()\n            \n    condition = Condition()\n    stop_event = Event()\n    live_thread_1 = Thread(name='producer', target=live_loop_1, args=(condition,stop_event))\n    live_thread_2 = Thread(name='consumer1', target=live_loop_2, args=(condition,stop_event))\n    live_thread_3 = Thread(name='consumer2', target=live_loop_3, args=(condition,stop_event))\n    live_thread_4 = Thread(name='consumer3', target=live_loop_3, args=(condition,stop_event))\n    \n    live_thread_1.start()\n    live_thread_2.start()\n    live_thread_3.start()\n    live_thread_4.start()\n    \n    input(\"Press Enter to continue...\")\n\n\n.. parsed-literal::\n\n    Press Enter to continue...y\n\n\n\n\n.. parsed-literal::\n\n    'y'\n\n\n\nAfter starting the loops you can change them\n\n.. code-block:: python\n\n    def live_1():\n        sample(BD_HAUS,amp=2)\n        sleep(0.5)\n        pass\n\n.. code-block:: python\n\n    def live_2():\n        #sample(AMBI_CHOIR, rate=0.4)\n        #sleep(1)\n        pass\n\n.. code-block:: python\n\n    def live_3():\n        use_synth(TB303)\n        play(E2, release=4,cutoff=120,cutoff_attack=1)\n        sleep(4)\n\n.. code-block:: python\n\n    def live_4():\n        notes = scale(E3, MINOR_PENTATONIC, num_octaves=2)\n        for i in range(8):\n            play(random.choice(notes),release=0.1,amp=1.5)\n            sleep(0.125)\n\nAnd stop.\n\n.. code-block:: python\n\n    stop_event.set()\n\nCreating Sound\n~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n    from psonic import *\n    \n    synth(SINE, note=D4)\n    synth(SQUARE, note=D4)\n    synth(TRI, note=D4, amp=0.4)\n\n.. code-block:: python\n\n    detune = 0.7\n    synth(SQUARE, note = E4)\n    synth(SQUARE, note = E4+detune)\n\n.. code-block:: python\n\n    detune=0.1 # Amplitude shaping\n    synth(SQUARE, note = E2, release = 2)\n    synth(SQUARE, note = E2+detune, amp =  2, release = 2)\n    synth(GNOISE, release = 2, amp = 1, cutoff = 60)\n    synth(GNOISE, release = 0.5, amp = 1, cutoff = 100)\n    synth(NOISE, release = 0.2, amp = 1, cutoff = 90)\n\nNext Step\n~~~~~~~~~\n\nUsing FX *Not implemented yet*\n\n.. code-block:: python\n\n    from psonic import *\n    \n    with Fx(SLICER):\n        synth(PROPHET,note=E2,release=8,cutoff=80)\n        synth(PROPHET,note=E2+4,release=8,cutoff=80)\n\n.. code-block:: python\n\n    with Fx(SLICER, phase=0.125, probability=0.6,prob_pos=1):\n        synth(TB303, note=E2, cutoff_attack=8, release=8)\n        synth(TB303, note=E3, cutoff_attack=4, release=8)\n        synth(TB303, note=E4, cutoff_attack=2, release=8)\n\nOSC Communication (Sonic Pi Ver. 3.x or better)\n-----------------------------------------------\n\nIn Sonic Pi version 3 or better you can work with messages.\n\n.. code-block:: python\n\n    from psonic import *\n\nFirst you need a programm in the Sonic Pi server that receives messages.\nYou can write it in th GUI or send one with Python.\n\n.. code-block:: python\n\n    run(\"\"\"live_loop :foo do\n      use_real_time\n      a, b, c = sync \"/osc*/trigger/prophet\"\n      synth :prophet, note: a, cutoff: b, sustain: c\n    end \"\"\")\n\nNow send a message to Sonic Pi.\n\n.. code-block:: python\n\n    send_message('/trigger/prophet', 70, 100, 8)\n\n.. code-block:: python\n\n    stop()\n\nRecording\n---------\n\nWith python-sonic you can record wave files.\n\n.. code-block:: python\n\n    from psonic import *\n\n.. code-block:: python\n\n    # start recording\n    start_recording()\n    \n    play(chord(E4, MINOR)) \n    sleep(1)\n    play(chord(E4, MAJOR))\n    sleep(1)\n    play(chord(E4, MINOR7))\n    sleep(1)\n    play(chord(E4, DOM7))\n    sleep(1)\n\n.. code-block:: python\n\n    # stop recording\n    stop_recording\n\n\n\n\n.. parsed-literal::\n\n    \u003cfunction psonic.psonic.stop_recording()\u003e\n\n\n\n.. code-block:: python\n\n    # save file\n    save_recording('/Volumes/jupyter/python-sonic/test.wav')\n\nMore Examples\n-------------\n\n.. code-block:: python\n\n    from psonic import *\n\n.. code-block:: python\n\n    #Inspired by Steve Reich Clapping Music\n    \n    clapping = [1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0]\n    \n    for i in range(13):\n        for j in range(4):\n            for k in range(12): \n              if clapping[k] ==1 : sample(DRUM_SNARE_SOFT,pan=-0.5)\n              if clapping[(i+k)%12] == 1: sample(DRUM_HEAVY_KICK,pan=0.5)\n              sleep (0.25)\n\nProjects that use Python-Sonic\n------------------------------\n\nRaspberry Pi sonic-track.py a Sonic-pi Motion Track Demo\nhttps://github.com/pageauc/sonic-track\n\nSources\n-------\n\nJoe Armstrong: Connecting Erlang to the Sonic Pi\nhttp://joearms.github.io/2015/01/05/Connecting-Erlang-to-Sonic-Pi.html\n\nJoe Armstrong: Controlling Sound with OSC Messages\nhttp://joearms.github.io/2016/01/29/Controlling-Sound-with-OSC-Messages.html\n\n..\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgkvoelkl%2Fpython-sonic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgkvoelkl%2Fpython-sonic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgkvoelkl%2Fpython-sonic/lists"}